From e75e26da92424528e190a2111acfcc49c657e894 Mon Sep 17 00:00:00 2001 From: rtk0c Date: Mon, 29 Mar 2021 19:14:07 -0700 Subject: Replace Dialog.hpp with portable-file-dialogs, more work on projects --- core/CMakeLists.txt | 32 +--------- core/locale/zh_CN.json | 2 + core/src/UI/Localization.hpp | 24 +++---- core/src/UI/UI_MainWindow.cpp | 63 ++++++++++-------- core/src/Utils/Dialog/Dialog.cpp | 18 ------ core/src/Utils/Dialog/Dialog.hpp | 52 --------------- core/src/Utils/Dialog/Dialog_linux.cpp | 83 ------------------------ core/src/Utils/Dialog/Dialog_macos.mm | 113 --------------------------------- core/src/Utils/Dialog/Dialog_win32.cpp | 64 ------------------- core/src/Utils/Dialog/fwd.hpp | 1 - core/src/Utils/fwd.hpp | 2 - 11 files changed, 56 insertions(+), 398 deletions(-) delete mode 100644 core/src/Utils/Dialog/Dialog.cpp delete mode 100644 core/src/Utils/Dialog/Dialog.hpp delete mode 100644 core/src/Utils/Dialog/Dialog_linux.cpp delete mode 100644 core/src/Utils/Dialog/Dialog_macos.mm delete mode 100644 core/src/Utils/Dialog/Dialog_win32.cpp delete mode 100644 core/src/Utils/Dialog/fwd.hpp (limited to 'core') diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index be089d8..d8e9db1 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -57,28 +57,6 @@ add_source_group(UTILS_MODULE_SOURCES src/Utils/String.cpp ) -# These files are compiled individually, hence no UNITY_GROUP property -# This is because the files here may contain non-c++ languages -set(UTILS_DIALOG_MODULE_SOURCES - src/Utils/Dialog/Dialog.cpp -) -if(APPLE) - find_library(COCOA_LIBRARY Cocoa) - list(APPEND UTILS_DIALOG_MODULE_SOURCES - src/Utils/Dialog/Dialog_macos.mm - ) -elseif(WIN32) - list(APPEND UTILS_DIALOG_MODULE_SOURCES - src/Utils/Dialog/Dialog_win32.cpp - ) -elseif(LINUX) - find_package(PkgConfig REQUIRED) - pkg_check_modules(GTK3 REQUIRED gtk+-3.0) - list(APPEND UTILS_DIALOG_MODULE_SOURCES - src/Utils/Dialog/Dialog_linux.cpp - ) -endif() - function(add_executable_variant TARGET_NAME) message("CpltCore: generating executable ${TARGET_NAME}") @@ -182,11 +160,7 @@ function(add_executable_variant TARGET_NAME) endif() endfunction() -if(BUILD_CORE_MAIN) - add_executable_variant(CpltCore_main) - target_compile_definitions(CpltCore_main PRIVATE DOCTEST_CONFIG_DISABLE=1) -endif() +add_executable_variant(CpltCore_main) +target_compile_definitions(CpltCore_main PRIVATE DOCTEST_CONFIG_DISABLE=1) -if(BUILD_CORE_TESTS) - add_executable_variant(CpltCore_test) -endif() +add_executable_variant(CpltCore_test) diff --git a/core/locale/zh_CN.json b/core/locale/zh_CN.json index 8550b1d..3b38f40 100644 --- a/core/locale/zh_CN.json +++ b/core/locale/zh_CN.json @@ -11,9 +11,11 @@ "Project.New.Cancel": "取消", "Project.New.Name": "项目名称", "Project.New.Path": "项目路径", + "Project.New.Path.DialogTitle": "项目路径", "Project.New.EmptyName": "项目名不能为空", "Project.New.InvalidPath": "无效路径", "Project.Open": "打开项目...", + "Project.Open.DialogTitle": "打开项目", "Project.Recents": "最近使用", "Project.Recents.Clear": "清空", "Project.Recents.NonePresent": "(暂无最近使用的项目)", diff --git a/core/src/UI/Localization.hpp b/core/src/UI/Localization.hpp index 7b401ef..e604165 100644 --- a/core/src/UI/Localization.hpp +++ b/core/src/UI/Localization.hpp @@ -19,19 +19,21 @@ public: BasicTranslation TabExport{ "MainWindow.Tab.Exports"sv }; BasicTranslation NewProject{ "Project.New"sv }; - BasicTranslation TitleNewProject{ "Project.New.DialogTitle"sv }; - BasicTranslation ActionNewProjectConfirm{ "Project.New.Confirm"sv }; - BasicTranslation ActionNewProjectCancel{ "Project.New.Cancel"sv }; - BasicTranslation HintNewProjectName{ "Project.New.Name"sv }; - BasicTranslation HintNewProjectPath{ "Project.New.Path"sv }; - BasicTranslation ErrorNewProjectEmptyName{ "Project.New.EmptyName"sv }; - BasicTranslation ErrorNewProjectInvalidPath{ "Project.New.InvalidPath"sv }; + BasicTranslation NewProjectTitle{ "Project.New.DialogTitle"sv }; + BasicTranslation ConfirmNewProject{ "Project.New.Confirm"sv }; + BasicTranslation CancelNewProject{ "Project.New.Cancel"sv }; + BasicTranslation NewProjectNameHint{ "Project.New.Name"sv }; + BasicTranslation NewProjectPathHint{ "Project.New.Path"sv }; + BasicTranslation NewProjectPathDialogTitle{ "Project.New.Path.DialogTitle"sv }; + BasicTranslation NewProjectEmptyNameError{ "Project.New.EmptyName"sv }; + BasicTranslation NewProjectInvalidPathError{ "Project.New.InvalidPath"sv }; BasicTranslation OpenProject{ "Project.Open"sv }; + BasicTranslation OpenProjectDialogTitle{ "Project.Open.DialogTitle"sv }; BasicTranslation RecentProjects{ "Project.Recents"sv }; - BasicTranslation ActionClearRecentProjects{ "Project.Recents.Clear"sv }; - BasicTranslation MessageNoRecentProjects{ "Project.Recents.NonePresent"sv }; - BasicTranslation TooltipOpenRecentProject{ "Project.Recents.Open.Tooltip"sv }; - BasicTranslation TooltipDeleteRecentProject{ "Project.Recents.Delete.Tooltip"sv }; + BasicTranslation ClearRecentProjects{ "Project.Recents.Clear"sv }; + BasicTranslation NoRecentProjectsMessage{ "Project.Recents.NonePresent"sv }; + BasicTranslation OpenRecentProjectTooltip{ "Project.Recents.Open.Tooltip"sv }; + BasicTranslation DeleteRecentProjectTooltip{ "Project.Recents.Delete.Tooltip"sv }; }; diff --git a/core/src/UI/UI_MainWindow.cpp b/core/src/UI/UI_MainWindow.cpp index 9b20550..de300e2 100644 --- a/core/src/UI/UI_MainWindow.cpp +++ b/core/src/UI/UI_MainWindow.cpp @@ -5,6 +5,8 @@ #include "UI/Localization.hpp" #include "UI/States.hpp" +#include + #include #include #include @@ -18,9 +20,9 @@ void LoadProjectAt(const std::filesystem::path& path) { auto& uis = UIState::GetInstance(); auto& gs = GlobalStates::GetInstance(); - if (uis.CurrentProject) { - uis.CloseCurrentProject(); - } + auto project = Project::Load(path); + auto uptr = std::unique_ptr(new Project(std::move(project))); + uis.SetCurrentProject(std::move(uptr)); } void ProjectTab_Normal() { @@ -36,45 +38,52 @@ void ProjectTab_NoProject() { static std::string dirName; static fs::path dirPath; static bool dirNameIsValid = false; + + auto TrySelectPath = [&](fs::path newPath) { + if (fs::exists(newPath)) { + dirNameIsValid = true; + dirPath = std::move(newPath); + } else { + dirNameIsValid = false; + } + }; + if (ImGui::Button(ls->NewProject.Get())) { auto vs = ImGui::GetMainViewport()->Size; // Viewport Size ImGui::SetNextWindowSize({ vs.x * 0.5f, vs.y * 0.5f }); ImGui::SetNextWindowPos({ vs.x / 2, vs.y / 2 }, ImGuiCond_Always, { 0.5f, 0.5f }); // Center window initially - ImGui::OpenPopup(ls->TitleNewProject.Get()); + ImGui::OpenPopup(ls->NewProjectTitle.Get()); } // Make it so that the modal dialog has a close button bool newProjectDialogDummyTrue = true; - if (ImGui::BeginPopupModal(ls->TitleNewProject.Get(), &newProjectDialogDummyTrue)) { - ImGui::InputTextWithHint("##ProjectName", ls->HintNewProjectName.Get(), &projectName); + if (ImGui::BeginPopupModal(ls->NewProjectTitle.Get(), &newProjectDialogDummyTrue)) { + ImGui::InputTextWithHint("##ProjectName", ls->NewProjectNameHint.Get(), &projectName); - if (ImGui::InputTextWithHint("##ProjectPath", ls->HintNewProjectPath.Get(), &dirName)) { + if (ImGui::InputTextWithHint("##ProjectPath", ls->NewProjectPathHint.Get(), &dirName)) { // Changed, validate value - fs::path newPath(dirName); - if (fs::exists(newPath)) { - dirNameIsValid = true; - dirPath = std::move(newPath); - } else { - dirNameIsValid = false; - } + TrySelectPath(fs::path(dirName)); } ImGui::SameLine(); if (ImGui::Button("...")) { - // TODO file dialog + auto selection = pfd::select_folder(ls->NewProjectPathDialogTitle.Get()).result(); + if (!selection.empty()) { + TrySelectPath(fs::path(selection)); + } } if (projectName.empty()) { ImGui::ErrorIcon(); ImGui::SameLine(); - ImGui::Text(ls->ErrorNewProjectEmptyName.Get()); + ImGui::Text(ls->NewProjectEmptyNameError.Get()); } if (!dirNameIsValid) { ImGui::ErrorIcon(); ImGui::SameLine(); - ImGui::Text(ls->ErrorNewProjectInvalidPath.Get()); + ImGui::Text(ls->NewProjectInvalidPathError.Get()); } ImGui::Spacing(); @@ -85,7 +94,7 @@ void ProjectTab_NoProject() { ImGui::PushItemFlag(ImGuiItemFlags_Disabled, false); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.5f * ImGui::GetStyle().Alpha); } - if (ImGui::Button(ls->ActionNewProjectConfirm.Get())) { + if (ImGui::Button(ls->ConfirmNewProject.Get())) { ImGui::CloseCurrentPopup(); auto project = Project::Create(std::move(projectName), dirPath); @@ -104,7 +113,7 @@ void ProjectTab_NoProject() { } ImGui::SameLine(); - if (ImGui::Button(ls->ActionNewProjectCancel.Get())) { + if (ImGui::Button(ls->CancelNewProject.Get())) { ImGui::CloseCurrentPopup(); } @@ -112,19 +121,23 @@ void ProjectTab_NoProject() { } if (ImGui::Button(ls->OpenProject.Get())) { - // TODO + auto selection = pfd::open_file(ls->OpenProjectDialogTitle.Get()).result(); + if (!selection.empty()) { + fs::path path(selection[0]); + LoadProjectAt(path); + } } ImGui::Separator(); ImGui::Text(ls->RecentProjects.Get()); ImGui::SameLine(); - if (ImGui::Button(ls->ActionClearRecentProjects.Get())) { + if (ImGui::Button(ls->ClearRecentProjects.Get())) { gs.ClearRecentProjects(); } auto& recentProjects = gs.GetRecentProjects(); if (recentProjects.empty()) { - ImGui::Text(ls->MessageNoRecentProjects.Get()); + ImGui::Text(ls->NoRecentProjectsMessage.Get()); } for (auto it = recentProjects.begin(); it != recentProjects.end(); ++it) { auto& [path, recent] = *it; @@ -135,7 +148,7 @@ void ProjectTab_NoProject() { LoadProjectAt(path); } if (ImGui::IsItemHovered()) { - ImGui::SetTooltip(ls->TooltipOpenRecentProject.Get()); + ImGui::SetTooltip(ls->OpenRecentProjectTooltip.Get()); } ImGui::SameLine(); @@ -143,7 +156,7 @@ void ProjectTab_NoProject() { gs.RemoveRecentProject(std::distance(recentProjects.begin(), it)); } if (ImGui::IsItemHovered()) { - ImGui::SetTooltip(ls->TooltipDeleteRecentProject.Get()); + ImGui::SetTooltip(ls->DeleteRecentProjectTooltip.Get()); } } } @@ -163,7 +176,7 @@ void UI::MainWindow() { ImGui::EndTabItem(); } - if (ImGui::BeginTabItem(ls->TabProject.Get(), nullptr, ImGuiTabItemFlags_SetSelected)) { + if (ImGui::BeginTabItem(ls->TabProject.Get(), nullptr)) { if (uis.CurrentProject) { ProjectTab_Normal(); } else { diff --git a/core/src/Utils/Dialog/Dialog.cpp b/core/src/Utils/Dialog/Dialog.cpp deleted file mode 100644 index c4459c0..0000000 --- a/core/src/Utils/Dialog/Dialog.cpp +++ /dev/null @@ -1,18 +0,0 @@ -// Adapted from https://github.com/aaronmjacobs/Boxer/blob/master/include/boxer/boxer.h -#include "Dialog.hpp" - -namespace Dialog { - -Selection Show(const char* message, const char* title, Style style) { - return Show(message, title, style, kDefaultButtons); -} - -Selection Show(const char* message, const char* title, Buttons buttons) { - return Show(message, title, kDefaultStyle, buttons); -} - -Selection Show(const char* message, const char* title) { - return Show(message, title, kDefaultStyle, kDefaultButtons); -} - -} // namespace Dialog diff --git a/core/src/Utils/Dialog/Dialog.hpp b/core/src/Utils/Dialog/Dialog.hpp deleted file mode 100644 index e8989e3..0000000 --- a/core/src/Utils/Dialog/Dialog.hpp +++ /dev/null @@ -1,52 +0,0 @@ -// Adapted from https://github.com/aaronmjacobs/Boxer/blob/master/include/boxer/boxer.h -#pragma once - -namespace Dialog { - -/// Options for styles to apply to a message box. -enum class Style { - Info, - Warning, - Error, - Question, -}; - -/// Options for buttons to provide on a message box. -enum class Buttons { - OK, - OKCancel, - YesNo, - Quit, -}; - -/// Possible responses from a message box. 'None' signifies that no option was chosen, and 'Error' signifies that an -/// error was encountered while creating the message box. -enum class Selection { - OK, - Cancel, - Yes, - No, - Quit, - None, - Error, -}; - -/// The default style to apply to a message box. -constexpr Style kDefaultStyle = Style::Info; - -/// The default buttons to provide on a message box. -constexpr Buttons kDefaultButtons = Buttons::OK; - -/// Blocking call to create a modal message box with the given message, title, style, and buttons. -Selection Show(const char* message, const char* title, Style style, Buttons buttons); - -/// Convenience function to call show() with the default buttons. -Selection Show(const char* message, const char* title, Style style); - -/// Convenience function to call show() with the default style. -Selection Show(const char* message, const char* title, Buttons buttons); - -/// Convenience function to call show() with the default style and buttons. -Selection Show(const char* message, const char* title); - -} // namespace Dialog diff --git a/core/src/Utils/Dialog/Dialog_linux.cpp b/core/src/Utils/Dialog/Dialog_linux.cpp deleted file mode 100644 index 11c3cee..0000000 --- a/core/src/Utils/Dialog/Dialog_linux.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Adapted from https://github.com/aaronmjacobs/Boxer/blob/master/src/boxer_linux.cpp -#include "Dialog.hpp" - -#include - -namespace Dialog { -namespace { - - GtkMessageType GetMessageType(Style style) { - switch (style) { - case Style::Info: - return GTK_MESSAGE_INFO; - case Style::Warning: - return GTK_MESSAGE_WARNING; - case Style::Error: - return GTK_MESSAGE_ERROR; - case Style::Question: - return GTK_MESSAGE_QUESTION; - default: - return GTK_MESSAGE_INFO; - } - } - - GtkButtonsType GetButtonsType(Buttons buttons) { - switch (buttons) { - case Buttons::OK: - return GTK_BUTTONS_OK; - case Buttons::OKCancel: - return GTK_BUTTONS_OK_CANCEL; - case Buttons::YesNo: - return GTK_BUTTONS_YES_NO; - case Buttons::Quit: - return GTK_BUTTONS_CLOSE; - default: - return GTK_BUTTONS_OK; - } - } - - Selection getSelection(gint response) { - switch (response) { - case GTK_RESPONSE_OK: - return Selection::OK; - case GTK_RESPONSE_CANCEL: - return Selection::Cancel; - case GTK_RESPONSE_YES: - return Selection::Yes; - case GTK_RESPONSE_NO: - return Selection::No; - case GTK_RESPONSE_CLOSE: - return Selection::Quit; - default: - return Selection::None; - } - } - -} // namespace - -Selection Show(const char* message, const char* title, Style style, Buttons buttons) { - if (!gtk_init_check(0, nullptr)) { - return Selection::Error; - } - - // Create a parent window to stop gtk_dialog_run from complaining - GtkWidget* parent = gtk_window_new(GTK_WINDOW_TOPLEVEL); - - GtkWidget* dialog = gtk_message_dialog_new(GTK_WINDOW(parent), - GTK_DIALOG_MODAL, - GetMessageType(style), - GetButtonsType(buttons), - "%s", - message); - gtk_window_set_title(GTK_WINDOW(dialog), title); - Selection selection = getSelection(gtk_dialog_run(GTK_DIALOG(dialog))); - - gtk_widget_destroy(GTK_WIDGET(dialog)); - gtk_widget_destroy(GTK_WIDGET(parent)); - while (g_main_context_iteration(nullptr, false)) { - // Do nothing - } - - return selection; -} -} // namespace Dialog diff --git a/core/src/Utils/Dialog/Dialog_macos.mm b/core/src/Utils/Dialog/Dialog_macos.mm deleted file mode 100644 index c0164a0..0000000 --- a/core/src/Utils/Dialog/Dialog_macos.mm +++ /dev/null @@ -1,113 +0,0 @@ -// Adapted from https://github.com/aaronmjacobs/Boxer/blob/master/src/boxer_osx.mm -#include "Dialog.hpp" - -#import - -namespace Dialog { -namespace { - - NSString* const kOkStr = @"OK"; - NSString* const kCancelStr = @"Cancel"; - NSString* const kYesStr = @"Yes"; - NSString* const kNoStr = @"No"; - NSString* const kQuitStr = @"Quit"; - - NSAlertStyle GetAlertStyle(Style style) { -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12 - switch (style) { - case Style::Info: - return NSAlertStyleInformational; - case Style::Warning: - return NSAlertStyleWarning; - case Style::Error: - return NSAlertStyleCritical; - case Style::Question: - return NSAlertStyleWarning; - default: - return NSAlertStyleInformational; - } -#else - switch (style) { - case Style::Info: - return NSInformationalAlertStyle; - case Style::Warning: - return NSWarningAlertStyle; - case Style::Error: - return NSCriticalAlertStyle; - case Style::Question: - return NSWarningAlertStyle; - default: - return NSInformationalAlertStyle; - } -#endif - } - - void SetButtons(NSAlert* alert, Buttons buttons) { - switch (buttons) { - case Buttons::OK: - [alert addButtonWithTitle:kOkStr]; - break; - case Buttons::OKCancel: - [alert addButtonWithTitle:kOkStr]; - [alert addButtonWithTitle:kCancelStr]; - break; - case Buttons::YesNo: - [alert addButtonWithTitle:kYesStr]; - [alert addButtonWithTitle:kNoStr]; - break; - case Buttons::Quit: - [alert addButtonWithTitle:kQuitStr]; - break; - default: - [alert addButtonWithTitle:kOkStr]; - } - } - - Selection GetSelection(int index, Buttons buttons) { - switch (buttons) { - case Buttons::OK: - return index == NSAlertFirstButtonReturn ? Selection::OK : Selection::None; - case Buttons::OKCancel: - if (index == NSAlertFirstButtonReturn) { - return Selection::OK; - } else if (index == NSAlertSecondButtonReturn) { - return Selection::Cancel; - } else { - return Selection::None; - } - case Buttons::YesNo: - if (index == NSAlertFirstButtonReturn) { - return Selection::Yes; - } else if (index == NSAlertSecondButtonReturn) { - return Selection::No; - } else { - return Selection::None; - } - case Buttons::Quit: - return index == NSAlertFirstButtonReturn ? Selection::Quit : Selection::None; - default: - return Selection::None; - } - } - -} // namespace - -Selection show(const char* message, const char* title, Style style, Buttons buttons) { - NSAlert* alert = [[NSAlert alloc] init]; - - [alert setMessageText:[NSString stringWithCString:title encoding:[NSString defaultCStringEncoding]]]; - [alert setInformativeText:[NSString stringWithCString:message encoding:[NSString defaultCStringEncoding]]]; - - [alert setAlertStyle:GetAlertStyle(style)]; - SetButtons(alert, buttons); - - // Force the alert to appear on top of any other windows - [[alert window] setLevel:NSModalPanelWindowLevel]; - - Selection selection = GetSelection([alert runModal], buttons); - [alert release]; - - return selection; -} - -} // namespace Dialog diff --git a/core/src/Utils/Dialog/Dialog_win32.cpp b/core/src/Utils/Dialog/Dialog_win32.cpp deleted file mode 100644 index b82f382..0000000 --- a/core/src/Utils/Dialog/Dialog_win32.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// Adapted from https://github.com/aaronmjacobs/Boxer/blob/master/src/boxer_win.cpp -#include "Dialog.hpp" - -#define WIN32_LEAN_AND_MEAN -#include - -namespace Dialog { -namespace { - - UINT GetIcon(Style style) { - switch (style) { - case Style::Info: - return MB_ICONINFORMATION; - case Style::Warning: - return MB_ICONWARNING; - case Style::Error: - return MB_ICONERROR; - case Style::Question: - return MB_ICONQUESTION; - default: - return MB_ICONINFORMATION; - } - } - - UINT GetButtons(Buttons buttons) { - switch (buttons) { - case Buttons::OK: - case Buttons::Quit: // There is no 'Quit' button on Windows :( - return MB_OK; - case Buttons::OKCancel: - return MB_OKCANCEL; - case Buttons::YesNo: - return MB_YESNO; - default: - return MB_OK; - } - } - - Selection GetSelection(int response, Buttons buttons) { - switch (response) { - case IDOK: - return buttons == Buttons::Quit ? Selection::Quit : Selection::OK; - case IDCANCEL: - return Selection::Cancel; - case IDYES: - return Selection::Yes; - case IDNO: - return Selection::No; - default: - return Selection::None; - } - } - -} // namespace - -Selection Show(const char* message, const char* title, Style style, Buttons buttons) { - UINT flags = MB_TASKMODAL; - - flags |= GetIcon(style); - flags |= GetButtons(buttons); - - return GetSelection(MessageBox(nullptr, message, title, flags), buttons); -} -} // namespace Dialog diff --git a/core/src/Utils/Dialog/fwd.hpp b/core/src/Utils/Dialog/fwd.hpp deleted file mode 100644 index 50e9667..0000000 --- a/core/src/Utils/Dialog/fwd.hpp +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/core/src/Utils/fwd.hpp b/core/src/Utils/fwd.hpp index 1949ca2..f33cb14 100644 --- a/core/src/Utils/fwd.hpp +++ b/core/src/Utils/fwd.hpp @@ -1,7 +1,5 @@ #pragma once -#include "Dialog/fwd.hpp" - // Sigslot.hpp class SignalStub; template -- cgit v1.2.3-70-g09d2