diff options
Diffstat (limited to 'core/src/UI')
-rw-r--r-- | core/src/UI/Localization.hpp | 20 | ||||
-rw-r--r-- | core/src/UI/States.cpp | 15 | ||||
-rw-r--r-- | core/src/UI/States.hpp | 6 | ||||
-rw-r--r-- | core/src/UI/UI.hpp | 7 | ||||
-rw-r--r-- | core/src/UI/UI_MainWindow.cpp | 129 | ||||
-rw-r--r-- | core/src/UI/UI_Utils.cpp | 16 |
6 files changed, 183 insertions, 10 deletions
diff --git a/core/src/UI/Localization.hpp b/core/src/UI/Localization.hpp index 648dd6d..7b401ef 100644 --- a/core/src/UI/Localization.hpp +++ b/core/src/UI/Localization.hpp @@ -18,8 +18,20 @@ public: BasicTranslation TabItems{ "MainWindow.Tab.Items"sv }; BasicTranslation TabExport{ "MainWindow.Tab.Exports"sv }; - BasicTranslation NewProject{ "Project.NewProject"sv }; - BasicTranslation OpenProject{ "Project.OpenProject"sv }; - BasicTranslation Recents{ "Project.Recents"sv }; - BasicTranslation ClearRecents{ "Project.ClearRecents"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 OpenProject{ "Project.Open"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 }; }; diff --git a/core/src/UI/States.cpp b/core/src/UI/States.cpp index efae152..07bbcf7 100644 --- a/core/src/UI/States.cpp +++ b/core/src/UI/States.cpp @@ -2,6 +2,9 @@ #include "Model/Project.hpp" +#include <memory> +#include <utility> + static std::unique_ptr<UIState> uiStateInstance; void UIState::Init() { @@ -11,3 +14,15 @@ void UIState::Init() { UIState& UIState::GetInstance() { return *uiStateInstance; } + +void UIState::SetCurrentProject(std::unique_ptr<Project> project) { + CloseCurrentProject(); + CurrentProject = std::move(project); +} + +void UIState::CloseCurrentProject() { + if (CurrentProject) { + // TODO save stuff + CurrentProject = nullptr; + } +} diff --git a/core/src/UI/States.hpp b/core/src/UI/States.hpp index d1c1faf..cbb556f 100644 --- a/core/src/UI/States.hpp +++ b/core/src/UI/States.hpp @@ -4,6 +4,8 @@ #include <memory> +/// Minimal state shared by all UI components, such as database, items, export, etc. +/// Note that global components (settings) is not supposed to access these. class UIState { public: static void Init(); @@ -11,4 +13,8 @@ public: public: std::unique_ptr<Project> CurrentProject; + +public: + void SetCurrentProject(std::unique_ptr<Project> project); + void CloseCurrentProject(); }; diff --git a/core/src/UI/UI.hpp b/core/src/UI/UI.hpp index 08f5771..b0c3aaa 100644 --- a/core/src/UI/UI.hpp +++ b/core/src/UI/UI.hpp @@ -1,5 +1,12 @@ #pragma once +namespace ImGui { + +void ErrorIcon(); +void WarningIcon(); + +} // namespace ImGui + namespace UI { void MainWindow(); diff --git a/core/src/UI/UI_MainWindow.cpp b/core/src/UI/UI_MainWindow.cpp index 0c8e7b9..9b20550 100644 --- a/core/src/UI/UI_MainWindow.cpp +++ b/core/src/UI/UI_MainWindow.cpp @@ -1,34 +1,151 @@ #include "UI.hpp" +#include "Model/GlobalStates.hpp" #include "Model/Project.hpp" #include "UI/Localization.hpp" #include "UI/States.hpp" +#include <IconsFontAwesome.h> #include <imgui.h> +#include <imgui_internal.h> +#include <imgui_stdlib.h> +#include <filesystem> + +namespace fs = std::filesystem; namespace { +void LoadProjectAt(const std::filesystem::path& path) { + auto& uis = UIState::GetInstance(); + auto& gs = GlobalStates::GetInstance(); + + if (uis.CurrentProject) { + uis.CloseCurrentProject(); + } +} + void ProjectTab_Normal() { // TODO } void ProjectTab_NoProject() { auto ls = LocaleStrings::Instance.get(); + auto& gs = GlobalStates::GetInstance(); + auto& uis = UIState::GetInstance(); + static std::string projectName; + static std::string dirName; + static fs::path dirPath; + static bool dirNameIsValid = false; if (ImGui::Button(ls->NewProject.Get())) { - // TODO + 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()); } + + // 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::InputTextWithHint("##ProjectPath", ls->HintNewProjectPath.Get(), &dirName)) { + // Changed, validate value + fs::path newPath(dirName); + if (fs::exists(newPath)) { + dirNameIsValid = true; + dirPath = std::move(newPath); + } else { + dirNameIsValid = false; + } + } + ImGui::SameLine(); + if (ImGui::Button("...")) { + // TODO file dialog + } + + if (projectName.empty()) { + ImGui::ErrorIcon(); + + ImGui::SameLine(); + ImGui::Text(ls->ErrorNewProjectEmptyName.Get()); + } + + if (!dirNameIsValid) { + ImGui::ErrorIcon(); + + ImGui::SameLine(); + ImGui::Text(ls->ErrorNewProjectInvalidPath.Get()); + } + + ImGui::Spacing(); + + bool formValid = dirNameIsValid && !projectName.empty(); + + if (!formValid) { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, false); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.5f * ImGui::GetStyle().Alpha); + } + if (ImGui::Button(ls->ActionNewProjectConfirm.Get())) { + ImGui::CloseCurrentPopup(); + + auto project = Project::Create(std::move(projectName), dirPath); + auto uptr = std::unique_ptr<Project>(new Project(std::move(project))); + uis.SetCurrentProject(std::move(uptr)); + + // Dialog just got closed, reset states + projectName = ""; + dirName = ""; + dirPath = fs::path{}; + dirNameIsValid = false; + } + if (!formValid) { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + } + + ImGui::SameLine(); + if (ImGui::Button(ls->ActionNewProjectCancel.Get())) { + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } + if (ImGui::Button(ls->OpenProject.Get())) { // TODO } ImGui::Separator(); - ImGui::Text(ls->Recents.Get()); + ImGui::Text(ls->RecentProjects.Get()); ImGui::SameLine(); - if (ImGui::Button(ls->ClearRecents.Get())) { - // TODO + if (ImGui::Button(ls->ActionClearRecentProjects.Get())) { + gs.ClearRecentProjects(); } - // TODO + auto& recentProjects = gs.GetRecentProjects(); + if (recentProjects.empty()) { + ImGui::Text(ls->MessageNoRecentProjects.Get()); + } + for (auto it = recentProjects.begin(); it != recentProjects.end(); ++it) { + auto& [path, recent] = *it; + ImGui::Text(recent.c_str()); + + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_EDIT)) { + LoadProjectAt(path); + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip(ls->TooltipOpenRecentProject.Get()); + } + + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_TRASH)) { + gs.RemoveRecentProject(std::distance(recentProjects.begin(), it)); + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip(ls->TooltipDeleteRecentProject.Get()); + } + } } } // namespace @@ -46,7 +163,7 @@ void UI::MainWindow() { ImGui::EndTabItem(); } - if (ImGui::BeginTabItem(ls->TabProject.Get())) { + if (ImGui::BeginTabItem(ls->TabProject.Get(), nullptr, ImGuiTabItemFlags_SetSelected)) { if (uis.CurrentProject) { ProjectTab_Normal(); } else { diff --git a/core/src/UI/UI_Utils.cpp b/core/src/UI/UI_Utils.cpp new file mode 100644 index 0000000..61a62f0 --- /dev/null +++ b/core/src/UI/UI_Utils.cpp @@ -0,0 +1,16 @@ +#include "UI.hpp" + +#include <IconsFontAwesome.h> +#include <imgui.h> + +void ImGui::ErrorIcon() { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4{ 237 / 255.0f, 67 / 255.0f, 55 / 255.0f, 1.0f }); // #ED4337 + ImGui::Text(ICON_FA_EXCLAMATION_CIRCLE); + ImGui::PopStyleColor(); +} + +void ImGui::WarningIcon() { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4{ 255 / 255.0f, 184 / 255.0f, 24 / 255.0f, 1.0f }); // #FFB818 + ImGui::Text(ICON_FA_EXCLAMATION_TRIANGLE); + ImGui::PopStyleColor(); +} |