diff options
author | rtk0c <[email protected]> | 2021-05-25 23:56:02 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2021-05-25 23:56:02 -0700 |
commit | a611b22650d1e40593db4fb1bce29d925e49e932 (patch) | |
tree | 1103179b6344c368e214852f16742129642c338b /core/src/UI | |
parent | bb2ab4bc5b2c9cc25ef1858ac538f2dc48af2d2c (diff) |
More work on workflow management UI
Diffstat (limited to 'core/src/UI')
-rw-r--r-- | core/src/UI/Localization.hpp | 1 | ||||
-rw-r--r-- | core/src/UI/UI_DatabaseView.cpp | 8 | ||||
-rw-r--r-- | core/src/UI/UI_Workflows.cpp | 191 |
3 files changed, 153 insertions, 47 deletions
diff --git a/core/src/UI/Localization.hpp b/core/src/UI/Localization.hpp index b421d24..c470fa7 100644 --- a/core/src/UI/Localization.hpp +++ b/core/src/UI/Localization.hpp @@ -19,6 +19,7 @@ public: BasicTranslation Add{ "Generic.Add"sv }; BasicTranslation Edit{ "Generic.Edit"sv }; BasicTranslation Delete{ "Generic.Delete"sv }; + BasicTranslation Rename{ "Generic.Rename"sv }; BasicTranslation Disconnect{ "Generic.Disconnect"sv }; BasicTranslation Close{ "Generic.Close"sv }; BasicTranslation DialogConfirm{ "Generic.Dialog.Confirm"sv }; diff --git a/core/src/UI/UI_DatabaseView.cpp b/core/src/UI/UI_DatabaseView.cpp index fb7fdfe..73ea657 100644 --- a/core/src/UI/UI_DatabaseView.cpp +++ b/core/src/UI/UI_DatabaseView.cpp @@ -468,7 +468,7 @@ private: case DeliveryDirection::WarehouseToCustomer: outgoingFlag = true; break; } - auto& stmt = mProject->GetTransactionsModel().GetDeliveries().FilterByTypeAndId; + auto& stmt = mProject->Database.GetDeliveries().FilterByTypeAndId; // clang-format off DEFER { stmt.reset(); }; // clang-format on @@ -482,7 +482,7 @@ private: int arrivalTimeCol = stmt.getColumnIndex("ArrivalTime"); while (stmt.executeStep()) { auto items = LoadItems( - mProject->GetTransactionsModel().GetDeliveries().GetItems, + mProject->Database.GetDeliveries().GetItems, stmt.getColumn(rowIdCol).getInt64()); auto summary = CreateItemsSummary(items); @@ -609,7 +609,7 @@ public: #pragma ide diagnostic ignored "HidingNonVirtualFunction" void OnProjectChanged(Project* newProject) { - auto& table = newProject->GetTransactionsModel().GetSales(); + auto& table = newProject->Database.GetSales(); Statements.GetRowCount = &table.GetRowCount; Statements.GetRows = &table.GetRows; Statements.GetItems = &table.GetItems; @@ -634,7 +634,7 @@ public: #pragma ide diagnostic ignored "HidingNonVirtualFunction" void OnProjectChanged(Project* newProject) { - auto& table = newProject->GetTransactionsModel().GetPurchases(); + auto& table = newProject->Database.GetPurchases(); Statements.GetRowCount = &table.GetRowCount; Statements.GetRows = &table.GetRows; Statements.GetItems = &table.GetItems; diff --git a/core/src/UI/UI_Workflows.cpp b/core/src/UI/UI_Workflows.cpp index a375ec0..feebe89 100644 --- a/core/src/UI/UI_Workflows.cpp +++ b/core/src/UI/UI_Workflows.cpp @@ -1,15 +1,18 @@ #include "UI.hpp" +#include "Model/Project.hpp" #include "Model/Workflow/Nodes/DocumentNodes.hpp" #include "Model/Workflow/Nodes/NumericNodes.hpp" #include "Model/Workflow/Nodes/TextNodes.hpp" #include "Model/Workflow/Nodes/UserInputNodes.hpp" #include "Model/Workflow/Workflow.hpp" #include "UI/Localization.hpp" +#include "UI/States.hpp" #include "Utils/Macros.hpp" #include <imgui.h> #include <imgui_node_editor.h> +#include <imgui_stdlib.h> #include <memory> #include <span> #include <vector> @@ -19,12 +22,12 @@ namespace ImNodes = ax::NodeEditor; namespace { enum class WorkflowCategory { - NumericCategory, - TextCategory, - DocumentsCategory, - UserInputCategory, - SystemInputCategory, - OutputCategory, + Numeric, + Text, + Documents, + UserInput, + SystemInput, + Output, }; class WorkflowDatabase @@ -42,12 +45,6 @@ public: private: std::vector<Candidate> mCandidates; -#define SUB_RANGE_ACCESS(Type, AccessorName, storage, begin, nextBegin) \ - std::span<Type> AccessorName() \ - { \ - return { &storage[begin], (size_t)(nextBegin - begin) }; \ - } - int mTextOffset; int mDocumentOffset; int mUserInputOffset; @@ -55,57 +52,64 @@ private: int mOutputOffset; public: - SUB_RANGE_ACCESS(Candidate, GetNumericNodes, mCandidates, 0, mTextOffset); - SUB_RANGE_ACCESS(Candidate, GetTextNodes, mCandidates, mTextOffset, mDocumentOffset); - SUB_RANGE_ACCESS(Candidate, GetDocumentNodes, mCandidates, mDocumentOffset, mUserInputOffset); - SUB_RANGE_ACCESS(Candidate, GetUserInputNodes, mCandidates, mUserInputOffset, mSystemInputNodes); - SUB_RANGE_ACCESS(Candidate, GetSystemInputNodes, mCandidates, mSystemInputNodes, mOutputOffset); - SUB_RANGE_ACCESS(Candidate, GetOutputNodes, mCandidates, mOutputOffset, mCandidates.size()); + // clang-format off + std::span<Candidate> GetNumericNodes() { return { &mCandidates[0], (size_t)(mTextOffset - 0) }; }; + std::span<Candidate> GetTextNodes() { return { &mCandidates[mTextOffset], (size_t)(mDocumentOffset - mTextOffset) }; }; + std::span<Candidate> GetDocumentNodes() { return { &mCandidates[mDocumentOffset], (size_t)(mUserInputOffset - mDocumentOffset) }; }; + std::span<Candidate> GetUserInputNodes() { return { &mCandidates[mUserInputOffset], (size_t)(mSystemInputNodes - mUserInputOffset) }; }; + std::span<Candidate> GetSystemInputNodes() { return { &mCandidates[mSystemInputNodes], (size_t)(mOutputOffset - mSystemInputNodes) }; }; + std::span<Candidate> GetOutputNodes() { return { &mCandidates[mOutputOffset], (size_t)(mCandidates.size() - mOutputOffset) }; }; + // clang-format on -#undef SUB_RANGE_ACCESS +public: + static WorkflowDatabase& GetInstance() + { + static WorkflowDatabase database; + return database; + } public: - void SetupCandidates() + WorkflowDatabase() { // Numeric nodes offset start at 0 mCandidates.push_back(Candidate{ .Constructor = []() -> std::unique_ptr<WorkflowNode> { return std::make_unique<NumericOperationNode>(NumericOperationNode::Addition); }, .Name = "Add", - .Category = WorkflowCategory::NumericCategory, + .Category = WorkflowCategory::Numeric, }); mCandidates.push_back(Candidate{ .Constructor = []() -> std::unique_ptr<WorkflowNode> { return std::make_unique<NumericOperationNode>(NumericOperationNode::Subtraction); }, .Name = "Subtract", - .Category = WorkflowCategory::NumericCategory, + .Category = WorkflowCategory::Numeric, }); mCandidates.push_back(Candidate{ .Constructor = []() -> std::unique_ptr<WorkflowNode> { return std::make_unique<NumericOperationNode>(NumericOperationNode::Multiplication); }, .Name = "Multiply", - .Category = WorkflowCategory::NumericCategory, + .Category = WorkflowCategory::Numeric, }); mCandidates.push_back(Candidate{ .Constructor = []() -> std::unique_ptr<WorkflowNode> { return std::make_unique<NumericOperationNode>(NumericOperationNode::Division); }, .Name = "Divide", - .Category = WorkflowCategory::NumericCategory, + .Category = WorkflowCategory::Numeric, }); mCandidates.push_back(Candidate{ .Constructor = []() -> std::unique_ptr<WorkflowNode> { return std::make_unique<NumericExpressionNode>(); }, .Name = "Evaluate expression", - .Category = WorkflowCategory::NumericCategory, + .Category = WorkflowCategory::Numeric, }); mTextOffset = mCandidates.size(); mCandidates.push_back(Candidate{ .Constructor = []() -> std::unique_ptr<WorkflowNode> { return std::make_unique<TextFormatterNode>(); }, .Name = "Fill template text", - .Category = WorkflowCategory::TextCategory, + .Category = WorkflowCategory::Text, }); mDocumentOffset = mCandidates.size(); mCandidates.push_back(Candidate{ .Constructor = []() -> std::unique_ptr<WorkflowNode> { return std::make_unique<DocumentTemplateExpansionNode>(); }, .Name = "Document template", - .Category = WorkflowCategory::DocumentsCategory, + .Category = WorkflowCategory::Documents, }); /* Inputs */ @@ -114,13 +118,13 @@ public: mCandidates.push_back(Candidate{ .Constructor = []() -> std::unique_ptr<WorkflowNode> { return std::make_unique<FormInputNode>(); }, .Name = "Input: form", - .Category = WorkflowCategory::UserInputCategory, + .Category = WorkflowCategory::UserInput, }); mCandidates.push_back(Candidate{ .Constructor = []() -> std::unique_ptr<WorkflowNode> { return std::make_unique<DatabaseRowsInputNode>(); }, .Name = "Input: database rows", - .Category = WorkflowCategory::UserInputCategory, + .Category = WorkflowCategory::UserInput, }); mSystemInputNodes = mCandidates.size(); @@ -134,19 +138,21 @@ public: class WorkflowUI { private: - Workflow* mWorkflow; + std::unique_ptr<Workflow> mWorkflow; + WorkflowDatabase* mWorkflowDb; + ImNodes::EditorContext* mContext; - WorkflowDatabase mWorkflowDatabase; ImNodes::NodeId mContextMenuNodeId = 0; ImNodes::PinId mContextMenuPinId = 0; ImNodes::LinkId mContextMenuLinkId = 0; public: - WorkflowUI() + WorkflowUI(std::unique_ptr<Workflow> workflow) + : mWorkflow{ std::move(workflow) } { + mWorkflowDb = &WorkflowDatabase::GetInstance(); mContext = ImNodes::CreateEditor(); - mWorkflowDatabase.SetupCandidates(); } ~WorkflowUI() @@ -333,12 +339,12 @@ public: } }; - DisplayCandidatesCategory("Numeric nodes", mWorkflowDatabase.GetNumericNodes()); - DisplayCandidatesCategory("Text nodes", mWorkflowDatabase.GetTextNodes()); - DisplayCandidatesCategory("Document nodes", mWorkflowDatabase.GetDocumentNodes()); - DisplayCandidatesCategory("User input nodes", mWorkflowDatabase.GetUserInputNodes()); - DisplayCandidatesCategory("System input nodes", mWorkflowDatabase.GetSystemInputNodes()); - DisplayCandidatesCategory("Output nodes", mWorkflowDatabase.GetOutputNodes()); + DisplayCandidatesCategory("Numeric nodes", mWorkflowDb->GetNumericNodes()); + DisplayCandidatesCategory("Text nodes", mWorkflowDb->GetTextNodes()); + DisplayCandidatesCategory("Document nodes", mWorkflowDb->GetDocumentNodes()); + DisplayCandidatesCategory("User input nodes", mWorkflowDb->GetUserInputNodes()); + DisplayCandidatesCategory("System input nodes", mWorkflowDb->GetSystemInputNodes()); + DisplayCandidatesCategory("Output nodes", mWorkflowDb->GetOutputNodes()); ImGui::EndPopup(); } @@ -352,31 +358,130 @@ public: ImNodes::End(); } }; + +struct DrawWorkflowList_State +{ + const WorkflowInfo* SelectedWorkflow = nullptr; +}; + +void DrawWorkflowList(DrawWorkflowList_State& state) +{ + auto& uis = UIState::GetInstance(); + auto& workflows = uis.CurrentProject->GetWorkflows(); + + // TODO sort the list + for (auto& info : workflows) { + if (ImGui::Selectable(info.Name.c_str(), state.SelectedWorkflow == &info)) { + state.SelectedWorkflow = &info; + } + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text("Path: %s", info.PathStringCache.c_str()); + ImGui::EndTooltip(); + } + } +} } // namespace void UI::WorkflowsTab() { auto ls = LocaleStrings::Instance.get(); + auto& uis = UIState::GetInstance(); + bool openedDummy = true; static std::unique_ptr<WorkflowUI> openWorkflow; + static DrawWorkflowList_State state; + // Toolbar item: close if (ImGui::Button(ls->Close.Get(), openWorkflow == nullptr)) { openWorkflow = nullptr; } + + // Toolbar item: open... ImGui::SameLine(); if (ImGui::Button(ls->OpenWorkflow.Get())) { ImGui::OpenPopup(ls->OpenWorkflowDialogTitle.Get()); } - if (ImGui::BeginPopupModal(ls->OpenWorkflowDialogTitle.Get())) { - // TODO + if (ImGui::BeginPopupModal(ls->OpenWorkflowDialogTitle.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) { + DrawWorkflowList(state); + + if (state.SelectedWorkflow) { + auto workflow = state.SelectedWorkflow->LoadFromDisk(); + openWorkflow = std::make_unique<WorkflowUI>(std::move(workflow)); + } + ImGui::EndPopup(); } + + // Toolbar item: manage... ImGui::SameLine(); if (ImGui::Button(ls->ManageWorkflows.Get())) { ImGui::OpenPopup(ls->ManageWorkflowsDialogTitle.Get()); } - if (ImGui::BeginPopupModal(ls->ManageWorkflowsDialogTitle.Get())) { - // TODO + if (ImGui::BeginPopupModal(ls->ManageWorkflowsDialogTitle.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) { + DrawWorkflowList(state); + + enum class NameSelectionError + { + None, + Duplicated, + Empty, + }; + static std::string newName; + static NameSelectionError newNameError; + if (ImGui::Button(ls->Rename.Get(), state.SelectedWorkflow == nullptr)) { + ImGui::OpenPopup("Rename workflow"); + newName.clear(); + } + if (ImGui::BeginPopupModal("Rename workflow")) { + if (ImGui::InputText("New name", &newName)) { + if (newName.empty()) { + newNameError = NameSelectionError::Empty; + } + + auto& workflows = uis.CurrentProject->GetWorkflows(); + if (workflows.find(newName) != workflows.end()) { + newNameError = NameSelectionError::Duplicated; + } + } + + if (ImGui::Button(ls->DialogConfirm.Get(), newName.empty())) { + auto& project = uis.CurrentProject; + project->RenameWorkflow(state.SelectedWorkflow->Name, newName); + state.SelectedWorkflow = &project->GetWorkflows()[newName]; + } + ImGui::SameLine(); + if (ImGui::Button(ls->DialogCancel.Get())) { + ImGui::CloseCurrentPopup(); + } + + switch (newNameError) { + case NameSelectionError::None: break; + case NameSelectionError::Duplicated: + ImGui::ErrorMessage("Duplicate workflow name"); + break; + case NameSelectionError::Empty: + ImGui::ErrorMessage("Workflow name cannot be empty"); + break; + } + + ImGui::EndPopup(); + } + + if (ImGui::Button(ls->Delete.Get(), state.SelectedWorkflow == nullptr)) { + ImGui::OpenPopup("Delete confirmation"); + } + if (ImGui::BeginPopupModal("Delete confirmation")) { + if (ImGui::Button(ls->DialogConfirm.Get())) { + uis.CurrentProject->RemoveWorkflow(state.SelectedWorkflow->Name); + } + ImGui::SameLine(); + if (ImGui::Button(ls->DialogCancel.Get())) { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + ImGui::EndPopup(); } |