diff options
Diffstat (limited to 'core/src/UI/UI_Templates.cpp')
-rw-r--r-- | core/src/UI/UI_Templates.cpp | 977 |
1 files changed, 0 insertions, 977 deletions
diff --git a/core/src/UI/UI_Templates.cpp b/core/src/UI/UI_Templates.cpp deleted file mode 100644 index cd15cb7..0000000 --- a/core/src/UI/UI_Templates.cpp +++ /dev/null @@ -1,977 +0,0 @@ -#include "UI.hpp" - -#include "Model/GlobalStates.hpp" -#include "Model/Project.hpp" -#include "Model/Template/TableTemplate.hpp" -#include "Model/Template/TableTemplateIterator.hpp" -#include "Model/Template/Template.hpp" -#include "Utils/I18n.hpp" - -#include <IconsFontAwesome.h> -#include <imgui.h> -#include <imgui_extra_math.h> -#include <imgui_internal.h> -#include <imgui_stdlib.h> -#include <charconv> -#include <fstream> -#include <iostream> -#include <utility> -#include <variant> - -namespace CPLT_UNITY_ID { -class TemplateUI -{ -public: - static std::unique_ptr<TemplateUI> CreateByKind(std::unique_ptr<Template> tmpl); - static std::unique_ptr<TemplateUI> CreateByKind(Template::Kind kind); - - virtual ~TemplateUI() = default; - virtual void Display() = 0; - virtual void Close() = 0; -}; - -// Table template styles -constexpr ImU32 kSingleParamOutline = IM_COL32(255, 255, 0, 255); -constexpr ImU32 kArrayGroupOutline = IM_COL32(255, 0, 0, 255); - -class TableTemplateUI : public TemplateUI -{ -private: - std::unique_ptr<TableTemplate> mTable; - - struct UICell - { - bool Hovered = false; - bool Held = false; - bool Selected = false; - }; - std::vector<UICell> mUICells; - - struct UIArrayGroup - { - ImVec2 Pos; - ImVec2 Size; - }; - std::vector<UIArrayGroup> mUIArrayGroups; - - struct Sizer - { - bool Hovered = false; - bool Held = false; - }; - std::vector<Sizer> mRowSizers; - std::vector<Sizer> mColSizers; - - /* Selection range */ - Vec2i mSelectionTL; - Vec2i mSelectionBR; - - /* Selection states */ - - /// "CStates" stands for "Constant cell selection States" - struct CStates - { - }; - - /// "SStates" stands for "Singular parameter selection States". - struct SStates - { - std::string EditBuffer; - bool ErrorDuplicateVarName; - bool HasLeftAG; - bool HasRightAG; - }; - - /// "AStates" stands for "Array group parameter selection States". - struct AStates - { - std::string EditBuffer; - bool ErrorDuplicateVarName; - }; - - // "RStates" stands for "Range selection States". - struct RStates - { - }; - - union - { - // Initialize to this element - std::monostate mIdleState{}; - CStates mCS; - SStates mSS; - AStates mAS; - RStates mRS; - }; - - /* Table resizer dialog states */ - int mNewTableWidth; - int mNewTableHeight; - - /* Table states */ - enum EditMode - { - ModeEditing, - ModeColumnResizing, - ModeRowResizing, - }; - EditMode mMode = ModeEditing; - - float mStartDragDim; - /// Depending on row/column sizer being dragged, this will be the y/x coordinate - float mStartDragMouseCoordinate; - - bool mDirty = false; - bool mFirstDraw = true; - -public: - TableTemplateUI(std::unique_ptr<TableTemplate> table) - : mTable{ std::move(table) } - , mSelectionTL{ -1, -1 } - , mSelectionBR{ -1, -1 } - { - // TODO debug code - Resize(6, 5); - } - - ~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 - } - } - - void Display() override - { - ImGui::Columns(2); - if (mFirstDraw) { - mFirstDraw = false; - ImGui::SetColumnWidth(0, ImGui::GetWindowWidth() * 0.15f); - } - - DisplayInspector(); - ImGui::NextColumn(); - - auto initialPos = ImGui::GetCursorPos(); - DisplayTable(); - DisplayTableResizers(initialPos); - ImGui::NextColumn(); - - ImGui::Columns(1); - } - - void Close() override - { - // TODO - } - - void Resize(int width, int height) - { - mTable->Resize(width, height); - mUICells.resize(width * height); - mUIArrayGroups.resize(mTable->GetArrayGroupCount()); - mRowSizers.resize(width); - mColSizers.resize(height); - - for (size_t i = 0; i < mUIArrayGroups.size(); ++i) { - auto& ag = mTable->GetArrayGroup(i); - auto& uag = mUIArrayGroups[i]; - - auto itemSpacing = ImGui::GetStyle().ItemSpacing; - uag.Pos.x = CalcTablePixelWidth() + itemSpacing.x; - uag.Pos.y = CalcTablePixelHeight() + itemSpacing.y; - - uag.Size.x = mTable->GetRowHeight(ag.Row); - uag.Size.y = 0; - for (int x = ag.LeftCell; x <= ag.RightCell; ++x) { - uag.Size.y += mTable->GetColumnWidth(x); - } - } - - mSelectionTL = { 0, 0 }; - mSelectionBR = { 0, 0 }; - } - -private: - void DisplayInspector() - { - bool openedDummy = true; - - // This is an id, no need to localize - if (ImGui::BeginTabBar("Inspector")) { - if (ImGui::BeginTabItem(I18N_TEXT("Cell", L10N_TABLE_CELL))) { - if (!IsSelected()) { - ImGui::Text(I18N_TEXT("Select a cell to edit", L10N_TABLE_CELL_SELECT_MSG)); - } else if (mSelectionTL == mSelectionBR) { - DisplayCellProperties(mSelectionTL); - } else { - DisplayRangeProperties(mSelectionTL, mSelectionBR); - } - 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))) { - if (ImGui::Button(I18N_TEXT("Configure table properties...", L10N_TABLE_CONFIGURE_PROPERTIES))) { - mNewTableWidth = mTable->GetTableWidth(); - mNewTableHeight = mTable->GetTableHeight(); - OpenPopup(I18N_TEXT("Table properties", L10N_TABLE_PROPERTIES)); - } - - int mode = mMode; - ImGui::RadioButton(I18N_TEXT("Edit table", L10N_TABLE_EDIT_TABLE), &mode, ModeEditing); - ImGui::RadioButton(I18N_TEXT("Resize column widths", L10N_TABLE_EDIT_RESIZE_COLS), &mode, ModeColumnResizing); - ImGui::RadioButton(I18N_TEXT("Resize rows heights", L10N_TABLE_EDIT_RESIZE_ROWS), &mode, ModeRowResizing); - mMode = static_cast<EditMode>(mode); - - // Table contents - DisplayTableContents(); - - ImGui::EndTabItem(); - } - if (ImGui::BeginPopupModal(I18N_TEXT("Table properties", L10N_TABLE_PROPERTIES), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) { - DisplayTableProperties(); - ImGui::EndPopup(); - } - - ImGui::EndTabBar(); - } - } - - static char NthUppercaseLetter(int n) - { - return (char)((int)'A' + n); - } - - static void ExcelRow(int row, char* bufferBegin, char* bufferEnd) - { - auto res = std::to_chars(bufferBegin, bufferEnd, row); - if (res.ec != std::errc()) { - return; - } - } - - static char* ExcelColumn(int column, char* bufferBegin, char* bufferEnd) - { - // https://stackoverflow.com/a/182924/11323702 - - int dividend = column; - int modulo; - - char* writeHead = bufferEnd - 1; - *writeHead = '\0'; - --writeHead; - - while (dividend > 0) { - if (writeHead < bufferBegin) { - return nullptr; - } - - modulo = (dividend - 1) % 26; - - *writeHead = NthUppercaseLetter(modulo); - --writeHead; - - dividend = (dividend - modulo) / 26; - } - - // `writeHead` at this point would be a one-past-the-bufferEnd reverse iterator (i.e. one-past-the-(text)beginning in the bufferBegin) - // add 1 to get to the actual beginning of the text - return writeHead + 1; - } - - void DisplayCellProperties(Vec2i pos) - { - auto& cell = mTable->GetCell(pos); - auto& uiCell = mUICells[pos.y * mTable->GetTableWidth() + pos.x]; - - char colStr[8]; // 2147483647 -> FXSHRXW, len == 7, along with \0 - char* colBegin = ExcelColumn(pos.x + 1, std::begin(colStr), std::end(colStr)); - char rowStr[11]; // len(2147483647) == 10, along with \0 - 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) { - case TableCell::ConstantCell: - ImGui::Text(I18N_TEXT("Type: Constant", L10N_TABLE_CELL_TYPE_CONST)); - break; - case TableCell::SingularParametricCell: - ImGui::Text(I18N_TEXT("Type: Single parameter", L10N_TABLE_CELL_TYPE_PARAM)); - break; - case TableCell::ArrayParametricCell: - ImGui::Text(I18N_TEXT("Type: Array group", L10N_TABLE_CELL_TYPE_CREATE_AG)); - break; - } - - ImGui::SameLine(); - if (ImGui::Button(ICON_FA_EDIT)) { - ImGui::OpenPopup("ConvertCtxMenu"); - } - if (ImGui::BeginPopup("ConvertCtxMenu")) { - 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 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 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.y, pos.x, pos.x); // Use automatically generated name - ResetAS(pos); - } - - 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 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(); - } - - ImGui::Spacing(); - - constexpr auto kLeft = I18N_TEXT("Left", L10N_TABLE_CELL_ALIGN_LEFT); - constexpr auto kCenter = I18N_TEXT("Center", L10N_TABLE_CELL_ALIGN_CENTER); - constexpr auto kRight = I18N_TEXT("Right", L10N_TABLE_CELL_ALIGN_RIGHT); - - const char* horizontalText; - switch (cell.HorizontalAlignment) { - case TableCell::AlignAxisMin: horizontalText = kLeft; break; - case TableCell::AlignCenter: horizontalText = kCenter; break; - case TableCell::AlignAxisMax: horizontalText = kRight; break; - } - - if (ImGui::BeginCombo(I18N_TEXT("Horizontal alignment", L10N_TABLE_CELL_HORIZONTAL_ALIGNMENT), horizontalText)) { - if (ImGui::Selectable(kLeft, cell.HorizontalAlignment == TableCell::AlignAxisMin)) { - cell.HorizontalAlignment = TableCell::AlignAxisMin; - } - if (ImGui::Selectable(kCenter, cell.HorizontalAlignment == TableCell::AlignCenter)) { - cell.HorizontalAlignment = TableCell::AlignCenter; - } - if (ImGui::Selectable(kRight, cell.HorizontalAlignment == TableCell::AlignAxisMax)) { - cell.HorizontalAlignment = TableCell::AlignAxisMax; - } - ImGui::EndCombo(); - } - - constexpr auto kTop = I18N_TEXT("Left", L10N_TABLE_CELL_ALIGN_TOP); - constexpr auto kMiddle = I18N_TEXT("Middle", L10N_TABLE_CELL_ALIGN_MIDDLE); - constexpr auto kBottom = I18N_TEXT("Right", L10N_TABLE_CELL_ALIGN_BOTTOM); - - const char* verticalText; - switch (cell.VerticalAlignment) { - case TableCell::AlignAxisMin: verticalText = kTop; break; - case TableCell::AlignCenter: verticalText = kMiddle; break; - case TableCell::AlignAxisMax: verticalText = kBottom; break; - } - - if (ImGui::BeginCombo(I18N_TEXT("Vertical alignment", L10N_TABLE_CELL_VERTICAL_ALIGNMENT), verticalText)) { - if (ImGui::Selectable(kTop, cell.VerticalAlignment == TableCell::AlignAxisMin)) { - cell.VerticalAlignment = TableCell::AlignAxisMin; - } - if (ImGui::Selectable(kMiddle, cell.VerticalAlignment == TableCell::AlignCenter)) { - cell.VerticalAlignment = TableCell::AlignCenter; - } - if (ImGui::Selectable(kBottom, cell.VerticalAlignment == TableCell::AlignAxisMax)) { - cell.VerticalAlignment = TableCell::AlignAxisMax; - } - ImGui::EndCombo(); - } - - switch (cell.Type) { - case TableCell::ConstantCell: - ImGui::InputText(I18N_TEXT("Content", L10N_TABLE_CELL_CONTENT), &cell.Content); - break; - - case TableCell::SingularParametricCell: - 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)); - } - - if (mSS.ErrorDuplicateVarName) { - ImGui::ErrorMessage(I18N_TEXT("Variable name duplicated.", L10N_TABLE_CELL_VAR_NAME_DUP)); - } - break; - - case TableCell::ArrayParametricCell: - if (ImGui::InputText(I18N_TEXT("Variable name", L10N_TABLE_CELL_VAR_NAME), &mAS.EditBuffer)) { - auto ag = mTable->GetArrayGroup(cell.DataId); - 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 link to this cell; local within the array group.", L10N_TABLE_CELL_ARRAY_VAR_TOOLTIP)); - } - - if (mAS.ErrorDuplicateVarName) { - ImGui::ErrorMessage(I18N_TEXT("Variable name duplicated.", L10N_TABLE_CELL_VAR_NAME_DUP)); - } - break; - } - } - - void DisplayRangeProperties(Vec2i tl, Vec2i br) - { - // TODO - } - - void DisplayTableContents() - { - if (ImGui::TreeNode(ICON_FA_BONG " " I18N_TEXT("Parameters", L10N_TABLE_SINGLE_PARAMS))) { - TableSingleParamsIter iter(*mTable); - while (iter.HasNext()) { - auto& cell = iter.Next(); - if (ImGui::Selectable(cell.Content.c_str())) { - SelectCell(cell.Location); - } - } - ImGui::TreePop(); - } - if (ImGui::TreeNode(ICON_FA_LIST " " I18N_TEXT("Array groups", L10N_TABLE_ARRAY_GROUPS))) { - TableArrayGroupsIter iter(*mTable); - // For each array group - while (iter.HasNext()) { - if (ImGui::TreeNode(iter.PeekNameCStr())) { - auto& ag = iter.Peek(); - // For each cell in the array group - for (int x = ag.LeftCell; x <= ag.RightCell; ++x) { - Vec2i pos{ x, ag.Row }; - auto& cell = mTable->GetCell(pos); - if (ImGui::Selectable(cell.Content.c_str())) { - SelectCell(pos); - } - } - ImGui::TreePop(); - } - iter.Next(); - } - ImGui::TreePop(); - } - } - - void DisplayTableProperties() - { - 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(); - } - - // TODO - } - - void DisplayTable() - { - struct CellPalette - { - ImU32 Regular; - ImU32 Hovered; - ImU32 Active; - - ImU32 GetColorFor(const UICell& cell) const - { - if (cell.Held) { - return Active; - } else if (cell.Hovered) { - return Hovered; - } else { - return Regular; - } - } - }; - - CellPalette constantPalette{ - .Regular = ImGui::GetColorU32(ImGuiCol_Button), - .Hovered = ImGui::GetColorU32(ImGuiCol_ButtonHovered), - .Active = ImGui::GetColorU32(ImGuiCol_ButtonActive), - }; - CellPalette paramPalette{ - .Regular = IM_COL32(0, 214, 4, 102), - .Hovered = IM_COL32(0, 214, 4, 255), - .Active = IM_COL32(0, 191, 2, 255), - }; - - // TODO array group color - - auto navHighlight = ImGui::GetColorU32(ImGuiCol_NavHighlight); - - int colCount = mTable->GetTableWidth(); - int rowCount = mTable->GetTableHeight(); - for (int rowIdx = 0; rowIdx < rowCount; ++rowIdx) { - int rowHeight = mTable->GetRowHeight(rowIdx); - - for (int colIdx = 0; colIdx < colCount; ++colIdx) { - int colWidth = mTable->GetColumnWidth(colIdx); - - int i = rowIdx * colCount + colIdx; - auto window = ImGui::GetCurrentWindow(); - auto id = window->GetID(i); - - Vec2i cellLoc{ colIdx, rowIdx }; - auto& cell = mTable->GetCell(cellLoc); - auto& uiCell = mUICells[i]; - - ImVec2 size(colWidth, rowHeight); - ImRect rect{ - window->DC.CursorPos, - window->DC.CursorPos + ImGui::CalcItemSize(size, 0.0f, 0.0f), - }; - - /* Draw cell selection */ - - if (uiCell.Selected) { - constexpr int mt = 2; // Marker Thickness - constexpr int ms = 8; // Marker Size - - ImVec2 outerTL(rect.Min - ImVec2(mt, mt)); - ImVec2 outerBR(rect.Max + ImVec2(mt, mt)); - - // Top left - window->DrawList->AddRectFilled(outerTL + ImVec2(0, 0), outerTL + ImVec2(ms, mt), navHighlight); - window->DrawList->AddRectFilled(outerTL + ImVec2(0, mt), outerTL + ImVec2(mt, ms), navHighlight); - - // Top right - ImVec2 outerTR(outerBR.x, outerTL.y); - window->DrawList->AddRectFilled(outerTR + ImVec2(-ms, 0), outerTR + ImVec2(0, mt), navHighlight); - window->DrawList->AddRectFilled(outerTR + ImVec2(-mt, mt), outerTR + ImVec2(0, ms), navHighlight); - - // Bottom right - window->DrawList->AddRectFilled(outerBR + ImVec2(-ms, -mt), outerBR + ImVec2(0, 0), navHighlight); - window->DrawList->AddRectFilled(outerBR + ImVec2(-mt, -ms), outerBR + ImVec2(0, -mt), navHighlight); - - // Bottom left - ImVec2 outerBL(outerTL.x, outerBR.y); - window->DrawList->AddRectFilled(outerBL + ImVec2(0, -mt), outerBL + ImVec2(ms, 0), navHighlight); - window->DrawList->AddRectFilled(outerBL + ImVec2(0, -ms), outerBL + ImVec2(mt, -mt), navHighlight); - } - - /* Draw cell body */ - - CellPalette* palette; - switch (cell.Type) { - case TableCell::ConstantCell: - palette = &constantPalette; - break; - - case TableCell::SingularParametricCell: - case TableCell::ArrayParametricCell: - palette = ¶mPalette; - break; - } - - window->DrawList->AddRectFilled(rect.Min, rect.Max, palette->GetColorFor(uiCell)); - - /* Draw cell content */ - - auto content = cell.Content.c_str(); - auto contentEnd = content + cell.Content.size(); - auto textSize = ImGui::CalcTextSize(content, contentEnd); - - ImVec2 textRenderPos; - switch (cell.HorizontalAlignment) { - case TableCell::AlignAxisMin: textRenderPos.x = rect.Min.x; break; - case TableCell::AlignCenter: textRenderPos.x = rect.Min.x + colWidth / 2 - textSize.x / 2; break; - case TableCell::AlignAxisMax: textRenderPos.x = rect.Max.x - textSize.x; break; - } - switch (cell.VerticalAlignment) { - case TableCell::AlignAxisMin: textRenderPos.y = rect.Min.y; break; - case TableCell::AlignCenter: textRenderPos.y = rect.Min.y + rowHeight / 2 - textSize.y / 2; break; - case TableCell::AlignAxisMax: textRenderPos.y = rect.Max.y - textSize.y; break; - } - window->DrawList->AddText(textRenderPos, IM_COL32(0, 0, 0, 255), content, contentEnd); - - /* Update ImGui cursor */ - - ImGui::ItemSize(size); - if (!ImGui::ItemAdd(rect, id)) { - goto logicEnd; - } - - if (mMode != ModeEditing) { - goto logicEnd; - } - if (ImGui::ButtonBehavior(rect, id, &uiCell.Hovered, &uiCell.Held)) { - if (ImGui::GetIO().KeyShift && IsSelected()) { - SelectRange(mSelectionTL, { colIdx, rowIdx }); - } else { - SelectCell({ colIdx, rowIdx }); - } - } - - logicEnd: - // Don't SameLine() if we are on the last cell in the row - if (colIdx != colCount - 1) { - ImGui::SameLine(); - } - } - } - - for (auto& uag : mUIArrayGroups) { - ImGui::GetCurrentWindow()->DrawList->AddRect( - uag.Pos - ImVec2(1, 1), - uag.Pos + uag.Size + ImVec2(1, 1), - kArrayGroupOutline); - } - } - - void DisplayResizers( - ImVec2 pos, - ImVec2 sizerDim, - ImVec2 sizerOffset, - std::type_identity_t<float ImVec2::*> vecCompGetter, - std::type_identity_t<int (TableTemplate::*)() const> lenGetter, - std::type_identity_t<int (TableTemplate::*)(int) const> dimGetter, - std::type_identity_t<void (TableTemplate::*)(int, int)> dimSetter) - { - auto window = ImGui::GetCurrentWindow(); - auto spacing = ImGui::GetStyle().ItemSpacing.*vecCompGetter; - - auto regularColor = ImGui::GetColorU32(ImGuiCol_Button); - auto hoveredColor = ImGui::GetColorU32(ImGuiCol_ButtonHovered); - auto activeColor = ImGui::GetColorU32(ImGuiCol_ButtonActive); - - auto GetColor = [&](const Sizer& sizer) -> ImU32 { - if (sizer.Held) { - return activeColor; - } else if (sizer.Hovered) { - return hoveredColor; - } else { - return regularColor; - } - }; - - for (int ix = 0; ix < (mTable.get()->*lenGetter)(); ++ix) { - // ImGui uses float for sizes, our table uses int (because excel uses int) - // Convert here to avoid mountains of narrowing warnings below - auto dim = (float)(mTable.get()->*dimGetter)(ix); - - pos.*vecCompGetter += dim; - ImRect rect{ - pos - sizerOffset, - pos - sizerOffset + ImGui::CalcItemSize(sizerDim, 0.0f, 0.0f), - }; - pos.*vecCompGetter += spacing; - - auto& sizer = mColSizers[ix]; - auto id = window->GetID(ix); - window->DrawList->AddRectFilled(rect.Min, rect.Max, GetColor(sizer)); - - if (ImGui::ButtonBehavior(rect, id, &sizer.Hovered, &sizer.Held, ImGuiButtonFlags_PressedOnClick)) { - mStartDragDim = dim; - mStartDragMouseCoordinate = ImGui::GetMousePos().*vecCompGetter; - } - if (sizer.Held) { - float change = ImGui::GetMousePos().*vecCompGetter - mStartDragMouseCoordinate; - float colWidth = std::max(mStartDragDim + change, 1.0f); - (mTable.get()->*dimSetter)(ix, (int)colWidth); - } - } - } - - void DisplayTableResizers(ImVec2 topLeftPixelPos) - { - constexpr float kExtraSideLength = 5.0f; - constexpr float kExtraAxialLength = 2.0f; - - switch (mMode) { - case ModeEditing: break; - - case ModeColumnResizing: - ImGui::PushID("Cols"); - DisplayResizers( - topLeftPixelPos, - ImVec2( - ImGui::GetStyle().ItemSpacing.x + kExtraSideLength * 2, - CalcTablePixelHeight() + kExtraAxialLength * 2), - ImVec2(kExtraSideLength, kExtraAxialLength), - &ImVec2::x, - &TableTemplate::GetTableWidth, - &TableTemplate::GetColumnWidth, - &TableTemplate::SetColumnWidth); - ImGui::PopID(); - break; - - case ModeRowResizing: - ImGui::PushID("Rows"); - DisplayResizers( - topLeftPixelPos, - ImVec2( - CalcTablePixelWidth() + kExtraAxialLength * 2, - ImGui::GetStyle().ItemSpacing.y + kExtraSideLength * 2), - ImVec2(kExtraAxialLength, kExtraSideLength), - &ImVec2::y, - &TableTemplate::GetTableHeight, - &TableTemplate::GetRowHeight, - &TableTemplate::SetRowHeight); - ImGui::PopID(); - break; - } - } - - float CalcTablePixelWidth() const - { - float horizontalSpacing = ImGui::GetStyle().ItemSpacing.x; - float width = 0; - for (int x = 0; x < mTable->GetTableWidth(); ++x) { - width += mTable->GetColumnWidth(x); - width += horizontalSpacing; - } - return width - horizontalSpacing; - } - - float CalcTablePixelHeight() const - { - float verticalSpacing = ImGui::GetStyle().ItemSpacing.y; - float height = 0; - for (int y = 0; y < mTable->GetTableHeight(); ++y) { - height += mTable->GetRowHeight(y); - height += verticalSpacing; - } - return height - verticalSpacing; - } - - template <class TFunction> - void ForeachSelectedCell(const TFunction& func) - { - for (int y = mSelectionTL.y; y <= mSelectionBR.y; ++y) { - for (int x = mSelectionTL.x; x <= mSelectionBR.x; ++x) { - int i = y * mTable->GetTableWidth() + x; - func(i, x, y); - } - } - } - - bool IsSelected() const - { - return mSelectionTL.x != -1; - } - - void ClearSelection() - { - if (IsSelected()) { - ForeachSelectedCell([this](int i, int, int) { - auto& uiCell = mUICells[i]; - uiCell.Selected = false; - }); - } - - mSelectionTL = { -1, -1 }; - mSelectionBR = { -1, -1 }; - - ResetIdleState(); - } - - void ResetIdleState() - { - mIdleState = {}; - } - - void SelectRange(Vec2i p1, Vec2i p2) - { - ClearSelection(); - - if (p2.x < p1.x) { - std::swap(p2.x, p1.x); - } - if (p2.y < p1.y) { - std::swap(p2.y, p1.y); - } - - mSelectionTL = p1; - mSelectionBR = p2; - - ForeachSelectedCell([this](int i, int, int) { - auto& uiCell = mUICells[i]; - uiCell.Selected = true; - }); - - ResetRS(); - } - - void ResetRS() - { - mRS = {}; - } - - void SelectCell(Vec2i pos) - { - ClearSelection(); - - mSelectionTL = pos; - mSelectionBR = pos; - - int i = pos.y * mTable->GetTableWidth() + pos.x; - mUICells[i].Selected = true; - - 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) - { - new (&mSS) SStates{ - .EditBuffer = mTable->GetCell(pos).Content, - .ErrorDuplicateVarName = false, - .HasLeftAG = pos.x > 1 && mTable->GetCell({ pos.x - 1, pos.y }).Type == TableCell::ArrayParametricCell, - .HasRightAG = pos.x < mTable->GetTableWidth() - 1 && mTable->GetCell({ pos.x + 1, pos.y }).Type == TableCell::ArrayParametricCell, - }; - } - - void ResetAS(Vec2i pos) - { - new (&mAS) AStates{ - .EditBuffer = mTable->GetCell(pos).Content, - .ErrorDuplicateVarName = false, - }; - } -}; - -template <class TTarget> -static auto CastTemplateAs(std::unique_ptr<Template>& input) requires std::is_base_of_v<Template, TTarget> -{ - return std::unique_ptr<TTarget>(static_cast<TTarget*>(input.release())); -} - -std::unique_ptr<TemplateUI> TemplateUI::CreateByKind(std::unique_ptr<Template> tmpl) -{ - switch (tmpl->GetKind()) { - case Template::KD_Table: return std::make_unique<TableTemplateUI>(CastTemplateAs<TableTemplate>(tmpl)); - case Template::InvalidKind: break; - } - return nullptr; -} - -std::unique_ptr<TemplateUI> TemplateUI::CreateByKind(Template::Kind kind) -{ - switch (kind) { - case Template::KD_Table: return std::make_unique<TableTemplateUI>(std::make_unique<TableTemplate>()); - case Template::InvalidKind: break; - } - return nullptr; -} -} // namespace CPLT_UNITY_ID - -void UI::TemplatesTab() -{ - auto& project = *GlobalStates::GetInstance().GetCurrentProject(); - - static std::unique_ptr<CPLT_UNITY_ID::TemplateUI> openTemplate; - static AssetList::ListState state; - bool openedDummy = true; - - // Toolbar item: close - if (ImGui::Button(ICON_FA_TIMES " " I18N_TEXT("Close", L10N_CLOSE), openTemplate == nullptr)) { - openTemplate->Close(); - openTemplate = nullptr; - } - - // Toolbar item: open... - ImGui::SameLine(); - if (ImGui::Button(I18N_TEXT("Open asset...", L10N_ASSET_OPEN))) { - ImGui::OpenPopup(I18N_TEXT("Open asset", L10N_ASSET_OPEN_DIALOG_TITLE)); - } - if (ImGui::BeginPopupModal(I18N_TEXT("Open asset", L10N_ASSET_OPEN_DIALOG_TITLE), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) { - if (ImGui::Button(ICON_FA_FOLDER_OPEN " " I18N_TEXT("Open", L10N_OPEN), state.SelectedAsset == nullptr)) { - ImGui::CloseCurrentPopup(); - - auto tmpl = project.Templates.Load(*state.SelectedAsset); - openTemplate = CPLT_UNITY_ID::TemplateUI::CreateByKind(std::move(tmpl)); - } - ImGui::SameLine(); - project.Templates.DisplayControls(state); - project.Templates.DisplayDetailsList(state); - - ImGui::EndPopup(); - } - - // Toolbar item: manage... - ImGui::SameLine(); - if (ImGui::Button(I18N_TEXT("Manage assets...", L10N_ASSET_MANAGE))) { - ImGui::OpenPopup(I18N_TEXT("Manage assets", L10N_ASSET_MANAGE_DIALOG_TITLE)); - } - if (ImGui::BeginPopupModal(I18N_TEXT("Manage assets", L10N_ASSET_MANAGE_DIALOG_TITLE), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) { - project.Templates.DisplayControls(state); - project.Templates.DisplayDetailsList(state); - ImGui::EndPopup(); - } - - if (openTemplate) { - openTemplate->Display(); - } -} |