aboutsummaryrefslogtreecommitdiff
path: root/core/src/UI/UI_Templates.cpp
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2021-05-30 23:00:41 -0700
committerrtk0c <[email protected]>2021-05-30 23:00:41 -0700
commitc90f78df080a9891930ee346b0ad87498ba5b697 (patch)
treec4f4c475086337e25cbb985625423591c47310e1 /core/src/UI/UI_Templates.cpp
parent088da97531935a61870ecada10f06b9b9a8255d1 (diff)
Initial work on templates UI
Diffstat (limited to 'core/src/UI/UI_Templates.cpp')
-rw-r--r--core/src/UI/UI_Templates.cpp289
1 files changed, 289 insertions, 0 deletions
diff --git a/core/src/UI/UI_Templates.cpp b/core/src/UI/UI_Templates.cpp
new file mode 100644
index 0000000..628f3f7
--- /dev/null
+++ b/core/src/UI/UI_Templates.cpp
@@ -0,0 +1,289 @@
+#include "UI.hpp"
+
+#include "Model/Project.hpp"
+#include "Model/Template/TableTemplate.hpp"
+#include "Model/Template/Template.hpp"
+#include "UI/Localization.hpp"
+#include "UI/States.hpp"
+
+#include <imgui.h>
+#include <imgui_extra_math.h>
+#include <imgui_stdlib.h>
+#include <fstream>
+#include <iostream>
+#include <utility>
+
+namespace {
+class TemplateUI
+{
+public:
+ virtual ~TemplateUI() = default;
+ virtual void Draw() = 0;
+};
+
+class TableTemplateUI : public TemplateUI
+{
+private:
+ std::unique_ptr<TableTemplate> mTable;
+
+public:
+ TableTemplateUI(std::unique_ptr<TableTemplate> table)
+ : mTable{ std::move(table) }
+ {
+ }
+
+ virtual void Draw() override
+ {
+ ImGui::Columns(2);
+
+ DrawInspector();
+ ImGui::NextColumn();
+
+ DrawTable();
+ ImGui::NextColumn();
+
+ ImGui::Columns(1);
+ }
+
+private:
+ void DrawInspector()
+ {
+ }
+
+ void DrawTable()
+ {
+ constexpr int kCellSpacing = 20;
+
+ int colCount = mTable->GetTableWidth();
+ int rowCount = mTable->GetTableHeight();
+ float x = 0.0f;
+ float y = 0.0f;
+ for (int rowIdx = 0; rowIdx < rowCount; ++rowIdx) {
+ int rowHeight = mTable->GetRowHeight(rowIdx);
+
+ for (int colIdx = 0; colIdx < colCount; ++colIdx) {
+ int colWidth = mTable->GetColumnWidth(colIdx);
+
+ ImRect rect{
+ ImVec2(x, y),
+ ImVec2(colWidth, rowHeight),
+ };
+
+ // TODO
+
+ x += colWidth;
+ x += kCellSpacing;
+ }
+
+ y += rowHeight;
+ y += kCellSpacing;
+ }
+ }
+};
+
+struct DrawTemplateList_State
+{
+ // Internal data
+
+ // Items that are intended for user usage
+ const TemplateInfo* SelectedTemplate = nullptr;
+};
+
+void DrawTemplateList(DrawTemplateList_State& state)
+{
+ auto& uis = UIState::GetInstance();
+ auto& templates = uis.CurrentProject->GetTemplates();
+
+ for (auto& info : templates) {
+ if (ImGui::Selectable(info.Name.c_str(), state.SelectedTemplate == &info)) {
+ state.SelectedTemplate = &info;
+ }
+ if (ImGui::IsItemHovered()) {
+ ImGui::BeginTooltip();
+ ImGui::Text("Path: %s", info.PathStringCache.c_str());
+ ImGui::EndTooltip();
+ }
+ }
+}
+} // namespace
+
+void UI::TemplatesTab()
+{
+ auto ls = LocaleStrings::Instance.get();
+ auto& uis = UIState::GetInstance();
+
+ bool openedDummy = true;
+ static std::unique_ptr<TemplateUI> openTemplate;
+ static DrawTemplateList_State state;
+
+ // Toolbar item: close
+ if (ImGui::Button(ls->Close.Get(), openTemplate == nullptr)) {
+ openTemplate = nullptr;
+ }
+
+ // Toolbar item: open...
+ ImGui::SameLine();
+ if (ImGui::Button("Open...")) {
+ ImGui::OpenPopup("Open template");
+ }
+ if (ImGui::BeginPopupModal("Open template", &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
+ DrawTemplateList(state);
+
+ if (state.SelectedTemplate) {
+ // TODO
+ }
+
+ ImGui::EndPopup();
+ }
+
+ // Toolbar item: manage...
+ ImGui::SameLine();
+ if (ImGui::Button("Manage...")) {
+ ImGui::OpenPopup("Manage templates");
+ }
+ if (ImGui::BeginPopupModal("Manage templates", &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) {
+ DrawTemplateList(state);
+
+ enum class NameSelectionError
+ {
+ None,
+ Duplicated,
+ Empty,
+ };
+
+ static std::string newName;
+ static NameSelectionError newNameError;
+ auto ValidateNewName = [&]() -> void {
+ if (newName.empty()) {
+ newNameError = NameSelectionError::Empty;
+ }
+
+ auto& templates = uis.CurrentProject->GetTemplates();
+ if (templates.find(newName) != templates.end()) {
+ newNameError = NameSelectionError::Duplicated;
+ }
+ };
+ auto ShowNewNameErrors = [&]() -> void {
+ switch (newNameError) {
+ case NameSelectionError::None: break;
+ case NameSelectionError::Duplicated:
+ ImGui::ErrorMessage("Duplicate template name");
+ break;
+ case NameSelectionError::Empty:
+ ImGui::ErrorMessage("Template name cannot be empty");
+ break;
+ }
+ };
+
+ static Template::Kind newKind = Template::InvalidKind;
+ auto ShowNewKindErrors = [&]() -> void {
+ if (newKind == Template::InvalidKind) {
+ ImGui::ErrorMessage("Must select a valid template type");
+ }
+ };
+
+ auto IsInputValid = [&]() -> bool {
+ return newNameError == NameSelectionError::None && newKind != Template::InvalidKind;
+ };
+
+ if (ImGui::Button(ls->Add.Get())) {
+ ImGui::OpenPopup("Create template");
+ }
+ if (ImGui::BeginPopupModal("Create template")) {
+ if (ImGui::InputText("Name", &newName)) {
+ ValidateNewName();
+ }
+
+ if (ImGui::BeginCombo("Type", Template::FormatKind(newKind))) {
+ for (int i = 0; i < Template::KindCount; ++i) {
+ auto kind = static_cast<Template::Kind>(i);
+ if (ImGui::Selectable(Template::FormatKind(kind), newKind == kind)) {
+ newKind = kind;
+ }
+ }
+ ImGui::EndCombo();
+ }
+
+ if (ImGui::Button(ls->DialogConfirm.Get(), IsInputValid())) {
+ auto& project = *uis.CurrentProject;
+
+ auto& info = *project.InsertTemplate(
+ newName,
+ TemplateInfo{
+ .Path = project.GetTemplatePath(newName),
+ .Name = newName, // Don't std::move here because evaluation order of `newName` (as parameter of InsertTemplate()) and this is unspecified
+ .Kind = newKind,
+ });
+
+ auto tmpl = Template::CreateByKind(newKind);
+
+ std::ofstream ofs(info.Path);
+ if (ofs) {
+ tmpl->WriteTo(ofs);
+ } else {
+ // Writing to disk here isn't necessary for downstream operations to function successfully;
+ // if the user makes any changes and don't save, those changes will not persist anyways
+ // if the user doesn't make any changes, it doesn't matter that the empty template file isn't created yet
+ }
+
+ openTemplate = std::make_unique<TableTemplateUI>(std::move(tmpl));
+ }
+ ImGui::SameLine();
+ if (ImGui::Button(ls->DialogCancel.Get())) {
+ ImGui::CloseCurrentPopup();
+ }
+
+ ShowNewNameErrors();
+ ShowNewKindErrors();
+
+ ImGui::EndPopup();
+ }
+
+ if (ImGui::Button(ls->Rename.Get(), state.SelectedTemplate == nullptr)) {
+ ImGui::OpenPopup("Rename template");
+ newName.clear();
+ }
+ if (ImGui::BeginPopupModal("Rename template")) {
+ if (ImGui::InputText("New name", &newName)) {
+ ValidateNewName();
+ }
+
+ if (ImGui::Button(ls->DialogConfirm.Get(), IsInputValid())) {
+ auto& project = *uis.CurrentProject;
+
+ project.RenameTemplate(
+ state.SelectedTemplate->Name,
+ newName);
+
+ // We mutated the map, the pointer may be invalid now
+ state.SelectedTemplate = &project.GetTemplates().at(newName);
+ }
+ ImGui::SameLine();
+ if (ImGui::Button(ls->DialogCancel.Get())) {
+ ImGui::CloseCurrentPopup();
+ }
+
+ ShowNewNameErrors();
+
+ ImGui::EndPopup();
+ }
+
+ if (ImGui::Button(ls->Delete.Get(), state.SelectedTemplate == nullptr)) {
+ ImGui::OpenPopup("Delete confirmation");
+ }
+ if (ImGui::BeginPopupModal("Delete confirmation")) {
+ assert(state.SelectedTemplate != nullptr);
+
+ if (ImGui::Button(ls->DialogConfirm.Get())) {
+ uis.CurrentProject->RemoveTemplate(state.SelectedTemplate->Name);
+ }
+ ImGui::SameLine();
+ if (ImGui::Button(ls->DialogCancel.Get())) {
+ ImGui::CloseCurrentPopup();
+ }
+ ImGui::EndPopup();
+ }
+
+ ImGui::EndPopup();
+ }
+}