From 782e95613da7fb2eb7a2fe9c3c9fbb5b6f756b09 Mon Sep 17 00:00:00 2001 From: rtk0c Date: Wed, 30 Jun 2021 11:42:13 -0700 Subject: Fix table parameter map is not updated with the UI --- core/src/Locale/zh_CN.h | 4 + core/src/Model/Template/TableTemplate.cpp | 42 ++++++- core/src/Model/Template/TableTemplate.hpp | 12 ++ core/src/UI/UI_Templates.cpp | 194 +++++++++++++++++++++++------- 4 files changed, 202 insertions(+), 50 deletions(-) diff --git a/core/src/Locale/zh_CN.h b/core/src/Locale/zh_CN.h index f65744d..632c229 100644 --- a/core/src/Locale/zh_CN.h +++ b/core/src/Locale/zh_CN.h @@ -126,6 +126,10 @@ #define L10N_TABLE "表格" #define L10N_TABLE_CONFIGURE_PROPERTIES "编辑表格属性..." #define L10N_TABLE_PROPERTIES "表格属性" +#define L10N_TABLE_DO_RESIZE "调整表格大小..." +#define L10N_TABLE_RESIZE "调整表格大小" +#define L10N_TABLE_WIDTH "宽度" +#define L10N_TABLE_HEIGHT "长度" #define L10N_TABLE_SINGLE_PARAMS "参数" #define L10N_TABLE_ARRAY_GROUPS "列表参数组" #define L10N_TABLE_CELL "单元格" diff --git a/core/src/Model/Template/TableTemplate.cpp b/core/src/Model/Template/TableTemplate.cpp index 6c3d86b..ce1d6a5 100644 --- a/core/src/Model/Template/TableTemplate.cpp +++ b/core/src/Model/Template/TableTemplate.cpp @@ -39,6 +39,29 @@ Vec2i TableArrayGroup::FindCell(std::string_view name) { } +template +static bool UpdateElementName(TMap& map, std::string_view oldName, std::string_view newName) +{ + auto iter = map.find(oldName); + if (iter == map.end()) { + return false; + } + + auto elm = iter.value(); + auto [DISCARD, inserted] = map.insert(newName, elm); + if (!inserted) { + return false; + } + + map.erase(iter); + return true; +} + +bool TableArrayGroup::UpdateCellName(std::string_view oldName, std::string_view newName) +{ + return ::UpdateElementName(mName2Cell, oldName, newName); +} + TableInstantiationParameters::TableInstantiationParameters(const TableTemplate& table) : mTable{ &table } { @@ -164,12 +187,11 @@ void TableTemplate::SetCellType(Vec2i pos, TableCell::CellType type) case TableCell::ArrayParametricCell: { auto& ag = mArrayGroups[cell.DataId]; - if (cell.Location.x == ag.LeftCell) { + if (pos.x == ag.LeftCell) { ag.LeftCell++; - } else if (cell.Location.x == ag.RightCell) { + } else if (pos.x == ag.RightCell) { ag.RightCell--; } else { - } } break; } @@ -180,7 +202,7 @@ void TableTemplate::SetCellType(Vec2i pos, TableCell::CellType type) case TableCell::SingularParametricCell: { int idx = pos.y * GetTableWidth() + pos.x; - auto [DISCARD, inserted] = mName2Parameters.emplace(cell.Content, idx); + auto [DISCARD, inserted] = mName2Parameters.insert(cell.Content, idx); // Duplicate name if (!inserted) { @@ -201,6 +223,11 @@ void TableTemplate::SetCellType(Vec2i pos, TableCell::CellType type) cell.Type = type; } +bool TableTemplate::UpdateParameterName(std::string_view oldName, std::string_view newName) +{ + return ::UpdateElementName(mName2Parameters, oldName, newName); +} + int TableTemplate::GetArrayGroupCount() const { return mArrayGroups.size(); @@ -239,7 +266,7 @@ TableArrayGroup* TableTemplate::AddArrayGroup(std::string_view name, int row, in std::swap(left, right); } - auto [DISCARD, inserted] = mName2ArrayGroups.emplace(name, (int)mArrayGroups.size()); + auto [DISCARD, inserted] = mName2ArrayGroups.insert(name, (int)mArrayGroups.size()); if (!inserted) { return nullptr; } @@ -252,6 +279,11 @@ TableArrayGroup* TableTemplate::AddArrayGroup(std::string_view name, int row, in return &mArrayGroups.back(); } +bool TableTemplate::UpdateArrayGroupName(std::string_view oldName, std::string_view newName) +{ + return ::UpdateElementName(mName2ArrayGroups, oldName, newName); +} + bool TableTemplate::ExtendArrayGroupLeft(int id, int n) { assert(n > 0); diff --git a/core/src/Model/Template/TableTemplate.hpp b/core/src/Model/Template/TableTemplate.hpp index a9a89d4..141e952 100644 --- a/core/src/Model/Template/TableTemplate.hpp +++ b/core/src/Model/Template/TableTemplate.hpp @@ -32,6 +32,7 @@ public: }; public: + /// Display content of this cell. This doesn't necessarily have to line up with the parameter name (if this cell is one). std::string Content; Vec2i Location; /// Location of the primary (top left) cell, if this cell is a part of a merged group. @@ -102,6 +103,7 @@ public: /// Find the location of the cell within this array group that has the given name. Vec2i FindCell(std::string_view name); + bool UpdateCellName(std::string_view oldName, std::string_view newName); }; // Forward declaration of libxlsxwriter structs @@ -165,13 +167,23 @@ public: const TableCell& GetCell(Vec2i pos) const; TableCell& GetCell(Vec2i pos); + /// void SetCellType(Vec2i pos, TableCell::CellType type); + /// Updates the parameter cell to a new name. Returns true on success and false on failure (param not found or name duplicates). + bool UpdateParameterName(std::string_view oldName, std::string_view newName); + int GetArrayGroupCount() const; const TableArrayGroup& GetArrayGroup(int id) const; TableArrayGroup& GetArrayGroup(int id); TableArrayGroup* AddArrayGroup(int row, int left, int right); TableArrayGroup* AddArrayGroup(std::string_view name, int row, int left, int right); + bool UpdateArrayGroupName(std::string_view oldName, std::string_view newName); bool ExtendArrayGroupLeft(int id, int n); bool ExtendArrayGroupRight(int id, int n); diff --git a/core/src/UI/UI_Templates.cpp b/core/src/UI/UI_Templates.cpp index b612662..b4e3aa5 100644 --- a/core/src/UI/UI_Templates.cpp +++ b/core/src/UI/UI_Templates.cpp @@ -16,6 +16,7 @@ #include #include #include +#include namespace { class TemplateUI @@ -59,14 +60,18 @@ private: /* Selection states */ union { + // Initialize to this element + std::monostate mIdleState{}; + /// "CS" stands for "Constant cell selection States" struct { - } mCS{}; // Initialize to this element + } mCS; /// "SS" stands for "Singular parameter selection States". struct { + std::string EditBuffer; bool ErrorDuplicateVarName; bool HasLeftAG; bool HasRightAG; @@ -75,10 +80,20 @@ private: /// "AS" stands for "Array group parameter selection States". struct { + std::string EditBuffer; bool ErrorDuplicateVarName; } mAS; + + // "RS" stands for "Range selection States". + struct + { + } mRS; }; + /* Table resizer dialog states */ + int mNewTableWidth; + int mNewTableHeight; + /* Table states */ bool mDirty = false; bool mFirstDraw = true; @@ -93,6 +108,36 @@ public: Resize(6, 5); } + virtual ~TableTemplateUI() override + { + // We can't move this to be a destructor of the union + // because that way it would run after the destruction of mTable + if (!IsSelected()) { + // Case: mIdleState + // Noop + } else if (mSelectionTL == mSelectionBR) { + switch (mTable->GetCell(mSelectionTL).Type) { + case TableCell::ConstantCell: + // Case: mCS + // Noop + break; + + case TableCell::SingularParametricCell: + // Case: mSS + mSS.EditBuffer.std::string::~string(); + break; + + case TableCell::ArrayParametricCell: + // Case: mAS + mAS.EditBuffer.std::string::~string(); + break; + } + } else { + // Case: mRS + // Noop + } + } + virtual void Display() override { ImGui::Columns(2); @@ -157,16 +202,24 @@ private: ImGui::EndTabItem(); } + auto OpenPopup = [](const char* name) { + // Act as if ImGui::OpenPopup is executed in the previous id stack frame (tab bar level) + // Note: we can't simply use ImGui::GetItemID() here, because that would return the id of the ImGui::Button + auto tabBar = ImGui::GetCurrentContext()->CurrentTabBar; + auto id = tabBar->Tabs[tabBar->LastTabItemIdx].ID; + ImGui::PopID(); + ImGui::OpenPopup(name); + ImGui::PushOverrideID(id); + }; if (ImGui::BeginTabItem(I18N_TEXT("Table", L10N_TABLE))) { - // Table properties if (ImGui::Button(I18N_TEXT("Configure table properties...", L10N_TABLE_CONFIGURE_PROPERTIES))) { - // Act as if ImGui::OpenPopup is executed in the previous id stack frame (tab bar level) - // Note: we can't simply use ImGui::GetItemID() here, because that would return the id of the ImGui::Button - auto tabBar = ImGui::GetCurrentContext()->CurrentTabBar; - auto id = tabBar->Tabs[tabBar->LastTabItemIdx].ID; - ImGui::PopID(); - ImGui::OpenPopup(I18N_TEXT("Table properties", L10N_TABLE_PROPERTIES)); - ImGui::PushOverrideID(id); + OpenPopup(I18N_TEXT("Table properties", L10N_TABLE_PROPERTIES)); + } + + if (ImGui::Button(I18N_TEXT("Resize table...", L10N_TABLE_DO_RESIZE))) { + mNewTableWidth = mTable->GetTableWidth(); + mNewTableHeight = mTable->GetTableHeight(); + OpenPopup(I18N_TEXT("Resize table", L10N_TABLE_RESIZE)); } // Table contents @@ -178,6 +231,10 @@ private: DisplayTableProperties(); ImGui::EndPopup(); } + if (ImGui::BeginPopupModal(I18N_TEXT("Resize table", L10N_TABLE_RESIZE), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) { + DisplayTableResizer(); + ImGui::EndPopup(); + } ImGui::EndTabBar(); } @@ -236,8 +293,7 @@ private: ExcelRow(pos.y + 1, std::begin(rowStr), std::end(rowStr)); ImGui::Text(I18N_TEXT("Location: %s%s", L10N_TABLE_CELL_POS), colBegin, rowStr); - switch (cell.Type) - { + switch (cell.Type) { case TableCell::ConstantCell: ImGui::Text(I18N_TEXT("Type: Constant", L10N_TABLE_CELL_TYPE_CONST)); break; @@ -253,31 +309,36 @@ private: ImGui::OpenPopup("ConvertCtxMenu"); } if (ImGui::BeginPopup("ConvertCtxMenu")) { - bool constantDisabled = cell.Type == TableCell::ConstantCell; - if (ImGui::MenuItem(I18N_TEXT("Convert to regular cell", L10N_TABLE_CELL_CONV_CONST), nullptr, false, !constantDisabled)) { + bool constantEnabled = cell.Type != TableCell::ConstantCell; + if (ImGui::MenuItem(I18N_TEXT("Convert to regular cell", L10N_TABLE_CELL_CONV_CONST), nullptr, false, constantEnabled)) { mTable->SetCellType(pos, TableCell::ConstantCell); + ResetCS(); } - bool singleDisabled = cell.Type == TableCell::SingularParametricCell; - if (ImGui::MenuItem(I18N_TEXT("Convert to parameter cell", L10N_TABLE_CELL_CONV_PARAM), nullptr, false, !singleDisabled)) { + bool singleEnabled = cell.Type != TableCell::SingularParametricCell; + if (ImGui::MenuItem(I18N_TEXT("Convert to parameter cell", L10N_TABLE_CELL_CONV_PARAM), nullptr, false, singleEnabled)) { mTable->SetCellType(pos, TableCell::SingularParametricCell); + ResetSS(pos); } - bool arrayDisabled = cell.Type == TableCell::ArrayParametricCell; - if (ImGui::MenuItem(I18N_TEXT("Add to a new array group", L10N_TABLE_CELL_CONV_CREATE_AG), nullptr, false, !arrayDisabled)) { - mTable->AddArrayGroup(pos.x, pos.x, pos.y); + bool arrayEnabled = cell.Type != TableCell::ArrayParametricCell; + if (ImGui::MenuItem(I18N_TEXT("Add to a new array group", L10N_TABLE_CELL_CONV_CREATE_AG), nullptr, false, arrayEnabled)) { + mTable->AddArrayGroup(pos.x, pos.x, pos.y); // Use automatically generated name + ResetAS(pos); } - bool leftDisabled = !mSS.HasLeftAG || arrayDisabled; - if (ImGui::MenuItem(I18N_TEXT("Add to the array group to the left", L10N_TABLE_CELL_CONV_ADD_AG_LEFT), nullptr, false, !leftDisabled)) { - auto& leftCell = mTable->GetCell((Vec2i){ pos.x - 1, pos.y }); + bool leftEnabled = mSS.HasLeftAG && arrayEnabled; + if (ImGui::MenuItem(I18N_TEXT("Add to the array group to the left", L10N_TABLE_CELL_CONV_ADD_AG_LEFT), nullptr, false, leftEnabled)) { + auto& leftCell = mTable->GetCell({ pos.x - 1, pos.y }); mTable->ExtendArrayGroupRight(leftCell.DataId, 1); + ResetAS(pos); } - bool rightDisabled = !mSS.HasRightAG || arrayDisabled; - if (ImGui::MenuItem(I18N_TEXT("Add to the array group to the right", L10N_TABLE_CELL_CONV_ADD_AG_RIGHT), nullptr, false, !rightDisabled)) { - auto& rightCell = mTable->GetCell((Vec2i){ pos.x + 1, pos.y }); + bool rightEnabled = mSS.HasRightAG && arrayEnabled; + if (ImGui::MenuItem(I18N_TEXT("Add to the array group to the right", L10N_TABLE_CELL_CONV_ADD_AG_RIGHT), nullptr, false, rightEnabled)) { + auto& rightCell = mTable->GetCell({ pos.x + 1, pos.y }); mTable->ExtendArrayGroupLeft(rightCell.DataId, 1); + ResetAS(pos); } ImGui::EndPopup(); @@ -339,9 +400,16 @@ private: break; case TableCell::SingularParametricCell: - if (ImGui::InputText(I18N_TEXT("Variable name", L10N_TABLE_CELL_VAR_NAME), &cell.Content)) { - auto c = mTable->FindCell(cell.Content); - mSS.ErrorDuplicateVarName = c != nullptr; + if (ImGui::InputText(I18N_TEXT("Variable name", L10N_TABLE_CELL_VAR_NAME), &mSS.EditBuffer)) { + // Sync name change to table + bool success = mTable->UpdateParameterName(cell.Content, mSS.EditBuffer); + if (success) { + // Flush name to display content + cell.Content = mSS.EditBuffer; + mSS.ErrorDuplicateVarName = false; + } else { + mSS.ErrorDuplicateVarName = true; + } } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(I18N_TEXT("Name of the parameter link to this cell.", L10N_TABLE_CELL_VAR_TOOLTIP)); @@ -353,10 +421,15 @@ private: break; case TableCell::ArrayParametricCell: - if (ImGui::InputText(I18N_TEXT("Variable name", L10N_TABLE_CELL_VAR_NAME), &cell.Content)) { + if (ImGui::InputText(I18N_TEXT("Variable name", L10N_TABLE_CELL_VAR_NAME), &mAS.EditBuffer)) { auto ag = mTable->GetArrayGroup(cell.DataId); - auto cl = ag.FindCell(cell.Content); - mAS.ErrorDuplicateVarName = cl.x != -1 && cl.y != -1; + bool success = ag.UpdateCellName(cell.Content, mAS.EditBuffer); + if (success) { + cell.Content = mAS.EditBuffer; + mAS.ErrorDuplicateVarName = false; + } else { + mAS.ErrorDuplicateVarName = true; + } } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(I18N_TEXT("Name of the parameter lnk to this cell; local within the array group.", L10N_TABLE_CELL_ARRAY_VAR_TOOLTIP)); @@ -413,6 +486,21 @@ private: // TODO } + void DisplayTableResizer() + { + ImGui::InputInt(I18N_TEXT("Width", L10N_TABLE_WIDTH), &mNewTableWidth); + ImGui::InputInt(I18N_TEXT("Height", L10N_TABLE_HEIGHT), &mNewTableHeight); + + if (ImGui::Button(I18N_TEXT("Confirm", L10N_CONFIRM))) { + ImGui::CloseCurrentPopup(); + Resize(mNewTableWidth, mNewTableHeight); + } + ImGui::SameLine(); + if (ImGui::Button(I18N_TEXT("Cancel", L10N_CANCEL))) { + ImGui::CloseCurrentPopup(); + } + } + void DisplayTable() { ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 8)); @@ -561,12 +649,12 @@ private: mSelectionTL = { -1, -1 }; mSelectionBR = { -1, -1 }; - ResetCS(); + ResetIdleState(); } - void ResetCS() + void ResetIdleState() { - mCS = {}; + mIdleState = {}; } void SelectRange(Vec2i p1, Vec2i p2) @@ -588,33 +676,49 @@ private: uiCell.Selected = true; }); - ResetAS(); + ResetRS(); } - void ResetSS(Vec2i pos) + void ResetRS() { - mSS = {}; - mSS.ErrorDuplicateVarName = false; - mSS.HasLeftAG = pos.x > 1 && mTable->GetCell({ pos.x - 1, pos.y }).Type == TableCell::ArrayParametricCell; - mSS.HasRightAG = pos.x < mTable->GetTableWidth() - 1 && mTable->GetCell({ pos.x + 1, pos.y }).Type == TableCell::ArrayParametricCell; + mRS = {}; } - void SelectCell(Vec2i cell) + void SelectCell(Vec2i pos) { ClearSelection(); - mSelectionTL = cell; - mSelectionBR = cell; + mSelectionTL = pos; + mSelectionBR = pos; - int i = cell.y * mTable->GetTableWidth() + cell.x; + int i = pos.y * mTable->GetTableWidth() + pos.x; mUICells[i].Selected = true; - ResetSS(cell); + switch (mTable->GetCell(pos).Type) { + case TableCell::ConstantCell: ResetCS(); break; + case TableCell::SingularParametricCell: ResetSS(pos); break; + case TableCell::ArrayParametricCell: ResetAS(pos); break; + } + } + + void ResetCS() + { + mCS = {}; + } + + void ResetSS(Vec2i pos) + { + mSS = {}; + mSS.EditBuffer = mTable->GetCell(pos).Content; + mSS.ErrorDuplicateVarName = false; + mSS.HasLeftAG = pos.x > 1 && mTable->GetCell({ pos.x - 1, pos.y }).Type == TableCell::ArrayParametricCell; + mSS.HasRightAG = pos.x < mTable->GetTableWidth() - 1 && mTable->GetCell({ pos.x + 1, pos.y }).Type == TableCell::ArrayParametricCell; } - void ResetAS() + void ResetAS(Vec2i pos) { mAS = {}; + mAS.EditBuffer = mTable->GetCell(pos).Content; mAS.ErrorDuplicateVarName = false; } }; -- cgit v1.2.3-70-g09d2