aboutsummaryrefslogtreecommitdiff
path: root/core/src/UI
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/UI')
-rw-r--r--core/src/UI/Localization.hpp20
-rw-r--r--core/src/UI/States.cpp15
-rw-r--r--core/src/UI/States.hpp6
-rw-r--r--core/src/UI/UI.hpp7
-rw-r--r--core/src/UI/UI_MainWindow.cpp129
-rw-r--r--core/src/UI/UI_Utils.cpp16
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();
+}