From 34f5b833d86ea1dad98d683723cf05a17684237b Mon Sep 17 00:00:00 2001 From: Aldrik Ramaekers Date: Thu, 7 Mar 2024 20:49:22 +0100 Subject: add ImFileDialog with minor changes --- .vscode/settings.json | 74 +++ build_win32.bat | 4 +- imfiledialog/ImFileDialog.cpp | 1397 +++++++++++++++++++++++++++++++++++++++++ imfiledialog/ImFileDialog.h | 136 ++++ imfiledialog/LICENSE | 21 + imgui/imconfig.h | 2 +- src/image.cpp | 19 + src/main.cpp | 13 +- 8 files changed, 1662 insertions(+), 4 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 imfiledialog/ImFileDialog.cpp create mode 100644 imfiledialog/ImFileDialog.h create mode 100644 imfiledialog/LICENSE diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b276d29 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,74 @@ +{ + "files.associations": { + "xstring": "cpp", + "algorithm": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "deque": "cpp", + "exception": "cpp", + "filesystem": "cpp", + "format": "cpp", + "forward_list": "cpp", + "fstream": "cpp", + "functional": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "locale": "cpp", + "map": "cpp", + "memory": "cpp", + "new": "cpp", + "optional": "cpp", + "ostream": "cpp", + "ratio": "cpp", + "sstream": "cpp", + "stack": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "string": "cpp", + "system_error": "cpp", + "thread": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "unordered_map": "cpp", + "utility": "cpp", + "vector": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocbuf": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xmemory": "cpp", + "xstddef": "cpp", + "xtr1common": "cpp", + "xtree": "cpp", + "xutility": "cpp" + } +} \ No newline at end of file diff --git a/build_win32.bat b/build_win32.bat index a8c2cf4..b6ef27b 100644 --- a/build_win32.bat +++ b/build_win32.bat @@ -4,11 +4,11 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary @set OUT_DIR=bin\\debug @set OUT_EXE=text-search @set INCLUDES=/I..\.. /I..\..\backends -@set SOURCES=imgui/imgui*.cpp src/*.cpp +@set SOURCES=imgui/imgui*.cpp src/*.cpp imfiledialog/*.cpp @set LIBS=opengl32.lib Advapi32.lib Shell32.lib bin/debug/data.obj bin/debug/icon.res windres misc/icon.rc -O coff -o bin/debug/icon.res ld -r -b binary -o bin/debug/data.obj LICENSE misc/logo_64.png imgui/LICENSE imspinner/LICENSE misc/search.png misc/folder.png mkdir %OUT_DIR% -cl /nologo /Zi /MD /EHsc /utf-8 %INCLUDES% /D UNICODE /D _UNICODE %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fd%OUT_DIR%/vc140.pdb /Fo%OUT_DIR%/ /link %LIBS% +cl /std:c++17 /nologo /Zi /MD /EHsc /utf-8 %INCLUDES% /D UNICODE /D _UNICODE %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fd%OUT_DIR%/vc140.pdb /Fo%OUT_DIR%/ /link %LIBS% if "%1"=="-r" call "bin/debug/text-search.exe" if "%1"=="-d" call devenv "bin/debug/text-search.exe" diff --git a/imfiledialog/ImFileDialog.cpp b/imfiledialog/ImFileDialog.cpp new file mode 100644 index 0000000..8cbc2c9 --- /dev/null +++ b/imfiledialog/ImFileDialog.cpp @@ -0,0 +1,1397 @@ +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "ImFileDialog.h" + +#include +#include +#include +#define IMGUI_DEFINE_MATH_OPERATORS +#include "../imgui/imgui.h" +#include "../imgui/imgui_internal.h" + +#include "../stb_image.h" + +#ifdef _WIN32 +#define NOMINMAX +#include +#include +#include +#pragma comment(lib, "Shell32.lib") +#else +#include +#include +#endif + +#define ICON_SIZE ImGui::GetFont()->FontSize + 3 +#define GUI_ELEMENT_SIZE std::max(GImGui->FontSize + 10.f, 24.f) +#define DEFAULT_ICON_SIZE 32 +#define PI 3.141592f + +namespace ifd { + static const char* GetDefaultFolderIcon(); + static const char* GetDefaultFileIcon(); + + /* UI CONTROLS */ + bool FolderNode(const char* label, ImTextureID icon, bool& clicked) + { + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + clicked = false; + + ImU32 id = window->GetID(label); + int opened = window->StateStorage.GetInt(id, 0); + ImVec2 pos = window->DC.CursorPos; + const bool is_mouse_x_over_arrow = (g.IO.MousePos.x >= pos.x && g.IO.MousePos.x < pos.x + g.FontSize); + if (ImGui::InvisibleButton(label, ImVec2(-FLT_MIN, g.FontSize + g.Style.FramePadding.y * 2))) + { + if (is_mouse_x_over_arrow) { + int* p_opened = window->StateStorage.GetIntRef(id, 0); + opened = *p_opened = !*p_opened; + } else { + clicked = true; + } + } + bool hovered = ImGui::IsItemHovered(); + bool active = ImGui::IsItemActive(); + bool doubleClick = ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left); + if (doubleClick && hovered) { + int* p_opened = window->StateStorage.GetIntRef(id, 0); + opened = *p_opened = !*p_opened; + clicked = false; + } + if (hovered || active) + window->DrawList->AddRectFilled(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, ImGui::ColorConvertFloat4ToU32(ImGui::GetStyle().Colors[active ? ImGuiCol_HeaderActive : ImGuiCol_HeaderHovered])); + + // Icon, text + float icon_posX = pos.x + g.FontSize + g.Style.FramePadding.y; + float text_posX = icon_posX + g.Style.FramePadding.y + ICON_SIZE; + ImGui::RenderArrow(window->DrawList, ImVec2(pos.x, pos.y+g.Style.FramePadding.y), ImGui::ColorConvertFloat4ToU32(ImGui::GetStyle().Colors[((hovered && is_mouse_x_over_arrow) || opened) ? ImGuiCol_Text : ImGuiCol_TextDisabled]), opened ? ImGuiDir_Down : ImGuiDir_Right); + window->DrawList->AddImage(icon, ImVec2(icon_posX, pos.y), ImVec2(icon_posX + ICON_SIZE, pos.y + ICON_SIZE)); + ImGui::RenderText(ImVec2(text_posX, pos.y + g.Style.FramePadding.y), label); + if (opened) + ImGui::TreePush(label); + return opened != 0; + } + bool FileNode(const char* label, ImTextureID icon) { + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + //ImU32 id = window->GetID(label); + ImVec2 pos = window->DC.CursorPos; + bool ret = ImGui::InvisibleButton(label, ImVec2(-FLT_MIN, g.FontSize + g.Style.FramePadding.y * 2)); + + bool hovered = ImGui::IsItemHovered(); + bool active = ImGui::IsItemActive(); + if (hovered || active) + window->DrawList->AddRectFilled(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, ImGui::ColorConvertFloat4ToU32(ImGui::GetStyle().Colors[active ? ImGuiCol_HeaderActive : ImGuiCol_HeaderHovered])); + + // Icon, text + window->DrawList->AddImage(icon, ImVec2(pos.x, pos.y), ImVec2(pos.x + ICON_SIZE, pos.y + ICON_SIZE)); + ImGui::RenderText(ImVec2(pos.x + g.Style.FramePadding.y + ICON_SIZE, pos.y + g.Style.FramePadding.y), label); + + return ret; + } + bool PathBox(const char* label, std::filesystem::path& path, char* pathBuffer, ImVec2 size_arg) { + ImGuiWindow* window = ImGui::GetCurrentWindow(); + if (window->SkipItems) + return false; + + bool ret = false; + const ImGuiID id = window->GetID(label); + int* state = window->StateStorage.GetIntRef(id, 0); + + ImGui::SameLine(); + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + ImVec2 pos = window->DC.CursorPos; + ImVec2 uiPos = ImGui::GetCursorPos(); + ImVec2 size = ImGui::CalcItemSize(size_arg, 200, GUI_ELEMENT_SIZE); + const ImRect bb(pos, pos + size); + + // buttons + if (!(*state & 0b001)) { + ImGui::PushClipRect(bb.Min, bb.Max, false); + + // background + bool hovered = g.IO.MousePos.x >= bb.Min.x && g.IO.MousePos.x <= bb.Max.x && + g.IO.MousePos.y >= bb.Min.y && g.IO.MousePos.y <= bb.Max.y; + bool clicked = hovered && ImGui::IsMouseReleased(ImGuiMouseButton_Left); + bool anyOtherHC = false; // are any other items hovered or clicked? + window->DrawList->AddRectFilled(pos, pos + size, ImGui::ColorConvertFloat4ToU32(ImGui::GetStyle().Colors[(*state & 0b10) ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg])); + + // fetch the buttons (so that we can throw some away if needed) + std::vector btnList; + float totalWidth = 0.0f; + for (auto comp : path) { + std::string section = comp.u8string(); + if (section.size() == 1 && (section[0] == '\\' || section[0] == '/')) + continue; + + totalWidth += ImGui::CalcTextSize(section.c_str()).x + style.FramePadding.x * 2.0f + GUI_ELEMENT_SIZE; + btnList.push_back(section); + } + totalWidth -= GUI_ELEMENT_SIZE; + + // UI buttons + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, ImGui::GetStyle().ItemSpacing.y)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + bool isFirstElement = true; + for (size_t i = 0; i < btnList.size(); i++) { + if (totalWidth > size.x - 30 && i != btnList.size() - 1) { // trim some buttons if there's not enough space + float elSize = ImGui::CalcTextSize(btnList[i].c_str()).x + style.FramePadding.x * 2.0f + GUI_ELEMENT_SIZE; + totalWidth -= elSize; + continue; + } + + ImGui::PushID(static_cast(i)); + if (!isFirstElement) { + ImGui::ArrowButtonEx("##dir_dropdown", ImGuiDir_Right, ImVec2(GUI_ELEMENT_SIZE, GUI_ELEMENT_SIZE)); + anyOtherHC |= ImGui::IsItemHovered() | ImGui::IsItemClicked(); + ImGui::SameLine(); + } + if (ImGui::Button(btnList[i].c_str(), ImVec2(0, GUI_ELEMENT_SIZE))) { +#ifdef _WIN32 + std::string newPath = ""; +#else + std::string newPath = "/"; +#endif + for (size_t j = 0; j <= i; j++) { + newPath += btnList[j]; +#ifdef _WIN32 + if (j != i) + newPath += "\\"; +#else + if (j != i) + newPath += "/"; +#endif + } + path = std::filesystem::u8path(newPath); + ret = true; + } + anyOtherHC |= ImGui::IsItemHovered() | ImGui::IsItemClicked(); + ImGui::SameLine(); + ImGui::PopID(); + + isFirstElement = false; + } + ImGui::PopStyleVar(2); + + + // click state + if (!anyOtherHC && clicked) { + strcpy(pathBuffer, path.u8string().c_str()); + *state |= 0b001; + *state &= 0b011; // remove SetKeyboardFocus flag + } + else + *state &= 0b110; + + // hover state + if (!anyOtherHC && hovered && !clicked) + *state |= 0b010; + else + *state &= 0b101; + + ImGui::PopClipRect(); + + // allocate space + ImGui::SetCursorPos(uiPos); + ImGui::ItemSize(size); + } + // input box + else { + bool skipActiveCheck = false; + if (!(*state & 0b100)) { + skipActiveCheck = true; + ImGui::SetKeyboardFocusHere(); + if (!ImGui::IsMouseClicked(ImGuiMouseButton_Left)) + *state |= 0b100; + } + if (ImGui::InputTextEx("##pathbox_input", "", pathBuffer, 1024, size_arg, ImGuiInputTextFlags_EnterReturnsTrue)) { + std::string tempStr(pathBuffer); + if (std::filesystem::exists(tempStr)) + path = std::filesystem::u8path(tempStr); + ret = true; + } + if (!skipActiveCheck && !ImGui::IsItemActive()) + *state &= 0b010; + } + + return ret; + } + + bool FileIcon(const char* label, bool isSelected, ImTextureID icon, ImVec2 size, bool hasPreview, int previewWidth, int previewHeight) + { + ImGuiStyle& style = ImGui::GetStyle(); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + float windowSpace = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x; + ImVec2 pos = window->DC.CursorPos; + bool ret = false; + + if (ImGui::InvisibleButton(label, size)) + ret = true; + + bool hovered = ImGui::IsItemHovered(); + bool active = ImGui::IsItemActive(); + bool doubleClick = ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left); + if (doubleClick && hovered) + ret = true; + + + float iconSize = size.y - g.FontSize * 2; + float iconPosX = pos.x + (size.x - iconSize) / 2.0f; + ImVec2 textSize = ImGui::CalcTextSize(label, 0, true, size.x); + + + if (hovered || active || isSelected) + window->DrawList->AddRectFilled(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, ImGui::ColorConvertFloat4ToU32(ImGui::GetStyle().Colors[active ? ImGuiCol_HeaderActive : (isSelected ? ImGuiCol_Header : ImGuiCol_HeaderHovered)])); + + if (hasPreview) { + ImVec2 availSize = ImVec2(size.x, iconSize); + + float scale = std::min(availSize.x / previewWidth, availSize.y / previewHeight); + availSize.x = previewWidth * scale; + availSize.y = previewHeight * scale; + + float previewPosX = pos.x + (size.x - availSize.x) / 2.0f; + float previewPosY = pos.y + (iconSize - availSize.y) / 2.0f; + + window->DrawList->AddImage(icon, ImVec2(previewPosX, previewPosY), ImVec2(previewPosX + availSize.x, previewPosY + availSize.y)); + } else + window->DrawList->AddImage(icon, ImVec2(iconPosX, pos.y), ImVec2(iconPosX + iconSize, pos.y + iconSize)); + + window->DrawList->AddText(g.Font, g.FontSize, ImVec2(pos.x + (size.x-textSize.x) / 2.0f, pos.y + iconSize), ImGui::ColorConvertFloat4ToU32(ImGui::GetStyle().Colors[ImGuiCol_Text]), label, 0, size.x); + + + float lastButtomPos = ImGui::GetItemRectMax().x; + float thisButtonPos = lastButtomPos + style.ItemSpacing.x + size.x; // Expected position if next button was on same line + if (thisButtonPos < windowSpace) + ImGui::SameLine(); + + return ret; + } + + FileDialog::FileData::FileData(const std::filesystem::path& path) { + std::error_code ec; + Path = path; + IsDirectory = std::filesystem::is_directory(path, ec); + Size = std::filesystem::file_size(path, ec); + + struct stat attr; + stat(path.u8string().c_str(), &attr); + DateModified = attr.st_ctime; + + HasIconPreview = false; + IconPreview = nullptr; + IconPreviewData = nullptr; + IconPreviewHeight = 0; + IconPreviewWidth = 0; + } + + FileDialog::FileDialog() { + m_isOpen = false; + m_type = 0; + m_calledOpenPopup = false; + m_sortColumn = 0; + m_sortDirection = ImGuiSortDirection_Ascending; + m_filterSelection = 0; + m_inputTextbox[0] = 0; + m_pathBuffer[0] = 0; + m_searchBuffer[0] = 0; + m_newEntryBuffer[0] = 0; + m_selectedFileItem = -1; + m_zoom = 1.0f; + + m_previewLoader = nullptr; + m_previewLoaderRunning = false; + + m_setDirectory(std::filesystem::current_path(), false); + + // favorites are available on every OS + FileTreeNode* quickAccess = new FileTreeNode("Quick Access"); + quickAccess->Read = true; + m_treeCache.push_back(quickAccess); + +#ifdef _WIN32 + wchar_t username[UNLEN + 1] = { 0 }; + DWORD username_len = UNLEN + 1; + GetUserNameW(username, &username_len); + + std::wstring userPath = L"C:\\Users\\" + std::wstring(username) + L"\\"; + + // Quick Access / Bookmarks + quickAccess->Children.push_back(new FileTreeNode(userPath + L"Desktop")); + quickAccess->Children.push_back(new FileTreeNode(userPath + L"Documents")); + quickAccess->Children.push_back(new FileTreeNode(userPath + L"Downloads")); + quickAccess->Children.push_back(new FileTreeNode(userPath + L"Pictures")); + + // OneDrive + FileTreeNode* oneDrive = new FileTreeNode(userPath + L"OneDrive"); + m_treeCache.push_back(oneDrive); + + // This PC + FileTreeNode* thisPC = new FileTreeNode("This PC"); + thisPC->Read = true; + if (std::filesystem::exists(userPath + L"3D Objects")) + thisPC->Children.push_back(new FileTreeNode(userPath + L"3D Objects")); + thisPC->Children.push_back(new FileTreeNode(userPath + L"Desktop")); + thisPC->Children.push_back(new FileTreeNode(userPath + L"Documents")); + thisPC->Children.push_back(new FileTreeNode(userPath + L"Downloads")); + thisPC->Children.push_back(new FileTreeNode(userPath + L"Music")); + thisPC->Children.push_back(new FileTreeNode(userPath + L"Pictures")); + thisPC->Children.push_back(new FileTreeNode(userPath + L"Videos")); + DWORD d = GetLogicalDrives(); + for (int i = 0; i < 26; i++) + if (d & (1 << i)) + thisPC->Children.push_back(new FileTreeNode(std::string(1, 'A' + i) + ":")); + m_treeCache.push_back(thisPC); +#else + std::error_code ec; + + // Quick Access + struct passwd *pw; + uid_t uid; + uid = geteuid(); + pw = getpwuid(uid); + if (pw) { + std::string homePath = "/home/" + std::string(pw->pw_name); + + if (std::filesystem::exists(homePath, ec)) + quickAccess->Children.push_back(new FileTreeNode(homePath)); + if (std::filesystem::exists(homePath + "/Desktop", ec)) + quickAccess->Children.push_back(new FileTreeNode(homePath + "/Desktop")); + if (std::filesystem::exists(homePath + "/Documents", ec)) + quickAccess->Children.push_back(new FileTreeNode(homePath + "/Documents")); + if (std::filesystem::exists(homePath + "/Downloads", ec)) + quickAccess->Children.push_back(new FileTreeNode(homePath + "/Downloads")); + if (std::filesystem::exists(homePath + "/Pictures", ec)) + quickAccess->Children.push_back(new FileTreeNode(homePath + "/Pictures")); + } + + // This PC + FileTreeNode* thisPC = new FileTreeNode("This PC"); + thisPC->Read = true; + for (const auto& entry : std::filesystem::directory_iterator("/", ec)) { + if (std::filesystem::is_directory(entry, ec)) + thisPC->Children.push_back(new FileTreeNode(entry.path().u8string())); + } + m_treeCache.push_back(thisPC); +#endif + } + FileDialog::~FileDialog() { + m_clearIconPreview(); + m_clearIcons(); + + for (auto fn : m_treeCache) + m_clearTree(fn); + m_treeCache.clear(); + } + bool FileDialog::Save(const std::string& key, const std::string& title, const std::string& filter, const std::string& startingDir) + { + if (!m_currentKey.empty()) + return false; + + m_currentKey = key; + m_currentTitle = title + "###" + key; + m_isOpen = true; + m_calledOpenPopup = false; + m_result.clear(); + m_inputTextbox[0] = 0; + m_selections.clear(); + m_selectedFileItem = -1; + m_isMultiselect = false; + m_type = IFD_DIALOG_SAVE; + + m_parseFilter(filter); + if (!startingDir.empty()) + m_setDirectory(std::filesystem::u8path(startingDir), false); + else + m_setDirectory(m_currentDirectory, false); // refresh contents + + return true; + } + bool FileDialog::Open(const std::string& key, const std::string& title, const std::string& filter, bool isMultiselect, const std::string& startingDir) + { + if (!m_currentKey.empty()) + return false; + + m_currentKey = key; + m_currentTitle = title + "###" + key; + m_isOpen = true; + m_calledOpenPopup = false; + m_result.clear(); + m_inputTextbox[0] = 0; + m_selections.clear(); + m_selectedFileItem = -1; + m_isMultiselect = isMultiselect; + m_type = filter.empty() ? IFD_DIALOG_DIRECTORY : IFD_DIALOG_FILE; + + m_parseFilter(filter); + if (!startingDir.empty()) + m_setDirectory(std::filesystem::u8path(startingDir), false); + else + m_setDirectory(m_currentDirectory, false); // refresh contents + + return true; + } + bool FileDialog::IsDone(const std::string& key, int window_w, int window_h) + { + bool isMe = m_currentKey == key; + + if (isMe && m_isOpen) { + ImGui::SetNextWindowPos({(window_w/2.0f)-400, (window_h/2.0f)-300}); + ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_Always); + if (!m_calledOpenPopup) { + ImGui::OpenPopup(m_currentTitle.c_str()); + m_calledOpenPopup = true; + } + + if (ImGui::BeginPopupModal(m_currentTitle.c_str(), &m_isOpen, ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove)) { + m_renderFileDialog(); + ImGui::EndPopup(); + } + else m_isOpen = false; + } + + return isMe && !m_isOpen; + } + void FileDialog::Close() + { + m_currentKey.clear(); + m_backHistory = std::stack(); + m_forwardHistory = std::stack(); + + // clear the tree + for (auto fn : m_treeCache) { + for (auto item : fn->Children) { + for (auto ch : item->Children) + m_clearTree(ch); + item->Children.clear(); + item->Read = false; + } + } + + // free icon textures + m_clearIconPreview(); + m_clearIcons(); + } + + void FileDialog::m_select(const std::filesystem::path& path, bool isCtrlDown) + { + bool multiselect = isCtrlDown && m_isMultiselect; + + if (!multiselect) { + m_selections.clear(); + m_selections.push_back(path); + } else { + auto it = std::find(m_selections.begin(), m_selections.end(), path); + if (it != m_selections.end()) + m_selections.erase(it); + else + m_selections.push_back(path); + } + + if (m_selections.size() == 1) { + std::string filename = m_selections[0].filename().u8string(); + if (filename.size() == 0) + filename = m_selections[0].u8string(); // drive + + strcpy(m_inputTextbox, filename.c_str()); + } + else { + std::string textboxVal = ""; + for (const auto& sel : m_selections) { + std::string filename = sel.filename().u8string(); + if (filename.size() == 0) + filename = sel.u8string(); + + textboxVal += "\"" + filename + "\", "; + } + strcpy(m_inputTextbox, textboxVal.substr(0, textboxVal.size() - 2).c_str()); + } + } + + bool FileDialog::m_finalize(const std::string& filename) + { + bool hasResult = (!filename.empty() && m_type != IFD_DIALOG_DIRECTORY) || m_type == IFD_DIALOG_DIRECTORY; + + if (hasResult) { + if (!m_isMultiselect || m_selections.size() <= 1) { + std::filesystem::path path = std::filesystem::u8path(filename); + if (path.is_absolute()) m_result.push_back(path); + else m_result.push_back(m_currentDirectory / path); + if (m_type == IFD_DIALOG_DIRECTORY || m_type == IFD_DIALOG_FILE) { + if (!std::filesystem::exists(m_result.back())) { + m_result.clear(); + return false; + } + } + } + else { + for (const auto& sel : m_selections) { + if (sel.is_absolute()) m_result.push_back(sel); + else m_result.push_back(m_currentDirectory / sel); + if (m_type == IFD_DIALOG_DIRECTORY || m_type == IFD_DIALOG_FILE) { + if (!std::filesystem::exists(m_result.back())) { + m_result.clear(); + return false; + } + } + } + } + + if (m_type == IFD_DIALOG_SAVE) { + // add the extension + if (m_filterSelection < m_filterExtensions.size() && m_filterExtensions[m_filterSelection].size() > 0) { + if (!m_result.back().has_extension()) { + std::string extAdd = m_filterExtensions[m_filterSelection][0]; + m_result.back().replace_extension(extAdd); + } + } + } + } + + m_isOpen = false; + + return true; + } + void FileDialog::m_parseFilter(const std::string& filter) + { + m_filter = ""; + m_filterExtensions.clear(); + m_filterSelection = 0; + + if (filter.empty()) + return; + + std::vector exts; + + size_t lastSplit = 0, lastExt = 0; + bool inExtList = false; + for (size_t i = 0; i < filter.size(); i++) { + if (filter[i] == ',') { + if (!inExtList) + lastSplit = i + 1; + else { + exts.push_back(filter.substr(lastExt, i - lastExt)); + lastExt = i + 1; + } + } + else if (filter[i] == '{') { + std::string filterName = filter.substr(lastSplit, i - lastSplit); + if (filterName == ".*") { + m_filter += std::string(std::string("All Files (*.*)\0").c_str(), 16); + m_filterExtensions.push_back(std::vector()); + } + else + m_filter += std::string((filterName + "\0").c_str(), filterName.size() + 1); + inExtList = true; + lastExt = i + 1; + } + else if (filter[i] == '}') { + exts.push_back(filter.substr(lastExt, i - lastExt)); + m_filterExtensions.push_back(exts); + exts.clear(); + + inExtList = false; + } + } + if (lastSplit != 0) { + std::string filterName = filter.substr(lastSplit); + if (filterName == ".*") { + m_filter += std::string(std::string("All Files (*.*)\0").c_str(), 16); + m_filterExtensions.push_back(std::vector()); + } + else + m_filter += std::string((filterName + "\0").c_str(), filterName.size() + 1); + } + } + + void* FileDialog::m_getIcon(const std::filesystem::path& path) + { +#ifdef _WIN32 + if (m_icons.count(path.u8string()) > 0) + return m_icons[path.u8string()]; + + std::string pathU8 = path.u8string(); + + std::error_code ec; + m_icons[pathU8] = nullptr; + + DWORD attrs = 0; + UINT flags = SHGFI_ICON | SHGFI_LARGEICON; + if (!std::filesystem::exists(path, ec)) { + flags |= SHGFI_USEFILEATTRIBUTES; + attrs = FILE_ATTRIBUTE_DIRECTORY; + } + + SHFILEINFOW fileInfo = { 0 }; + std::wstring pathW = path.wstring(); + for (int i = 0; i < pathW.size(); i++) + if (pathW[i] == '/') + pathW[i] = '\\'; + SHGetFileInfoW(pathW.c_str(), attrs, &fileInfo, sizeof(SHFILEINFOW), flags); + + if (fileInfo.hIcon == nullptr) + return nullptr; + + // check if icon is already loaded + auto itr = std::find(m_iconIndices.begin(), m_iconIndices.end(), fileInfo.iIcon); + if (itr != m_iconIndices.end()) { + const std::string& existingIconFilepath = m_iconFilepaths[itr - m_iconIndices.begin()]; + m_icons[pathU8] = m_icons[existingIconFilepath]; + return m_icons[pathU8]; + } + + m_iconIndices.push_back(fileInfo.iIcon); + m_iconFilepaths.push_back(pathU8); + + ICONINFO iconInfo = { 0 }; + GetIconInfo(fileInfo.hIcon, &iconInfo); + + if (iconInfo.hbmColor == nullptr) + return nullptr; + + DIBSECTION ds; + GetObject(iconInfo.hbmColor, sizeof(ds), &ds); + int byteSize = ds.dsBm.bmWidth * ds.dsBm.bmHeight * (ds.dsBm.bmBitsPixel / 8); + + if (byteSize == 0) + return nullptr; + + uint8_t* data = (uint8_t*)malloc(byteSize); + GetBitmapBits(iconInfo.hbmColor, byteSize, data); + + m_icons[pathU8] = this->CreateTexture(data, ds.dsBm.bmWidth, ds.dsBm.bmHeight, 0); + + free(data); + + return m_icons[pathU8]; +#else + if (m_icons.count(path.u8string()) > 0) + return m_icons[path.u8string()]; + + std::string pathU8 = path.u8string(); + + m_icons[pathU8] = nullptr; + + std::error_code ec; + int iconID = 1; + if (std::filesystem::is_directory(path, ec)) + iconID = 0; + + // check if icon is already loaded + auto itr = std::find(m_iconIndices.begin(), m_iconIndices.end(), iconID); + if (itr != m_iconIndices.end()) { + const std::string& existingIconFilepath = m_iconFilepaths[itr - m_iconIndices.begin()]; + m_icons[pathU8] = m_icons[existingIconFilepath]; + return m_icons[pathU8]; + } + + m_iconIndices.push_back(iconID); + m_iconFilepaths.push_back(pathU8); + + ImVec4 wndBg = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); + + // light theme - load default icons + if ((wndBg.x + wndBg.y + wndBg.z) / 3.0f > 0.5f) { + uint8_t* data = (uint8_t*)ifd::GetDefaultFileIcon(); + if (iconID == 0) + data = (uint8_t*)ifd::GetDefaultFolderIcon(); + m_icons[pathU8] = this->CreateTexture(data, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE, 0); + } + // dark theme - invert the colors + else { + uint8_t* data = (uint8_t*)ifd::GetDefaultFileIcon(); + if (iconID == 0) + data = (uint8_t*)ifd::GetDefaultFolderIcon(); + + uint8_t* invData = (uint8_t*)malloc(DEFAULT_ICON_SIZE * DEFAULT_ICON_SIZE * 4); + for (int y = 0; y < 32; y++) { + for (int x = 0; x < 32; x++) { + int index = (y* DEFAULT_ICON_SIZE + x) * 4; + invData[index + 0] = 255 - data[index + 0]; + invData[index + 1] = 255 - data[index + 1]; + invData[index + 2] = 255 - data[index + 2]; + invData[index + 3] = data[index + 3]; + } + } + m_icons[pathU8] = this->CreateTexture(invData, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE, 0); + + free(invData); + } + + return m_icons[pathU8]; +#endif + } + void FileDialog::m_clearIcons() + { + std::vector deletedIcons; + + // delete textures + for (auto& icon : m_icons) { + unsigned int ptr = (unsigned int)((uintptr_t)icon.second); + if (std::count(deletedIcons.begin(), deletedIcons.end(), ptr)) // skip duplicates + continue; + + deletedIcons.push_back(ptr); + //DeleteTexture(icon.second); + } + m_iconFilepaths.clear(); + m_iconIndices.clear(); + m_icons.clear(); + } + void FileDialog::m_refreshIconPreview() + { + if (m_zoom >= 5.0f) { + if (m_previewLoader == nullptr) { + m_previewLoaderRunning = true; + m_previewLoader = new std::thread(&FileDialog::m_loadPreview, this); + } + } else + m_clearIconPreview(); + } + void FileDialog::m_clearIconPreview() + { + m_stopPreviewLoader(); + + for (auto& data : m_content) { + if (!data.HasIconPreview) + continue; + + data.HasIconPreview = false; + this->DeleteTexture(data.IconPreview); + + if (data.IconPreviewData != nullptr) { + stbi_image_free(data.IconPreviewData); + data.IconPreviewData = nullptr; + } + } + } + void FileDialog::m_stopPreviewLoader() + { + if (m_previewLoader != nullptr) { + m_previewLoaderRunning = false; + + if (m_previewLoader && m_previewLoader->joinable()) + m_previewLoader->join(); + + delete m_previewLoader; + m_previewLoader = nullptr; + } + } + void FileDialog::m_loadPreview() + { + for (size_t i = 0; m_previewLoaderRunning && i < m_content.size(); i++) { + auto& data = m_content[i]; + + if (data.HasIconPreview) + continue; + + if (data.Path.has_extension()) { + std::string ext = data.Path.extension().u8string(); + if (ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".bmp" || ext == ".tga") { + int width, height, nrChannels; + unsigned char* image = stbi_load(data.Path.u8string().c_str(), &width, &height, &nrChannels, STBI_rgb_alpha); + + if (image == nullptr || width == 0 || height == 0) + continue; + + data.HasIconPreview = true; + data.IconPreviewData = image; + data.IconPreviewWidth = width; + data.IconPreviewHeight = height; + } + } + } + + m_previewLoaderRunning = false; + } + void FileDialog::m_clearTree(FileTreeNode* node) + { + if (node == nullptr) + return; + + for (auto n : node->Children) + m_clearTree(n); + + delete node; + node = nullptr; + } + void FileDialog::m_setDirectory(const std::filesystem::path& p, bool addHistory) + { + bool isSameDir = m_currentDirectory == p; + + if (addHistory && !isSameDir) + m_backHistory.push(m_currentDirectory); + + m_currentDirectory = p; +#ifdef _WIN32 + // drives don't work well without the backslash symbol + if (p.u8string().size() == 2 && p.u8string()[1] == ':') + m_currentDirectory = std::filesystem::u8path(p.u8string() + "\\"); +#endif + + m_clearIconPreview(); + m_content.clear(); // p == "" after this line, due to reference + m_selectedFileItem = -1; + + if (m_type == IFD_DIALOG_DIRECTORY || m_type == IFD_DIALOG_FILE) + m_inputTextbox[0] = 0; + m_selections.clear(); + + if (!isSameDir) { + m_searchBuffer[0] = 0; + m_clearIcons(); + } + + if (p.u8string() == "Quick Access") { + for (auto& node : m_treeCache) { + if (node->Path == p) + for (auto& c : node->Children) + m_content.push_back(FileData(c->Path)); + } + } + else if (p.u8string() == "This PC") { + for (auto& node : m_treeCache) { + if (node->Path == p) + for (auto& c : node->Children) + m_content.push_back(FileData(c->Path)); + } + } + else { + std::error_code ec; + if (std::filesystem::exists(m_currentDirectory, ec)) + for (const auto& entry : std::filesystem::directory_iterator(m_currentDirectory, ec)) { + FileData info(entry.path()); + + // skip files when IFD_DIALOG_DIRECTORY + if (!info.IsDirectory && m_type == IFD_DIALOG_DIRECTORY) + continue; + + // check if filename matches search query + if (m_searchBuffer[0]) { + std::string filename = info.Path.u8string(); + + std::string filenameSearch = filename; + std::string query(m_searchBuffer); + std::transform(filenameSearch.begin(), filenameSearch.end(), filenameSearch.begin(), ::tolower); + std::transform(query.begin(), query.end(), query.begin(), ::tolower); + + if (filenameSearch.find(query, 0) == std::string::npos) + continue; + } + + // check if extension matches + if (!info.IsDirectory && m_type != IFD_DIALOG_DIRECTORY) { + if (m_filterSelection < m_filterExtensions.size()) { + const auto& exts = m_filterExtensions[m_filterSelection]; + if (exts.size() > 0) { + std::string extension = info.Path.extension().u8string(); + + // extension not found? skip + if (std::count(exts.begin(), exts.end(), extension) == 0) + continue; + } + } + } + + m_content.push_back(info); + } + } + + m_sortContent(m_sortColumn, m_sortDirection); + m_refreshIconPreview(); + } + void FileDialog::m_sortContent(unsigned int column, unsigned int sortDirection) + { + // 0 -> name, 1 -> date, 2 -> size + m_sortColumn = column; + m_sortDirection = sortDirection; + + // split into directories and files + std::partition(m_content.begin(), m_content.end(), [](const FileData& data) { + return data.IsDirectory; + }); + + if (m_content.size() > 0) { + // find where the file list starts + size_t fileIndex = 0; + for (; fileIndex < m_content.size(); fileIndex++) + if (!m_content[fileIndex].IsDirectory) + break; + + // compare function + auto compareFn = [column, sortDirection](const FileData& left, const FileData& right) -> bool { + // name + if (column == 0) { + std::string lName = left.Path.u8string(); + std::string rName = right.Path.u8string(); + + std::transform(lName.begin(), lName.end(), lName.begin(), ::tolower); + std::transform(rName.begin(), rName.end(), rName.begin(), ::tolower); + + int comp = lName.compare(rName); + + if (sortDirection == ImGuiSortDirection_Ascending) + return comp < 0; + return comp > 0; + } + // date + else if (column == 1) { + if (sortDirection == ImGuiSortDirection_Ascending) + return left.DateModified < right.DateModified; + else + return left.DateModified > right.DateModified; + } + // size + else if (column == 2) { + if (sortDirection == ImGuiSortDirection_Ascending) + return left.Size < right.Size; + else + return left.Size > right.Size; + } + + return false; + }; + + // sort the directories + std::sort(m_content.begin(), m_content.begin() + fileIndex, compareFn); + + // sort the files + std::sort(m_content.begin() + fileIndex, m_content.end(), compareFn); + } + } + + void FileDialog::m_renderTree(FileTreeNode* node) + { + // directory + std::error_code ec; + ImGui::PushID(node); + bool isClicked = false; + std::string displayName = node->Path.stem().u8string(); + if (displayName.size() == 0) + displayName = node->Path.u8string(); + if (FolderNode(displayName.c_str(), (ImTextureID)m_getIcon(node->Path), isClicked)) { + if (!node->Read) { + // cache children if it's not already cached + if (std::filesystem::exists(node->Path, ec)) + for (const auto& entry : std::filesystem::directory_iterator(node->Path, ec)) { + if (std::filesystem::is_directory(entry, ec)) + node->Children.push_back(new FileTreeNode(entry.path().u8string())); + } + node->Read = true; + } + + // display children + for (auto c : node->Children) + m_renderTree(c); + + ImGui::TreePop(); + } + if (isClicked) + m_setDirectory(node->Path); + ImGui::PopID(); + } + void FileDialog::m_renderContent() + { + if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) + m_selectedFileItem = -1; + + // table view + if (m_zoom == 1.0f) { + if (ImGui::BeginTable("##contentTable", 3, /*ImGuiTableFlags_Resizable |*/ ImGuiTableFlags_Sortable, ImVec2(0, -FLT_MIN))) { + // header + ImGui::TableSetupColumn("Name##filename", ImGuiTableColumnFlags_WidthStretch, 0.0f -1.0f, 0); + ImGui::TableSetupColumn("Date modified##filedate", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize, 0.0f, 1); + ImGui::TableSetupColumn("Size##filesize", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize, 0.0f, 2); + ImGui::TableSetupScrollFreeze(0, 1); + ImGui::TableHeadersRow(); + + // sort + if (ImGuiTableSortSpecs* sortSpecs = ImGui::TableGetSortSpecs()) { + if (sortSpecs->SpecsDirty) { + sortSpecs->SpecsDirty = false; + m_sortContent(sortSpecs->Specs->ColumnUserID, sortSpecs->Specs->SortDirection); + } + } + + // content + int fileId = 0; + for (auto& entry : m_content) { + std::string filename = entry.Path.filename().u8string(); + if (filename.size() == 0) + filename = entry.Path.u8string(); // drive + + bool isSelected = std::count(m_selections.begin(), m_selections.end(), entry.Path); + + ImGui::TableNextRow(); + + // file name + ImGui::TableSetColumnIndex(0); + ImGui::Image((ImTextureID)m_getIcon(entry.Path), ImVec2(ICON_SIZE, ICON_SIZE)); + ImGui::SameLine(); + if (ImGui::Selectable(filename.c_str(), isSelected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) { + std::error_code ec; + bool isDir = std::filesystem::is_directory(entry.Path, ec); + + if (ImGui::IsMouseDoubleClicked(0)) { + if (isDir) { + m_setDirectory(entry.Path); + break; + } else + m_finalize(filename); + } else { + if ((isDir && m_type == IFD_DIALOG_DIRECTORY) || !isDir) + m_select(entry.Path, ImGui::GetIO().KeyCtrl); + } + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) + m_selectedFileItem = fileId; + fileId++; + + // date + ImGui::TableSetColumnIndex(1); + auto tm = std::localtime(&entry.DateModified); + if (tm != nullptr) + ImGui::Text("%d/%d/%d %02d:%02d", tm->tm_mon + 1, tm->tm_mday, 1900 + tm->tm_year, tm->tm_hour, tm->tm_min); + else ImGui::Text("---"); + + // size + ImGui::TableSetColumnIndex(2); + ImGui::Text("%.3f KiB", entry.Size/1024.0f); + } + + ImGui::EndTable(); + } + } + // "icon" view + else { + // content + int fileId = 0; + for (auto& entry : m_content) { + if (entry.HasIconPreview && entry.IconPreviewData != nullptr) { + entry.IconPreview = this->CreateTexture(entry.IconPreviewData, entry.IconPreviewWidth, entry.IconPreviewHeight, 1); + stbi_image_free(entry.IconPreviewData); + entry.IconPreviewData = nullptr; + } + + std::string filename = entry.Path.filename().u8string(); + if (filename.size() == 0) + filename = entry.Path.u8string(); // drive + + bool isSelected = std::count(m_selections.begin(), m_selections.end(), entry.Path); + + if (FileIcon(filename.c_str(), isSelected, entry.HasIconPreview ? entry.IconPreview : (ImTextureID)m_getIcon(entry.Path), ImVec2(32 + 16 * m_zoom, 32 + 16 * m_zoom), entry.HasIconPreview, entry.IconPreviewWidth, entry.IconPreviewHeight)) { + std::error_code ec; + bool isDir = std::filesystem::is_directory(entry.Path, ec); + + if (ImGui::IsMouseDoubleClicked(0)) { + if (isDir) { + m_setDirectory(entry.Path); + break; + } + else + m_finalize(filename); + } + else { + if ((isDir && m_type == IFD_DIALOG_DIRECTORY) || !isDir) + m_select(entry.Path, ImGui::GetIO().KeyCtrl); + } + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) + m_selectedFileItem = fileId; + fileId++; + } + } + } + void FileDialog::m_renderPopups() + { + bool openAreYouSureDlg = false, openNewFileDlg = false, openNewDirectoryDlg = false; + if (ImGui::BeginPopupContextItem("##dir_context")) { + if (ImGui::Selectable("New file")) + openNewFileDlg = true; + if (ImGui::Selectable("New directory")) + openNewDirectoryDlg = true; + if (m_selectedFileItem != -1 && ImGui::Selectable("Delete")) + openAreYouSureDlg = true; + ImGui::EndPopup(); + } + if (openAreYouSureDlg) + ImGui::OpenPopup("Are you sure?##delete"); + if (openNewFileDlg) + ImGui::OpenPopup("Enter file name##newfile"); + if (openNewDirectoryDlg) + ImGui::OpenPopup("Enter directory name##newdir"); + if (ImGui::BeginPopupModal("Are you sure?##delete")) { + if (m_selectedFileItem >= static_cast(m_content.size()) || m_content.size() == 0) + ImGui::CloseCurrentPopup(); + else { + const FileData& data = m_content[m_selectedFileItem]; + ImGui::TextWrapped("Are you sure you want to delete %s?", data.Path.filename().u8string().c_str()); + if (ImGui::Button("Yes")) { + std::error_code ec; + std::filesystem::remove_all(data.Path, ec); + m_setDirectory(m_currentDirectory, false); // refresh + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("No")) + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + if (ImGui::BeginPopupModal("Enter file name##newfile")) { + ImGui::PushItemWidth(250.0f); + ImGui::InputText("##newfilename", m_newEntryBuffer, 1024); // TODO: remove hardcoded literals + ImGui::PopItemWidth(); + + if (ImGui::Button("OK")) { + std::ofstream out((m_currentDirectory / std::string(m_newEntryBuffer)).string()); + out << ""; + out.close(); + + m_setDirectory(m_currentDirectory, false); // refresh + m_newEntryBuffer[0] = 0; + + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel")) { + m_newEntryBuffer[0] = 0; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + if (ImGui::BeginPopupModal("Enter directory name##newdir")) { + ImGui::PushItemWidth(250.0f); + ImGui::InputText("##newfilename", m_newEntryBuffer, 1024); // TODO: remove hardcoded literals + ImGui::PopItemWidth(); + + if (ImGui::Button("OK")) { + std::error_code ec; + std::filesystem::create_directory(m_currentDirectory / std::string(m_newEntryBuffer), ec); + m_setDirectory(m_currentDirectory, false); // refresh + m_newEntryBuffer[0] = 0; + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel")) { + ImGui::CloseCurrentPopup(); + m_newEntryBuffer[0] = 0; + } + ImGui::EndPopup(); + } + } + void FileDialog::m_renderFileDialog() + { + /***** TOP BAR *****/ + bool noBackHistory = m_backHistory.empty(), noForwardHistory = m_forwardHistory.empty(); + + ImGui::PushStyleColor(ImGuiCol_Button, 0); + if (noBackHistory) ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + if (ImGui::ArrowButtonEx("##back", ImGuiDir_Left, ImVec2(GUI_ELEMENT_SIZE, GUI_ELEMENT_SIZE), m_backHistory.empty() * ImGuiItemFlags_Disabled)) { + std::filesystem::path newPath = m_backHistory.top(); + m_backHistory.pop(); + m_forwardHistory.push(m_currentDirectory); + + m_setDirectory(newPath, false); + } + if (noBackHistory) ImGui::PopStyleVar(); + ImGui::SameLine(); + + if (noForwardHistory) ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + if (ImGui::ArrowButtonEx("##forward", ImGuiDir_Right, ImVec2(GUI_ELEMENT_SIZE, GUI_ELEMENT_SIZE), m_forwardHistory.empty() * ImGuiItemFlags_Disabled)) { + std::filesystem::path newPath = m_forwardHistory.top(); + m_forwardHistory.pop(); + m_backHistory.push(m_currentDirectory); + + m_setDirectory(newPath, false); + } + if (noForwardHistory) ImGui::PopStyleVar(); + ImGui::SameLine(); + + if (ImGui::ArrowButtonEx("##up", ImGuiDir_Up, ImVec2(GUI_ELEMENT_SIZE, GUI_ELEMENT_SIZE))) { + if (m_currentDirectory.has_parent_path()) + m_setDirectory(m_currentDirectory.parent_path()); + } + + std::filesystem::path curDirCopy = m_currentDirectory; + if (PathBox("##pathbox", curDirCopy, m_pathBuffer, ImVec2(-250, GUI_ELEMENT_SIZE))) + m_setDirectory(curDirCopy); + ImGui::SameLine(); + + ImGui::SameLine(); + ImGui::PopStyleColor(); + + if (ImGui::InputTextEx("##searchTB", "Search", m_searchBuffer, 128, ImVec2(-FLT_MIN, GUI_ELEMENT_SIZE), 0)) // TODO: no hardcoded literals + m_setDirectory(m_currentDirectory, false); // refresh + + + + /***** CONTENT *****/ + float bottomBarHeight = (GImGui->FontSize + ImGui::GetStyle().FramePadding.y + ImGui::GetStyle().ItemSpacing.y * 2.0f) * 2; + if (ImGui::BeginTable("##table", 2, ImGuiTableFlags_Resizable, ImVec2(0, -bottomBarHeight))) { + ImGui::TableSetupColumn("##tree", ImGuiTableColumnFlags_WidthFixed, 125.0f); + ImGui::TableSetupColumn("##content", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableNextRow(); + + // the tree on the left side + ImGui::TableSetColumnIndex(0); + ImGui::BeginChild("##treeContainer", ImVec2(0, -bottomBarHeight)); + for (auto node : m_treeCache) + m_renderTree(node); + ImGui::EndChild(); + + // content on the right side + ImGui::TableSetColumnIndex(1); + ImGui::BeginChild("##contentContainer", ImVec2(0, -bottomBarHeight)); + m_renderContent(); + ImGui::EndChild(); + if (ImGui::IsItemHovered() && ImGui::GetIO().KeyCtrl && ImGui::GetIO().MouseWheel != 0.0f) { + m_zoom = std::min(25.0f, std::max(1.0f, m_zoom + ImGui::GetIO().MouseWheel)); + m_refreshIconPreview(); + } + + // New file, New directory and Delete popups + m_renderPopups(); + + ImGui::EndTable(); + } + + + + /***** BOTTOM BAR *****/ + ImGui::Text("File name:"); + ImGui::SameLine(); + if (ImGui::InputTextEx("##file_input", "Filename", m_inputTextbox, 1024, ImVec2((m_type != IFD_DIALOG_DIRECTORY) ? -250.0f : -FLT_MIN, 0), ImGuiInputTextFlags_EnterReturnsTrue)) { + bool success = m_finalize(std::string(m_inputTextbox)); +#ifdef _WIN32 + if (!success) + MessageBeep(MB_ICONERROR); +#else + (void)success; +#endif + } + if (m_type != IFD_DIALOG_DIRECTORY) { + ImGui::SameLine(); + ImGui::SetNextItemWidth(-FLT_MIN); + int sel = static_cast(m_filterSelection); + if (ImGui::Combo("##ext_combo", &sel, m_filter.c_str())) { + m_filterSelection = static_cast(sel); + m_setDirectory(m_currentDirectory, false); // refresh + } + } + + // buttons + float ok_cancel_width = GUI_ELEMENT_SIZE * 7; + ImGui::SetCursorPosX(ImGui::GetWindowWidth() - ok_cancel_width); + if (ImGui::Button(m_type == IFD_DIALOG_SAVE ? "Save" : "Open", ImVec2(ok_cancel_width / 2 - ImGui::GetStyle().ItemSpacing.x, 0.0f))) { + std::string filename(m_inputTextbox); + bool success = false; + if (!filename.empty() || m_type == IFD_DIALOG_DIRECTORY) + success = m_finalize(filename); +#ifdef _WIN32 + if (!success) + MessageBeep(MB_ICONERROR); +#else + (void)success; +#endif + } + ImGui::SameLine(); + if (ImGui::Button("Cancel", ImVec2(-FLT_MIN, 0.0f))) { + if (m_type == IFD_DIALOG_DIRECTORY) + m_isOpen = false; + else + m_finalize(); + } + + int escapeKey = ImGui::GetIO().KeyMap[ImGuiKey_Escape]; + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && + escapeKey >= 0 && ImGui::IsKeyPressed((ImGuiKey)escapeKey, (ImGuiID)ImGuiKeyOwner_Any, ImGuiInputFlags_None)) + m_isOpen = false; + } +} + + +static const unsigned int file_icon[] = { + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x4c000000, 0xf5000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xdd000000, 0x2d000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0xd1000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6a000000, 0xa1000000, 0xff000000, 0xff000000, 0x2e000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x54000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x46000000, 0xf5000000, 0xe0000000, 0xff000000, 0x30000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6e000000, 0xf8000000, 0x01000000, 0xc3000000, 0xff000000, 0x30000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00000000, 0x00000000, 0xd2000000, 0xff000000, 0x30000000, 0x00000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x13000000, 0x00000000, 0x00000000, 0xd2000000, 0xff000000, 0x30000000, 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x73000000, 0xff000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xbe000000, 0xff000000, 0x30000000, 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x65000000, 0xff000000, 0x34000000, 0x10000000, 0x10000000, 0x03000000, 0x0a000000, 0xdb000000, 0xff000000, 0x2f000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0f000000, 0xd9000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xed000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x06000000, 0x5e000000, 0x6c000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x60000000, 0x9e000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x52000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6b000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6b000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0x54000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x54000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0xff000000, 0xd2000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0x6b000000, 0xd2000000, 0xff000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x4c000000, 0xf5000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xf5000000, 0x4b000000, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, +}; +static const unsigned int folder_icon[] = { + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00000000, 0x00000000, 0x45000000, 0x8a000000, 0x99000000, 0x97000000, 0x97000000, 0x97000000, 0x97000000, 0x97000000, 0x98000000, 0x81000000, 0x35000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x9e000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0x80000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x76000000, 0xff000000, 0xff000000, 0xf6000000, 0xe2000000, 0xe2000000, 0xe2000000, 0xe2000000, 0xe2000000, 0xe2000000, 0xe2000000, 0xff000000, 0xff000000, 0xff000000, 0x80000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xe7000000, 0xff000000, 0xbe000000, 0x11000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1e000000, 0xd1000000, 0xff000000, 0xff000000, 0x75000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xfa000000, 0xff000000, 0x5a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x06000000, 0xe0000000, 0xff000000, 0xff000000, 0x68000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xf4000000, 0xff000000, 0x67000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000000, 0xe4000000, 0xff000000, 0xff000000, 0xad000000, 0x94000000, 0x94000000, 0x94000000, 0x94000000, 0x94000000, 0x94000000, 0x94000000, 0x94000000, 0x94000000, 0x96000000, 0x8b000000, 0x4f000000, 0x00000000, 0x00000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x17000000, 0xe8000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xaf000000, 0x00000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0e000000, 0x88000000, 0xc3000000, 0xcd000000, 0xcc000000, 0xcc000000, 0xcc000000, 0xcc000000, 0xcc000000, 0xcc000000, 0xcc000000, 0xcb000000, 0xcc000000, 0xe2000000, 0xff000000, 0xff000000, 0x81000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xb6000000, 0xff000000, 0xec000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5b000000, 0xff000000, 0xf9000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x68000000, 0xff000000, 0xf4000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000, 0xff000000, 0xf3000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000, 0xff000000, 0xf3000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000, 0xff000000, 0xf3000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000, 0xff000000, 0xf3000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000, 0xff000000, 0xf3000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000, 0xff000000, 0xf3000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000, 0xff000000, 0xf3000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000, 0xff000000, 0xf3000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000, 0xff000000, 0xf3000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000, 0xff000000, 0xf3000000, + 0xf3000000, 0xff000000, 0x6a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000, 0xff000000, 0xf3000000, + 0xf4000000, 0xff000000, 0x68000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x68000000, 0xff000000, 0xf4000000, + 0xfa000000, 0xff000000, 0x5a000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5a000000, 0xff000000, 0xf9000000, + 0xea000000, 0xff000000, 0xb5000000, 0x05000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x05000000, 0xb5000000, 0xff000000, 0xea000000, + 0x7e000000, 0xff000000, 0xff000000, 0xeb000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xd6000000, 0xeb000000, 0xff000000, 0xff000000, 0x7f000000, + 0x00000000, 0xac000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xac000000, 0x00000000, + 0x00000000, 0x00000000, 0x53000000, 0x8f000000, 0x9a000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x99000000, 0x9a000000, 0x8f000000, 0x53000000, 0x00000000, 0x00000000, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, + 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, +}; +const char* ifd::GetDefaultFolderIcon() +{ + return (const char*)&folder_icon[0]; +} +const char* ifd::GetDefaultFileIcon() +{ + return (const char*)&file_icon[0]; +} diff --git a/imfiledialog/ImFileDialog.h b/imfiledialog/ImFileDialog.h new file mode 100644 index 0000000..76b2123 --- /dev/null +++ b/imfiledialog/ImFileDialog.h @@ -0,0 +1,136 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include // std::min, std::max + +#define IFD_DIALOG_FILE 0 +#define IFD_DIALOG_DIRECTORY 1 +#define IFD_DIALOG_SAVE 2 + +namespace ifd { + class FileDialog { + public: + static inline FileDialog& Instance() + { + static FileDialog ret; + return ret; + } + + FileDialog(); + ~FileDialog(); + + bool Save(const std::string& key, const std::string& title, const std::string& filter, const std::string& startingDir = ""); + + bool Open(const std::string& key, const std::string& title, const std::string& filter, bool isMultiselect = false, const std::string& startingDir = ""); + + bool IsDone(const std::string& key, int window_w, int window_h); + + inline bool HasResult() { return m_result.size(); } + inline const std::filesystem::path& GetResult() { return m_result[0]; } + inline const std::vector& GetResults() { return m_result; } + + void Close(); + + inline void SetZoom(float z) { + m_zoom = std::min(25.0f, std::max(1.0f, z)); + m_refreshIconPreview(); + } + inline float GetZoom() { return m_zoom; } + + std::function CreateTexture; // char -> fmt -> { 0 = BGRA, 1 = RGBA } + std::function DeleteTexture; + + class FileTreeNode { + public: +#ifdef _WIN32 + FileTreeNode(const std::wstring& path) { + Path = std::filesystem::path(path); + Read = false; + } +#endif + + FileTreeNode(const std::string& path) { + Path = std::filesystem::u8path(path); + Read = false; + } + + std::filesystem::path Path; + bool Read; + std::vector Children; + }; + class FileData { + public: + FileData(const std::filesystem::path& path); + + std::filesystem::path Path; + bool IsDirectory; + size_t Size; + time_t DateModified; + + bool HasIconPreview; + void* IconPreview; + uint8_t* IconPreviewData; + int IconPreviewWidth, IconPreviewHeight; + }; + + private: + std::string m_currentKey; + std::string m_currentTitle; + std::filesystem::path m_currentDirectory; + bool m_isMultiselect; + bool m_isOpen; + uint8_t m_type; + char m_inputTextbox[1024]; + char m_pathBuffer[1024]; + char m_newEntryBuffer[1024]; + char m_searchBuffer[128]; + bool m_calledOpenPopup; + std::stack m_backHistory, m_forwardHistory; + float m_zoom; + + std::vector m_selections; + int m_selectedFileItem; + void m_select(const std::filesystem::path& path, bool isCtrlDown = false); + + std::vector m_result; + bool m_finalize(const std::string& filename = ""); + + std::string m_filter; + std::vector> m_filterExtensions; + size_t m_filterSelection; + void m_parseFilter(const std::string& filter); + + std::vector m_iconIndices; + std::vector m_iconFilepaths; // m_iconIndices[x] <-> m_iconFilepaths[x] + std::unordered_map m_icons; + void* m_getIcon(const std::filesystem::path& path); + void m_clearIcons(); + void m_refreshIconPreview(); + void m_clearIconPreview(); + + std::thread* m_previewLoader; + bool m_previewLoaderRunning; + void m_stopPreviewLoader(); + void m_loadPreview(); + + std::vector m_treeCache; + void m_clearTree(FileTreeNode* node); + void m_renderTree(FileTreeNode* node); + + unsigned int m_sortColumn; + unsigned int m_sortDirection; + std::vector m_content; + void m_setDirectory(const std::filesystem::path& p, bool addHistory = true); + void m_sortContent(unsigned int column, unsigned int sortDirection); + void m_renderContent(); + + void m_renderPopups(); + void m_renderFileDialog(); + }; +} diff --git a/imfiledialog/LICENSE b/imfiledialog/LICENSE new file mode 100644 index 0000000..24cafde --- /dev/null +++ b/imfiledialog/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 dfranx + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/imgui/imconfig.h b/imgui/imconfig.h index 13166d8..d556cba 100644 --- a/imgui/imconfig.h +++ b/imgui/imconfig.h @@ -27,7 +27,7 @@ //#define IMGUI_API __declspec( dllimport ) //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names. -#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS +//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS //#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS. //---- Disable all of Dear ImGui or don't implement standard windows/tools. diff --git a/src/image.cpp b/src/image.cpp index e7df8b8..091a128 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -1,5 +1,6 @@ #include "image.h" #include "definitions.h" +#include "../imfiledialog/ImFileDialog.h" #define STB_IMAGE_IMPLEMENTATION #include "../stb_image.h" @@ -64,4 +65,22 @@ void ts_load_images() { size = _binary_misc_folder_png_end - _binary_misc_folder_png_start; data = (unsigned char *)_binary_misc_folder_png_start; img_folder = _ts_load_image(data, size); + + ifd::FileDialog::Instance().CreateTexture = [](uint8_t* data, int w, int h, char fmt) -> void* { + GLuint tex; + + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + //glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + + return (void*)(intptr_t)tex; + }; + ifd::FileDialog::Instance().DeleteTexture = [](void* tex) { + GLuint texID = (GLuint)tex; + glDeleteTextures(1, &texID); + }; } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 5dc0f04..a709ef4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,7 @@ #include "../imgui/imgui_spectrum.h" #include "../imgui/imgui_impl_opengl3_loader.h" #include "../imspinner/imspinner.h" +#include "../imfiledialog/imFileDialog.h" #include "../utf8.h" #include "definitions.h" #include "search.h" @@ -328,7 +329,17 @@ void ts_create_gui(int window_w, int window_h) { ImGui::BeginChild("search-boxes2", ImVec2(frame_w, textbox_area_height), false); { ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); - ImGui::ImageButton("Folder", (void*)(intptr_t)img_folder.id, ImVec2(18.0f, 18.0f)); + if (ImGui::ImageButton("Folder", (void*)(intptr_t)img_folder.id, ImVec2(18.0f, 18.0f))) { + ifd::FileDialog::Instance().Open("FolderSelectDialog", "Select a directory", ""); + } + if (ifd::FileDialog::Instance().IsDone("FolderSelectDialog", window_w, window_h)) { + if (ifd::FileDialog::Instance().HasResult()) { + std::string res = ifd::FileDialog::Instance().GetResult().u8string(); + snprintf(path_buffer, MAX_INPUT_LENGTH, res.c_str()); + } + ifd::FileDialog::Instance().Close(); + } + ImGui::SameLine(); ImGui::PushItemWidth(-1); if (ImGui::InputTextWithHint("filter-ti", "Filter", filter_buffer, MAX_INPUT_LENGTH, ImGuiInputTextFlags_EnterReturnsTrue)) { -- cgit v1.2.3-70-g09d2