mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
157 lines
5.6 KiB
C#
157 lines
5.6 KiB
C#
using Dalamud.Interface;
|
|
using Dalamud.Interface.ImGuiFileDialog;
|
|
using Dalamud.Utility;
|
|
using Dalamud.Bindings.ImGui;
|
|
using Luna;
|
|
using OtterGui;
|
|
using Penumbra.Communication;
|
|
using Penumbra.Services;
|
|
|
|
namespace Penumbra.UI;
|
|
|
|
public class FileDialogService : IDisposable, IUiService
|
|
{
|
|
private readonly CommunicatorService _communicator;
|
|
private readonly FileDialogManager _manager;
|
|
private readonly ConcurrentDictionary<string, string> _startPaths = new();
|
|
private bool _isOpen;
|
|
|
|
public FileDialogService(CommunicatorService communicator, Configuration config)
|
|
{
|
|
_communicator = communicator;
|
|
_manager = SetupFileManager(config.ModDirectory);
|
|
_communicator.ModDirectoryChanged.Subscribe(OnModDirectoryChange, ModDirectoryChanged.Priority.FileDialogService);
|
|
}
|
|
|
|
public void OpenFilePicker(string title, string filters, Action<bool, List<string>> callback, int selectionCountMax, string? startPath,
|
|
bool forceStartPath)
|
|
{
|
|
_isOpen = true;
|
|
_manager.OpenFileDialog(title, filters, CreateCallback(title, callback), selectionCountMax,
|
|
GetStartPath(title, startPath, forceStartPath));
|
|
}
|
|
|
|
public void OpenFolderPicker(string title, Action<bool, string> callback, string? startPath, bool forceStartPath)
|
|
{
|
|
_isOpen = true;
|
|
_manager.OpenFolderDialog(title, CreateCallback(title, callback), GetStartPath(title, startPath, forceStartPath));
|
|
}
|
|
|
|
public void OpenSavePicker(string title, string filters, string defaultFileName, string defaultExtension, Action<bool, string> callback,
|
|
string? startPath,
|
|
bool forceStartPath)
|
|
{
|
|
_isOpen = true;
|
|
_manager.SaveFileDialog(title, filters, defaultFileName, defaultExtension, CreateCallback(title, callback),
|
|
GetStartPath(title, startPath, forceStartPath));
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
_isOpen = false;
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
_isOpen = false;
|
|
_manager.Reset();
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
if (_isOpen)
|
|
_manager.Draw();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_startPaths.Clear();
|
|
_manager.Reset();
|
|
_communicator.ModDirectoryChanged.Unsubscribe(OnModDirectoryChange);
|
|
}
|
|
|
|
private string? GetStartPath(string title, string? startPath, bool forceStartPath)
|
|
{
|
|
var path = !forceStartPath && _startPaths.TryGetValue(title, out var p) ? p : startPath;
|
|
if (!path.IsNullOrEmpty() && !Directory.Exists(path))
|
|
path = null;
|
|
return path;
|
|
}
|
|
|
|
private Action<bool, List<string>> CreateCallback(string title, Action<bool, List<string>> callback)
|
|
{
|
|
return (valid, list) =>
|
|
{
|
|
_isOpen = false;
|
|
var loc = HandleRoot(GetCurrentLocation());
|
|
_startPaths[title] = loc;
|
|
callback(valid, list.Select(HandleRoot).ToList());
|
|
};
|
|
}
|
|
|
|
private Action<bool, string> CreateCallback(string title, Action<bool, string> callback)
|
|
{
|
|
return (valid, list) =>
|
|
{
|
|
_isOpen = false;
|
|
var loc = HandleRoot(GetCurrentLocation());
|
|
_startPaths[title] = loc;
|
|
callback(valid, HandleRoot(list));
|
|
};
|
|
}
|
|
|
|
private static string HandleRoot(string path)
|
|
{
|
|
if (path is [_, ':'])
|
|
return path + '\\';
|
|
|
|
return path;
|
|
}
|
|
|
|
// TODO: maybe change this from reflection when its public.
|
|
private string GetCurrentLocation()
|
|
=> (_manager.GetType().GetField("dialog", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(_manager) as FileDialog)
|
|
?.GetCurrentPath()
|
|
?? ".";
|
|
|
|
/// <summary> Set up the file selector with the right flags and custom side bar items. </summary>
|
|
private static FileDialogManager SetupFileManager(string modDirectory)
|
|
{
|
|
var fileManager = new FileDialogManager
|
|
{
|
|
AddedWindowFlags = ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoDocking,
|
|
};
|
|
|
|
if (Functions.GetDownloadsFolder(out var downloadsFolder))
|
|
fileManager.CustomSideBarItems.Add(("Downloads", downloadsFolder, FontAwesomeIcon.Download, -1));
|
|
|
|
if (Functions.GetQuickAccessFolders(out var folders))
|
|
foreach (var (idx, (name, path)) in folders.Index())
|
|
fileManager.CustomSideBarItems.Add(($"{name}##{idx}", path, FontAwesomeIcon.Folder, -1));
|
|
|
|
// Add Penumbra Root. This is not updated if the root changes right now.
|
|
fileManager.CustomSideBarItems.Add(("Root Directory", modDirectory, FontAwesomeIcon.Gamepad, 0));
|
|
|
|
// Remove Videos and Music.
|
|
fileManager.CustomSideBarItems.Add(("Videos", string.Empty, 0, -1));
|
|
fileManager.CustomSideBarItems.Add(("Music", string.Empty, 0, -1));
|
|
|
|
return fileManager;
|
|
}
|
|
|
|
/// <summary> Update the Root Directory link on changes. </summary>
|
|
private void OnModDirectoryChange(in ModDirectoryChanged.Arguments arguments)
|
|
{
|
|
var idx = _manager.CustomSideBarItems.IndexOf(t => t.Name == "Root Directory");
|
|
if (idx >= 0)
|
|
_manager.CustomSideBarItems.RemoveAt(idx);
|
|
|
|
if (!arguments.Valid)
|
|
return;
|
|
|
|
if (idx >= 0)
|
|
_manager.CustomSideBarItems.Insert(idx, ("Root Directory", arguments.Directory, FontAwesomeIcon.Gamepad, 0));
|
|
else
|
|
_manager.CustomSideBarItems.Add(("Root Directory", arguments.Directory, FontAwesomeIcon.Gamepad, 0));
|
|
}
|
|
}
|