aboutsummaryrefslogtreecommitdiff
path: root/core/src/UI/UI_Templates.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/UI/UI_Templates.cpp')
-rw-r--r--core/src/UI/UI_Templates.cpp977
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 = &paramPalette;
- 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();
- }
-}