1
0
mirror of synced 2024-11-30 18:34:29 +01:00

ui/ux: Give up on custom ImGui file browsers and just use the system one

This commit is contained in:
WerWolv 2021-02-22 23:36:13 +01:00
parent 7f97416e6e
commit 0af8b8155f
15 changed files with 53 additions and 2545 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "external/nativefiledialog"]
path = external/nativefiledialog
url = https://github.com/btzy/nativefiledialog-extended

View File

@ -19,7 +19,6 @@ add_library(imgui
source/imgui_impl_opengl3.cpp source/imgui_impl_opengl3.cpp
source/imgui_tables.cpp source/imgui_tables.cpp
source/imgui_widgets.cpp source/imgui_widgets.cpp
source/ImGuiFileBrowser.cpp
source/TextEditor.cpp source/TextEditor.cpp
source/imgui_imhex_extensions.cpp source/imgui_imhex_extensions.cpp
source/imnodes.cpp source/imnodes.cpp

File diff suppressed because it is too large Load Diff

View File

@ -1,123 +0,0 @@
#ifndef IMGUIFILEBROWSER_H
#define IMGUIFILEBROWSER_H
#include <imgui.h>
#include <string>
#include <vector>
namespace imgui_addons
{
class ImGuiFileBrowser
{
public:
ImGuiFileBrowser();
~ImGuiFileBrowser();
enum class DialogMode
{
SELECT, //Select Directory Mode
OPEN, //Open File mode
SAVE //Save File mode.
};
/* Use this to show an open file dialog. The function takes label for the window,
* the size, a DialogMode enum value defining in which mode the dialog should operate and optionally the extensions that are valid for opening.
* Note that the select directory mode doesn't need any extensions.
*/
bool showFileDialog(const std::string& label, const DialogMode mode, const ImVec2& sz_xy = ImVec2(0,0), const std::string& valid_types = "*.*");
/* Store the opened/saved file name or dir name (incase of selectDirectoryDialog) and the absolute path to the selection
* Should only be accessed when above functions return true else may contain garbage.
*/
std::string selected_fn;
std::string selected_path;
std::string ext; // Store the saved file extension
private:
struct Info
{
Info(std::string name, bool is_hidden) : name(name), is_hidden(is_hidden)
{
}
std::string name;
bool is_hidden;
};
//Enum used as bit flags.
enum FilterMode
{
FilterMode_Files = 0x01,
FilterMode_Dirs = 0x02
};
//Helper Functions
static std::string wStringToString(const wchar_t* wchar_arr);
static bool alphaSortComparator(const Info& a, const Info& b);
ImVec2 getButtonSize(std::string button_text);
/* Helper Functions that render secondary modals
* and help in validating file extensions and for filtering, parsing top navigation bar.
*/
void setValidExtTypes(const std::string& valid_types_string);
bool validateFile();
void showErrorModal();
void showInvalidFileModal();
bool showReplaceFileModal();
void showHelpMarker(std::string desc);
void parsePathTabs(std::string str);
void filterFiles(int filter_mode);
/* Core Functions that render the 4 different regions making up
* a simple file dialog
*/
bool renderNavAndSearchBarRegion();
bool renderFileListRegion();
bool renderInputTextAndExtRegion();
bool renderButtonsAndCheckboxRegion();
bool renderInputComboBox();
void renderExtBox();
/* Core Functions that handle navigation and
* reading directories/files
*/
bool readDIR(std::string path);
bool onNavigationButtonClick(int idx);
bool onDirClick(int idx);
// Functions that reset state and/or clear file list when reading new directory
void clearFileList();
void closeDialog();
#if defined (WIN32) || defined (_WIN32) || defined (__WIN32)
bool loadWindowsDrives(); // Helper Function for Windows to load Drive Letters.
#endif
#if defined(unix) || defined(__unix__) || defined(__unix) || defined(__APPLE__)
void initCurrentPath(); // Helper function for UNIX based system to load Absolute path using realpath
#endif
ImVec2 min_size, max_size, input_combobox_pos, input_combobox_sz;
DialogMode dialog_mode;
int filter_mode, col_items_limit, selected_idx, selected_ext_idx;
float col_width, ext_box_width;
bool show_hidden, show_inputbar_combobox, is_dir, is_appearing, filter_dirty, validate_file, path_input_enabled;
char input_fn[256];
char temp_dir_input[256];
std::vector<std::string> valid_exts;
std::vector<std::string> current_dirlist;
std::vector<Info> subdirs;
std::vector<Info> subfiles;
std::string current_path, error_msg, error_title, invfile_modal_id, repfile_modal_id;
ImGuiTextFilter filter;
std::string valid_types;
std::vector<const Info*> filtered_dirs; // Note: We don't need to call delete. It's just for storing filtered items from subdirs and subfiles so we don't use PassFilter every frame.
std::vector<const Info*> filtered_files;
std::vector< std::reference_wrapper<std::string> > inputcb_filter_files;
};
}
#endif // IMGUIFILEBROWSER_H

File diff suppressed because it is too large Load Diff

1
external/nativefiledialog vendored Submodule

@ -0,0 +1 @@
Subproject commit fbd8480bd63b8b9d808e3206acccd1cb113bac8b

View File

@ -5,7 +5,6 @@
#include "helpers/encoding_file.hpp" #include "helpers/encoding_file.hpp"
#include <imgui_memory_editor.h> #include <imgui_memory_editor.h>
#include <ImGuiFileBrowser.h>
#include <list> #include <list>
#include <tuple> #include <tuple>

View File

@ -12,7 +12,6 @@
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <ImGuiFileBrowser.h>
#include <TextEditor.h> #include <TextEditor.h>
namespace hex { namespace hex {

View File

@ -5,6 +5,7 @@ set(CMAKE_CXX_STANDARD 20)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/ImGui ${CMAKE_CURRENT_BINARY_DIR}/external/ImGui) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/ImGui ${CMAKE_CURRENT_BINARY_DIR}/external/ImGui)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/nlohmann_json ${CMAKE_CURRENT_BINARY_DIR}/external/nlohmann_json) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/nlohmann_json ${CMAKE_CURRENT_BINARY_DIR}/external/nlohmann_json)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/nativefiledialog ${CMAKE_CURRENT_BINARY_DIR}/external/nativefiledialog)
if (WIN32) if (WIN32)
@ -42,7 +43,7 @@ target_include_directories(libimhex PUBLIC include ${MBEDTLS_INCLUDE_DIR})
target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR}) target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR})
if (WIN32) if (WIN32)
target_link_libraries(libimhex PUBLIC imgui nlohmann_json libmbedcrypto.a) target_link_libraries(libimhex PUBLIC imgui nlohmann_json libmbedcrypto.a nfd)
else () else ()
target_link_libraries(libimhex PUBLIC imgui nlohmann_json mbedcrypto) target_link_libraries(libimhex PUBLIC imgui nlohmann_json mbedcrypto nfd)
endif () endif ()

View File

@ -13,7 +13,6 @@
#include <hex/views/view.hpp> #include <hex/views/view.hpp>
#include <imgui.h> #include <imgui.h>
#include <ImGuiFileBrowser.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -71,12 +70,6 @@ namespace hex {
static std::vector<ContentRegistry::Interface::DrawCallback> welcomeScreenEntries; static std::vector<ContentRegistry::Interface::DrawCallback> welcomeScreenEntries;
static std::vector<ContentRegistry::Interface::DrawCallback> footerItems; static std::vector<ContentRegistry::Interface::DrawCallback> footerItems;
static imgui_addons::ImGuiFileBrowser fileBrowser;
static imgui_addons::ImGuiFileBrowser::DialogMode fileBrowserDialogMode;
static std::string fileBrowserTitle;
static std::string fileBrowserValidExtensions;
static std::function<void(std::string)> fileBrowserCallback;
static std::vector<ContentRegistry::DataProcessorNode::Entry> dataProcessorNodes; static std::vector<ContentRegistry::DataProcessorNode::Entry> dataProcessorNodes;
static u32 dataProcessorNodeIdCounter; static u32 dataProcessorNodeIdCounter;

View File

@ -3,7 +3,7 @@
#include <hex.hpp> #include <hex.hpp>
#include <imgui.h> #include <imgui.h>
#include <ImGuiFileBrowser.h> #include <nfd.hpp>
#include <hex/api/event.hpp> #include <hex/api/event.hpp>
#include <hex/providers/provider.hpp> #include <hex/providers/provider.hpp>
@ -27,7 +27,13 @@ namespace hex {
virtual bool isAvailable(); virtual bool isAvailable();
virtual bool shouldProcess() { return this->isAvailable() && this->getWindowOpenState(); } virtual bool shouldProcess() { return this->isAvailable() && this->getWindowOpenState(); }
static void openFileBrowser(std::string title, imgui_addons::ImGuiFileBrowser::DialogMode mode, std::string validExtensions, const std::function<void(std::string)> &callback); enum class DialogMode {
Open,
Save,
Folder
};
static void openFileBrowser(std::string_view title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::string)> &callback);
static void doLater(std::function<void()> &&function); static void doLater(std::function<void()> &&function);
static std::vector<std::function<void()>>& getDeferedCalls(); static std::vector<std::function<void()>>& getDeferedCalls();

View File

@ -25,12 +25,6 @@ namespace hex {
std::vector<ContentRegistry::Interface::DrawCallback> SharedData::welcomeScreenEntries; std::vector<ContentRegistry::Interface::DrawCallback> SharedData::welcomeScreenEntries;
std::vector<ContentRegistry::Interface::DrawCallback> SharedData::footerItems; std::vector<ContentRegistry::Interface::DrawCallback> SharedData::footerItems;
imgui_addons::ImGuiFileBrowser SharedData::fileBrowser;
imgui_addons::ImGuiFileBrowser::DialogMode SharedData::fileBrowserDialogMode;
std::string SharedData::fileBrowserTitle;
std::string SharedData::fileBrowserValidExtensions;
std::function<void(std::string)> SharedData::fileBrowserCallback;
std::vector<ContentRegistry::DataProcessorNode::Entry> SharedData::dataProcessorNodes; std::vector<ContentRegistry::DataProcessorNode::Entry> SharedData::dataProcessorNodes;
u32 SharedData::dataProcessorNodeIdCounter = 1; u32 SharedData::dataProcessorNodeIdCounter = 1;

View File

@ -28,15 +28,30 @@ namespace hex {
return EventManager::post(eventType, userData); return EventManager::post(eventType, userData);
} }
void View::openFileBrowser(std::string title, imgui_addons::ImGuiFileBrowser::DialogMode mode, std::string validExtensions, const std::function<void(std::string)> &callback) { void View::openFileBrowser(std::string_view title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::string)> &callback) {
SharedData::fileBrowserTitle = title; NFD::Init();
SharedData::fileBrowserDialogMode = mode;
SharedData::fileBrowserValidExtensions = std::move(validExtensions);
SharedData::fileBrowserCallback = callback;
View::doLater([title]{ nfdchar_t *outPath;
ImGui::OpenPopup(title.c_str()); nfdresult_t result;
}); switch (mode) {
case DialogMode::Open:
result = NFD::OpenDialog(outPath, validExtensions.data(), validExtensions.size(), nullptr);
break;
case DialogMode::Save:
result = NFD::SaveDialog(outPath, validExtensions.data(), validExtensions.size(), nullptr);
break;
case DialogMode::Folder:
result = NFD::PickFolder(outPath, nullptr);
break;
default: __builtin_unreachable();
}
if (result == NFD_OKAY) {
callback(outPath);
NFD::FreePath(outPath);
}
NFD::Quit();
} }
void View::drawCommonInterfaces() { void View::drawCommonInterfaces() {
@ -49,11 +64,6 @@ namespace hex {
ImGui::EndPopup(); ImGui::EndPopup();
} }
if (SharedData::fileBrowser.showFileDialog(SharedData::fileBrowserTitle, SharedData::fileBrowserDialogMode, ImVec2(0, 0), SharedData::fileBrowserValidExtensions)) {
SharedData::fileBrowserCallback(SharedData::fileBrowser.selected_path);
SharedData::fileBrowserTitle = "";
}
} }
void View::showErrorPopup(std::string_view errorMessage) { void View::showErrorPopup(std::string_view errorMessage) {

View File

@ -174,12 +174,12 @@ namespace hex {
View::subscribeEvent(Events::OpenWindow, [this](auto name) { View::subscribeEvent(Events::OpenWindow, [this](auto name) {
if (std::any_cast<const char*>(name) == std::string("Open File")) { if (std::any_cast<const char*>(name) == std::string("Open File")) {
View::openFileBrowser("hex.view.hexeditor.open_file"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) { View::openFileBrowser("hex.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) {
this->openFile(path); this->openFile(path);
this->getWindowOpenState() = true; this->getWindowOpenState() = true;
}); });
} else if (std::any_cast<const char*>(name) == std::string("Open Project")) { } else if (std::any_cast<const char*>(name) == std::string("Open Project")) {
View::openFileBrowser("hex.view.hexeditor.open_project"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ".hexproj", [this](auto path) { View::openFileBrowser("hex.view.hexeditor.open_project"_lang, DialogMode::Open, { { "Project File", "hexproj" } }, [this](auto path) {
ProjectFile::load(path); ProjectFile::load(path);
View::postEvent(Events::ProjectFileLoad); View::postEvent(Events::ProjectFileLoad);
this->getWindowOpenState() = true; this->getWindowOpenState() = true;
@ -246,7 +246,7 @@ namespace hex {
} }
static void saveAs() { static void saveAs() {
View::openFileBrowser("hex.view.hexeditor.save_as"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, "*.*", [](auto path) { View::openFileBrowser("hex.view.hexeditor.save_as"_lang, View::DialogMode::Save, { }, [](auto path) {
FILE *file = fopen(path.c_str(), "wb"); FILE *file = fopen(path.c_str(), "wb");
if (file != nullptr) { if (file != nullptr) {
@ -293,14 +293,14 @@ namespace hex {
ImGui::InputText("##nolabel", this->m_loaderScriptScriptPath.data(), this->m_loaderScriptScriptPath.length(), ImGuiInputTextFlags_ReadOnly); ImGui::InputText("##nolabel", this->m_loaderScriptScriptPath.data(), this->m_loaderScriptScriptPath.length(), ImGuiInputTextFlags_ReadOnly);
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("hex.view.hexeditor.script.script"_lang)) { if (ImGui::Button("hex.view.hexeditor.script.script"_lang)) {
View::openFileBrowser("hex.view.hexeditor.script.script.title"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ".py", [this](auto path) { View::openFileBrowser("hex.view.hexeditor.script.script.title"_lang, DialogMode::Open, { { "Python Script", "py" } }, [this](auto path) {
this->m_loaderScriptScriptPath = path; this->m_loaderScriptScriptPath = path;
}); });
} }
ImGui::InputText("##nolabel", this->m_loaderScriptFilePath.data(), this->m_loaderScriptFilePath.length(), ImGuiInputTextFlags_ReadOnly); ImGui::InputText("##nolabel", this->m_loaderScriptFilePath.data(), this->m_loaderScriptFilePath.length(), ImGuiInputTextFlags_ReadOnly);
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("hex.view.hexeditor.script.file"_lang)) { if (ImGui::Button("hex.view.hexeditor.script.file"_lang)) {
View::openFileBrowser("hex.view.hexeditor.script.file.title"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) { View::openFileBrowser("hex.view.hexeditor.script.file.title"_lang, DialogMode::Open, { }, [this](auto path) {
this->m_loaderScriptFilePath = path; this->m_loaderScriptFilePath = path;
}); });
} }
@ -353,7 +353,7 @@ namespace hex {
if (ImGui::BeginMenu("hex.menu.file"_lang)) { if (ImGui::BeginMenu("hex.menu.file"_lang)) {
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.open_file"_lang, "CTRL + O")) { if (ImGui::MenuItem("hex.view.hexeditor.menu.file.open_file"_lang, "CTRL + O")) {
View::openFileBrowser("hex.view.hexeditor.open_file"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) { View::openFileBrowser("hex.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) {
this->openFile(path); this->openFile(path);
this->getWindowOpenState() = true; this->getWindowOpenState() = true;
}); });
@ -370,7 +370,7 @@ namespace hex {
ImGui::Separator(); ImGui::Separator();
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.open_project"_lang, "")) { if (ImGui::MenuItem("hex.view.hexeditor.menu.file.open_project"_lang, "")) {
View::openFileBrowser("hex.view.hexeditor.menu.file.open_project"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ".hexproj", [this](auto path) { View::openFileBrowser("hex.view.hexeditor.menu.file.open_project"_lang, DialogMode::Open, { { "Project File", "hexproj" } }, [this](auto path) {
ProjectFile::load(path); ProjectFile::load(path);
View::postEvent(Events::ProjectFileLoad); View::postEvent(Events::ProjectFileLoad);
this->getWindowOpenState() = true; this->getWindowOpenState() = true;
@ -381,7 +381,7 @@ namespace hex {
View::postEvent(Events::ProjectFileStore); View::postEvent(Events::ProjectFileStore);
if (ProjectFile::getProjectFilePath() == "") { if (ProjectFile::getProjectFilePath() == "") {
View::openFileBrowser("hex.view.hexeditor.save_project"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, ".hexproj", [](auto path) { View::openFileBrowser("hex.view.hexeditor.save_project"_lang, DialogMode::Save, { { "Project File", "hexproj" } }, [](auto path) {
ProjectFile::store(path); ProjectFile::store(path);
}); });
} }
@ -390,7 +390,7 @@ namespace hex {
} }
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.load_encoding_file"_lang)) { if (ImGui::MenuItem("hex.view.hexeditor.menu.file.load_encoding_file"_lang)) {
View::openFileBrowser("hex.view.hexeditor.load_enconding_file"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) { View::openFileBrowser("hex.view.hexeditor.load_enconding_file"_lang, DialogMode::Open, { }, [this](auto path) {
this->m_currEncodingFile = EncodingFile(EncodingFile::Type::Thingy, path); this->m_currEncodingFile = EncodingFile(EncodingFile::Type::Thingy, path);
}); });
} }
@ -400,7 +400,7 @@ namespace hex {
if (ImGui::BeginMenu("hex.view.hexeditor.menu.file.import"_lang)) { if (ImGui::BeginMenu("hex.view.hexeditor.menu.file.import"_lang)) {
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.import.base64"_lang)) { if (ImGui::MenuItem("hex.view.hexeditor.menu.file.import.base64"_lang)) {
View::openFileBrowser("hex.view.hexeditor.menu.file.import.base64"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) { View::openFileBrowser("hex.view.hexeditor.menu.file.import.base64"_lang, DialogMode::Open, { }, [this](auto path) {
std::vector<u8> base64; std::vector<u8> base64;
this->loadFromFile(path, base64); this->loadFromFile(path, base64);
@ -420,7 +420,7 @@ namespace hex {
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.import.ips"_lang)) { if (ImGui::MenuItem("hex.view.hexeditor.menu.file.import.ips"_lang)) {
View::openFileBrowser("hex.view.hexeditor.open_file"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) { View::openFileBrowser("hex.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) {
auto patchData = hex::readFile(path); auto patchData = hex::readFile(path);
auto patch = hex::loadIPSPatch(patchData); auto patch = hex::loadIPSPatch(patchData);
@ -434,7 +434,7 @@ namespace hex {
} }
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.import.ips32"_lang)) { if (ImGui::MenuItem("hex.view.hexeditor.menu.file.import.ips32"_lang)) {
View::openFileBrowser("hex.view.hexeditor.open_file"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) { View::openFileBrowser("hex.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) {
auto patchData = hex::readFile(path); auto patchData = hex::readFile(path);
auto patch = hex::loadIPS32Patch(patchData); auto patch = hex::loadIPS32Patch(patchData);
@ -464,7 +464,7 @@ namespace hex {
} }
this->m_dataToSave = generateIPSPatch(patches); this->m_dataToSave = generateIPSPatch(patches);
View::openFileBrowser("hex.view.hexeditor.menu.file.export.title"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, "*.*", [this](auto path) { View::openFileBrowser("hex.view.hexeditor.menu.file.export.title"_lang, DialogMode::Save, { }, [this](auto path) {
this->saveToFile(path, this->m_dataToSave); this->saveToFile(path, this->m_dataToSave);
}); });
} }
@ -477,7 +477,7 @@ namespace hex {
} }
this->m_dataToSave = generateIPS32Patch(patches); this->m_dataToSave = generateIPS32Patch(patches);
View::openFileBrowser("hex.view.hexeditor.menu.file.export.title"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, "*.*", [this](auto path) { View::openFileBrowser("hex.view.hexeditor.menu.file.export.title"_lang, DialogMode::Save, { }, [this](auto path) {
this->saveToFile(path, this->m_dataToSave); this->saveToFile(path, this->m_dataToSave);
}); });
} }

View File

@ -206,7 +206,7 @@ namespace hex {
void ViewPattern::drawMenu() { void ViewPattern::drawMenu() {
if (ImGui::BeginMenu("hex.menu.file"_lang)) { if (ImGui::BeginMenu("hex.menu.file"_lang)) {
if (ImGui::MenuItem("hex.view.pattern.menu.file.load_pattern"_lang)) { if (ImGui::MenuItem("hex.view.pattern.menu.file.load_pattern"_lang)) {
View::openFileBrowser("hex.view.pattern.open_pattern"_lang, imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ".hexpat", [this](auto path) { View::openFileBrowser("hex.view.pattern.open_pattern"_lang, DialogMode::Open, { { "Pattern File", "hexpat" } }, [this](auto path) {
this->loadPatternFile(path); this->loadPatternFile(path);
}); });
} }