Last active
November 20, 2023 02:03
-
-
Save prime31/91d1582624eb2635395417393018016e to your computer and use it in GitHub Desktop.
Simple file and folder picker for ImGui.Net
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using ImGuiNET; | |
using Microsoft.Xna.Framework; | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using Num = System.Numerics; | |
namespace Nez.ImGuiTools | |
{ | |
public class FilePicker | |
{ | |
static readonly Dictionary<object, FilePicker> _filePickers = new Dictionary<object, FilePicker>(); | |
public string RootFolder; | |
public string CurrentFolder; | |
public string SelectedFile; | |
public List<string> AllowedExtensions; | |
public bool OnlyAllowFolders; | |
public static FilePicker GetFolderPicker(object o, string startingPath) | |
=> GetFilePicker(o, startingPath, null, true); | |
public static FilePicker GetFilePicker(object o, string startingPath, string searchFilter = null, bool onlyAllowFolders = false) | |
{ | |
if (File.Exists(startingPath)) | |
{ | |
startingPath = new FileInfo(startingPath).DirectoryName; | |
} | |
else if (string.IsNullOrEmpty(startingPath) || !Directory.Exists(startingPath)) | |
{ | |
startingPath = Environment.CurrentDirectory; | |
if (string.IsNullOrEmpty(startingPath)) | |
startingPath = AppContext.BaseDirectory; | |
} | |
if (!_filePickers.TryGetValue(o, out FilePicker fp)) | |
{ | |
fp = new FilePicker(); | |
fp.RootFolder = startingPath; | |
fp.CurrentFolder = startingPath; | |
fp.OnlyAllowFolders = onlyAllowFolders; | |
if (searchFilter != null) | |
{ | |
if (fp.AllowedExtensions != null) | |
fp.AllowedExtensions.Clear(); | |
else | |
fp.AllowedExtensions = new List<string>(); | |
fp.AllowedExtensions.AddRange(searchFilter.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries)); | |
} | |
_filePickers.Add(o, fp); | |
} | |
return fp; | |
} | |
public static void RemoveFilePicker(object o) => _filePickers.Remove(o); | |
public bool Draw() | |
{ | |
ImGui.Text("Current Folder: " + Path.GetFileName(RootFolder) + CurrentFolder.Replace(RootFolder, "")); | |
bool result = false; | |
if (ImGui.BeginChildFrame(1, new Num.Vector2(400, 400))) | |
{ | |
var di = new DirectoryInfo(CurrentFolder); | |
if (di.Exists) | |
{ | |
if (di.Parent != null && CurrentFolder != RootFolder) | |
{ | |
ImGui.PushStyleColor(ImGuiCol.Text, Color.Yellow.PackedValue); | |
if (ImGui.Selectable("../", false, ImGuiSelectableFlags.DontClosePopups)) | |
CurrentFolder = di.Parent.FullName; | |
ImGui.PopStyleColor(); | |
} | |
var fileSystemEntries = GetFileSystemEntries(di.FullName); | |
foreach (var fse in fileSystemEntries) | |
{ | |
if (Directory.Exists(fse)) | |
{ | |
var name = Path.GetFileName(fse); | |
ImGui.PushStyleColor(ImGuiCol.Text, Color.Yellow.PackedValue); | |
if (ImGui.Selectable(name + "/", false, ImGuiSelectableFlags.DontClosePopups)) | |
CurrentFolder = fse; | |
ImGui.PopStyleColor(); | |
} | |
else | |
{ | |
var name = Path.GetFileName(fse); | |
bool isSelected = SelectedFile == fse; | |
if (ImGui.Selectable(name, isSelected, ImGuiSelectableFlags.DontClosePopups)) | |
SelectedFile = fse; | |
if (ImGui.IsMouseDoubleClicked(0)) | |
{ | |
result = true; | |
ImGui.CloseCurrentPopup(); | |
} | |
} | |
} | |
} | |
} | |
ImGui.EndChildFrame(); | |
if (ImGui.Button("Cancel")) | |
{ | |
result = false; | |
ImGui.CloseCurrentPopup(); | |
} | |
if (OnlyAllowFolders) | |
{ | |
ImGui.SameLine(); | |
if (ImGui.Button("Open")) | |
{ | |
result = true; | |
SelectedFile = CurrentFolder; | |
ImGui.CloseCurrentPopup(); | |
} | |
} | |
else if (SelectedFile != null) | |
{ | |
ImGui.SameLine(); | |
if (ImGui.Button("Open")) | |
{ | |
result = true; | |
ImGui.CloseCurrentPopup(); | |
} | |
} | |
return result; | |
} | |
bool TryGetFileInfo(string fileName, out FileInfo realFile) | |
{ | |
try | |
{ | |
realFile = new FileInfo(fileName); | |
return true; | |
} | |
catch | |
{ | |
realFile = null; | |
return false; | |
} | |
} | |
List<string> GetFileSystemEntries(string fullName) | |
{ | |
var files = new List<string>(); | |
var dirs = new List<string>(); | |
foreach (var fse in Directory.GetFileSystemEntries(fullName, "")) | |
{ | |
if (Directory.Exists(fse)) | |
{ | |
dirs.Add(fse); | |
} | |
else if (!OnlyAllowFolders) | |
{ | |
if (AllowedExtensions != null) | |
{ | |
var ext = Path.GetExtension(fse); | |
if (AllowedExtensions.Contains(ext)) | |
files.Add(fse); | |
} | |
else | |
{ | |
files.Add(fse); | |
} | |
} | |
} | |
var ret = new List<string>(dirs); | |
ret.AddRange(files); | |
return ret; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var isOpen = true; | |
if (ImGui.BeginPopupModal("save-file", ref isOpen, ImGuiWindowFlags.NoTitleBar)) | |
{ | |
var picker = FilePicker.GetFolderPicker(this, Path.Combine(Environment.CurrentDirectory)); | |
if (picker.Draw()) | |
{ | |
Console.WriteLine(picker.SelectedFile); | |
FilePicker.RemoveFilePicker(this); | |
} | |
ImGui.EndPopup(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Very slow and inefficient, especially for directories with many entries.
With every draw() (i.e. frame) the directory is read in again, which massively reduces the framerate. It is better to read in the directory only once when creating and again when changing the directory.