aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/src/Locale/zh_CN.h9
-rw-r--r--core/src/Model/Template/TableTemplate.cpp114
-rw-r--r--core/src/Model/Template/TableTemplate.hpp39
-rw-r--r--core/src/Model/Template/fwd.hpp2
-rw-r--r--core/src/UI/UI.hpp2
-rw-r--r--core/src/UI/UI_Templates.cpp166
-rw-r--r--core/src/UI/UI_Utils.cpp9
7 files changed, 317 insertions, 24 deletions
diff --git a/core/src/Locale/zh_CN.h b/core/src/Locale/zh_CN.h
index 8e0e3e3..d1f32ff 100644
--- a/core/src/Locale/zh_CN.h
+++ b/core/src/Locale/zh_CN.h
@@ -123,11 +123,20 @@
#define L10N_TEMPLATE_TABLE "表格模板"
+#define L10N_TABLE "表格"
+#define L10N_TABLE_CELL "单元格"
+#define L10N_TABLE_CELL_CONV "转换类型..."
+#define L10N_TABLE_CELL_CONV_PARAM "单元格参数"
+#define L10N_TABLE_CELL_CONV_CREATE_AG "创建列表参数组"
+#define L10N_TABLE_CELL_CONV_ADD_AG_LEFT "添加至左侧的列表参数组"
+#define L10N_TABLE_CELL_CONV_ADD_AG_RIGHT "添加至右侧的列表参数组"
+#define L10N_TABLE_CELL_SELECT_MSG "请单击选择一个单元格以编辑其属性"
#define L10N_TABLE_CELL_HORIZONTAL_ALIGNMENT "水平对齐"
#define L10N_TABLE_CELL_CONTENT "内容"
#define L10N_TABLE_CELL_VAR_NAME "变量名"
#define L10N_TABLE_CELL_VAR_TOOLTIP "参数单元格的唯一名称(表格内不得重复)。"
#define L10N_TABLE_CELL_ARRAY_VAR_TOOLTIP "列表参数组内单个参数单元格的名称,在组内唯一(不同的参数组可以包含相同的参数名)。"
+#define L10N_TABLE_CELL_VAR_NAME_DUP "参数名已重复"
#define L10N_TABLE_CELL_VERTICAL_ALIGNMENT "垂直对齐"
#define L10N_TABLE_CELL_ALIGN_LEFT "左对齐"
#define L10N_TABLE_CELL_ALIGN_CENTER "居中"
diff --git a/core/src/Model/Template/TableTemplate.cpp b/core/src/Model/Template/TableTemplate.cpp
index be61606..88980ae 100644
--- a/core/src/Model/Template/TableTemplate.cpp
+++ b/core/src/Model/Template/TableTemplate.cpp
@@ -34,26 +34,30 @@ int TableCellArrayGroup::GetCount() const
return RightCell - LeftCell + 1;
}
-TableInstanciationParameters::TableInstanciationParameters(const TableTemplate& table)
+Vec2i TableCellArrayGroup::FindCell(std::string_view name)
+{
+}
+
+TableInstantiationParameters::TableInstantiationParameters(const TableTemplate& table)
: mTable{ &table }
{
}
-TableInstanciationParameters& TableInstanciationParameters::ResetTable(const TableTemplate& newTable)
+TableInstantiationParameters& TableInstantiationParameters::ResetTable(const TableTemplate& newTable)
{
mTable = &newTable;
return *this;
}
-TableInstanciationParameters TableInstanciationParameters::RebindTable(const TableTemplate& newTable) const
+TableInstantiationParameters TableInstantiationParameters::RebindTable(const TableTemplate& newTable) const
{
- TableInstanciationParameters result(newTable);
+ TableInstantiationParameters result(newTable);
result.SingularCells = this->SingularCells;
result.ArrayGroups = this->ArrayGroups;
return result;
}
-const TableTemplate& TableInstanciationParameters::GetTable() const
+const TableTemplate& TableInstantiationParameters::GetTable() const
{
return *mTable;
}
@@ -142,6 +146,102 @@ TableCell& TableTemplate::GetCell(Vec2i pos)
return const_cast<TableCell&>(const_cast<const TableTemplate*>(this)->GetCell(pos));
}
+void TableTemplate::SetCellType(Vec2i pos, TableCell::CellType type)
+{
+ auto& cell = GetCell(pos);
+ if (cell.Type == type) {
+ return;
+ }
+
+ switch (type) {
+ case TableCell::ConstantCell: {
+ // TODO
+ } break;
+
+ case TableCell::SingularParametricCell: {
+ cell.Type = type;
+ } break;
+
+ // Setting the cell to be a part of a group requires calling the overload that supplies the group
+ case TableCell::ArrayParametricCell: break;
+ }
+}
+
+int TableTemplate::GetArrayGroupCount() const
+{
+ return mArrayGroups.size();
+}
+
+const TableCellArrayGroup& TableTemplate::GetArrayGroup(int id) const
+{
+ return mArrayGroups[id];
+}
+
+TableCellArrayGroup& TableTemplate::GetArrayGroup(int id)
+{
+ return mArrayGroups[id];
+}
+
+TableCellArrayGroup& TableTemplate::AddArrayGroup(int row, int left, int right)
+{
+ assert(row >= 0 && row < GetTableHeight());
+ assert(left >= 0 && left < GetTableWidth());
+ assert(right >= 0 && right < GetTableWidth());
+
+ // TODO check for overlap
+
+ if (left > right) {
+ std::swap(left, right);
+ }
+
+ mArrayGroups.push_back(TableCellArrayGroup{
+ .Row = row,
+ .LeftCell = left,
+ .RightCell = right,
+ });
+ return mArrayGroups.back();
+}
+
+bool TableTemplate::ExtendArrayGroupLeft(int id, int n)
+{
+ assert(n > 0);
+
+ auto& ag = mArrayGroups[id];
+ ag.LeftCell -= n;
+
+ return false;
+}
+
+bool TableTemplate::ExtendArrayGroupRight(int id, int n)
+{
+ assert(n > 0);
+
+ auto& ag = mArrayGroups[id];
+ ag.RightCell += n;
+
+ return false;
+}
+
+TableCell* TableTemplate::FindCell(std::string_view name)
+{
+ auto iter = mName2Parameters.find(name);
+ if (iter != mName2Parameters.end()) {
+ return &mCells[iter.value()];
+ } else {
+ return nullptr;
+ }
+}
+
+TableCellArrayGroup* TableTemplate::FindArrayGroup(std::string_view name)
+{
+ auto iter = mName2ArrayGroups.find(name);
+ if (iter != mName2ArrayGroups.end()) {
+ return &mArrayGroups[iter.value()];
+ } else {
+ return nullptr;
+ }
+}
+
TableTemplate::MergeCellsResult TableTemplate::MergeCells(Vec2i topLeft, Vec2i bottomRight)
{
auto SortTwo = [](int& a, int& b) {
@@ -200,14 +300,14 @@ TableTemplate::BreakCellsResult TableTemplate::BreakCells(Vec2i topLeft)
return BCR_Success;
}
-lxw_workbook* TableTemplate::InstantiateToExcelWorkbook(const TableInstanciationParameters& params) const
+lxw_workbook* TableTemplate::InstantiateToExcelWorkbook(const TableInstantiationParameters& params) const
{
auto workbook = workbook_new("Table.xlsx");
InstantiateToExcelWorksheet(workbook, params);
return workbook;
}
-lxw_worksheet* TableTemplate::InstantiateToExcelWorksheet(lxw_workbook* workbook, const TableInstanciationParameters& params) const
+lxw_worksheet* TableTemplate::InstantiateToExcelWorksheet(lxw_workbook* workbook, const TableInstantiationParameters& params) const
{
auto worksheet = workbook_add_worksheet(workbook, "CpltExport.xlsx");
diff --git a/core/src/Model/Template/TableTemplate.hpp b/core/src/Model/Template/TableTemplate.hpp
index ed1a96f..754ebe1 100644
--- a/core/src/Model/Template/TableTemplate.hpp
+++ b/core/src/Model/Template/TableTemplate.hpp
@@ -5,8 +5,10 @@
#include "Utils/VectorHash.hpp"
#include "cplt_fwd.hpp"
+#include <tsl/array_map.h>
#include <tsl/robin_map.h>
#include <string>
+#include <string_view>
#include <vector>
class TableCell
@@ -80,11 +82,13 @@ public:
/// \endcode
///
/// \see TableCell
-/// \see TableInstanciationParameters
+/// \see TableInstantiationParameters
/// \see TableTemplate
class TableCellArrayGroup
{
public:
+ /// Parameter name mapped to cell location (index from LeftCell).
+ tsl::array_map<char, int> mName2Cell;
int Row;
/// Leftmost cell in this group
int LeftCell;
@@ -95,6 +99,9 @@ public:
Vec2i GetLeftCell() const;
Vec2i GetRightCell() const;
int GetCount() const;
+
+ /// Find the location of the cell within this array group that has the given name.
+ Vec2i FindCell(std::string_view name);
};
// Forward declaration of libxlsxwriter structs
@@ -103,7 +110,7 @@ struct lxw_worksheet;
/// An object containing the necessary information to instanciate a table template.
/// \see TableTemplate
-class TableInstanciationParameters
+class TableInstantiationParameters
{
private:
const TableTemplate* mTable;
@@ -116,10 +123,10 @@ public:
std::vector<ArrayGroupData> ArrayGroups;
public:
- TableInstanciationParameters(const TableTemplate& table);
+ TableInstantiationParameters(const TableTemplate& table);
- TableInstanciationParameters& ResetTable(const TableTemplate& newTable);
- TableInstanciationParameters RebindTable(const TableTemplate& newTable) const;
+ TableInstantiationParameters& ResetTable(const TableTemplate& newTable);
+ TableInstantiationParameters RebindTable(const TableTemplate& newTable) const;
const TableTemplate& GetTable() const;
};
@@ -131,6 +138,10 @@ public:
class TableTemplate : public Template
{
private:
+ /// Map from parameter name to index of the parameter cell (stored in mCells).
+ tsl::array_map<char, int> mName2Parameters;
+ /// Map from array group name to the index of the array group (stored in mArrayGroups).
+ tsl::array_map<char, int> mName2ArrayGroups;
std::vector<TableCell> mCells;
std::vector<TableCellArrayGroup> mArrayGroups;
std::vector<int> mRowHeights;
@@ -151,6 +162,20 @@ public:
const TableCell& GetCell(Vec2i pos) const;
TableCell& GetCell(Vec2i pos);
+ void SetCellType(Vec2i pos, TableCell::CellType type);
+
+ int GetArrayGroupCount() const;
+ const TableCellArrayGroup& GetArrayGroup(int id) const;
+ TableCellArrayGroup& GetArrayGroup(int id);
+ TableCellArrayGroup& AddArrayGroup(int row, int left, int right);
+ bool ExtendArrayGroupLeft(int id, int n);
+ bool ExtendArrayGroupRight(int id, int n);
+
+ /// Find a singular parameter cell by its name. This does not include cells within an array group.
+ TableCell* FindCell(std::string_view name);
+
+ /// Find an array group by its name.
+ TableCellArrayGroup* FindArrayGroup(std::string_view name);
enum MergeCellsResult
{
@@ -166,8 +191,8 @@ public:
};
BreakCellsResult BreakCells(Vec2i topLeft);
- lxw_workbook* InstantiateToExcelWorkbook(const TableInstanciationParameters& params) const;
- lxw_worksheet* InstantiateToExcelWorksheet(lxw_workbook* workbook, const TableInstanciationParameters& params) const;
+ lxw_workbook* InstantiateToExcelWorkbook(const TableInstantiationParameters& params) const;
+ lxw_worksheet* InstantiateToExcelWorksheet(lxw_workbook* workbook, const TableInstantiationParameters& params) const;
virtual ReadResult ReadFrom(std::istream& stream) override;
virtual void WriteTo(std::ostream& stream) const override;
diff --git a/core/src/Model/Template/fwd.hpp b/core/src/Model/Template/fwd.hpp
index b0acb28..b918755 100644
--- a/core/src/Model/Template/fwd.hpp
+++ b/core/src/Model/Template/fwd.hpp
@@ -3,7 +3,7 @@
// TableTemplate.hpp
class TableCell;
class TableCellArrayGroup;
-class TableInstanciationParameters;
+class TableInstantiationParameters;
class TableTemplate;
// Template.hpp
diff --git a/core/src/UI/UI.hpp b/core/src/UI/UI.hpp
index 0a80b4c..b0f0a6f 100644
--- a/core/src/UI/UI.hpp
+++ b/core/src/UI/UI.hpp
@@ -13,6 +13,8 @@ void PopDisabled();
bool Button(const char* label, bool disabled);
bool Button(const char* label, const ImVec2& sizeArg, bool disabled);
+bool MenuItemConditional(const char* name, bool disabled);
+
void ErrorIcon();
void ErrorMessage(const char* fmt, ...);
void WarningIcon();
diff --git a/core/src/UI/UI_Templates.cpp b/core/src/UI/UI_Templates.cpp
index ab9c317..e77bef3 100644
--- a/core/src/UI/UI_Templates.cpp
+++ b/core/src/UI/UI_Templates.cpp
@@ -25,6 +25,10 @@ public:
virtual void Display() = 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:
@@ -38,9 +42,41 @@ private:
};
std::vector<UICell> mUICells;
+ struct UIArrayGroup
+ {
+ ImVec2 Pos;
+ ImVec2 Size;
+ };
+ std::vector<UIArrayGroup> mUIArrayGroups;
+
+ /* Selection range */
Vec2i mSelectionTL;
Vec2i mSelectionBR;
+ /* Selection states */
+ union
+ {
+ /// "CS" stands for "Constant cell selection States"
+ struct
+ {
+ } mCS{}; // Initialize to this element
+
+ /// "SS" stands for "Singular parameter selection States".
+ struct
+ {
+ bool ErrorDuplicateVarName;
+ bool HasLeftAG;
+ bool HasRightAG;
+ } mSS;
+
+ /// "AS" stands for "Array group parameter selection States".
+ struct
+ {
+ bool ErrorDuplicateVarName;
+ } mAS;
+ };
+
+ /* Table states */
bool mDirty = false;
bool mFirstDraw = true;
@@ -75,15 +111,38 @@ public:
{
mTable->Resize(width, height);
mUICells.resize(width * height);
+ mUIArrayGroups.resize(mTable->GetArrayGroupCount());
+
+ 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 = 0;
+ for (int x = 0; x < ag.LeftCell; ++x) {
+ uag.Pos.x += mTable->GetColumnWidth(x) + itemSpacing.x;
+ }
+ uag.Pos.y = 0;
+ for (int y = 0; y < ag.Row; ++y) {
+ uag.Pos.y += mTable->GetRowHeight(y) + 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);
+ }
+ }
}
private:
void DisplayInspector()
{
+ // This is an id, no need to localize
if (ImGui::BeginTabBar("Inspector")) {
- if (ImGui::BeginTabItem("Cell")) {
+ if (ImGui::BeginTabItem(I18N_TEXT("Cell", L10N_TABLE_CELL))) {
if (!IsSelected()) {
- ImGui::Text("Select a cell to edit");
+ ImGui::Text(I18N_TEXT("Select a cell to edit", L10N_TABLE_CELL_SELECT_MSG));
} else if (mSelectionTL == mSelectionBR) {
auto& selectCell = mTable->GetCell(mSelectionTL);
DisplayCellProperties(mSelectionTL);
@@ -93,8 +152,8 @@ private:
ImGui::EndTabItem();
}
- if (ImGui::BeginTabItem("Table")) {
- DisplayTableInspector();
+ if (ImGui::BeginTabItem(I18N_TEXT("Table", L10N_TABLE))) {
+ DisplayTableProperties();
ImGui::EndTabItem();
}
@@ -107,6 +166,36 @@ private:
auto& cell = mTable->GetCell(pos);
auto& uiCell = mUICells[pos.y * mTable->GetTableWidth() + pos.x];
+ if (ImGui::Button(I18N_TEXT("Convert to...", L10N_TABLE_CELL_CONV))) {
+ ImGui::OpenPopup("ConvertCtxMenu");
+ }
+ if (ImGui::BeginPopup("ConvertCtxMenu")) {
+ if (ImGui::MenuItem(I18N_TEXT("Single parameter", L10N_TABLE_CELL_CONV_PARAM))) {
+ mTable->SetCellType(pos, TableCell::SingularParametricCell);
+ }
+
+ bool createDisabled = cell.Type == TableCell::ArrayParametricCell;
+ if (ImGui::MenuItemConditional(I18N_TEXT("Create array group", L10N_TABLE_CELL_CONV_CREATE_AG), createDisabled)) {
+ mTable->AddArrayGroup(pos.x, pos.x, pos.y);
+ }
+
+ bool leftDisabled = !mSS.HasLeftAG || cell.Type == TableCell::ArrayParametricCell;
+ if (ImGui::MenuItemConditional(I18N_TEXT("Add to array group to the left", L10N_TABLE_CELL_CONV_ADD_AG_LEFT), leftDisabled)) {
+ auto& leftCell = mTable->GetCell((Vec2i){ pos.x - 1, pos.y });
+ mTable->ExtendArrayGroupRight(leftCell.DataId, 1);
+ }
+
+ bool rightDisabled = !mSS.HasRightAG || cell.Type == TableCell::ArrayParametricCell;
+ if (ImGui::MenuItemConditional(I18N_TEXT("Add to array group to the right", L10N_TABLE_CELL_CONV_ADD_AG_RIGHT), rightDisabled)) {
+ auto& rightCell = mTable->GetCell((Vec2i){ pos.x + 1, pos.y });
+ mTable->ExtendArrayGroupLeft(rightCell.DataId, 1);
+ }
+
+ 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);
@@ -162,20 +251,31 @@ private:
case TableCell::SingularParametricCell:
if (ImGui::InputText(I18N_TEXT("Variable name", L10N_TABLE_CELL_VAR_NAME), &cell.Content)) {
- // TODO validate if name is repeat
+ auto c = mTable->FindCell(cell.Content);
+ mSS.ErrorDuplicateVarName = c != nullptr;
}
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), &cell.Content)) {
- // TODO validate if name is repeat
+ auto ag = mTable->GetArrayGroup(cell.DataId);
+ auto cl = ag.FindCell(cell.Content);
+ mAS.ErrorDuplicateVarName = cl.x != -1 && cl.y != -1;
}
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));
}
+
+ if (mAS.ErrorDuplicateVarName) {
+ ImGui::ErrorMessage(I18N_TEXT("Variable name duplicated.", L10N_TABLE_CELL_VAR_NAME_DUP));
+ }
break;
}
}
@@ -185,7 +285,7 @@ private:
// TODO
}
- void DisplayTableInspector()
+ void DisplayTableProperties()
{
// TODO
}
@@ -193,6 +293,7 @@ private:
void DisplayTable()
{
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 8));
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 8));
ImGui::BeginChild("TableTemplate");
auto regularColor = ImGui::GetColorU32(ImGuiCol_Button);
@@ -222,7 +323,6 @@ private:
window->DC.CursorPos + ImGui::CalcItemSize(size, 0.0f, 0.0f),
};
- // TODO draw indicator for parameter cells
/* Draw cell body */
if (uiCell.Selected) {
@@ -242,6 +342,22 @@ private:
window->DrawList->AddRectFilled(rect.Min, rect.Max, color);
}
+ /* Draw cell type indicator */
+ switch (cell.Type) {
+ // No indicator
+ case TableCell::ConstantCell: break;
+
+ case TableCell::SingularParametricCell:
+ window->DrawList->AddRect(
+ rect.Min - ImVec2(1, 1),
+ rect.Max + ImVec2(1, 1),
+ kSingleParamOutline);
+ break;
+
+ // Drawn separately in loop below
+ case TableCell::ArrayParametricCell: break;
+ }
+
/* Draw cell content */
auto content = cell.Content.c_str();
@@ -283,8 +399,15 @@ private:
}
}
+ for (auto& uag : mUIArrayGroups) {
+ ImGui::GetCurrentWindow()->DrawList->AddRect(
+ uag.Pos - ImVec2(1, 1),
+ uag.Pos + uag.Size + ImVec2(1, 1),
+ kArrayGroupOutline);
+ }
+
ImGui::EndChild();
- ImGui::PopStyleVar();
+ ImGui::PopStyleVar(2);
}
template <class TFunction>
@@ -314,6 +437,13 @@ private:
mSelectionTL = { -1, -1 };
mSelectionBR = { -1, -1 };
+
+ ResetCS();
+ }
+
+ void ResetCS()
+ {
+ mCS = {};
}
void SelectRange(Vec2i p1, Vec2i p2)
@@ -334,6 +464,16 @@ private:
auto& uiCell = mUICells[i];
uiCell.Selected = true;
});
+
+ ResetAS();
+ }
+
+ void ResetSS(Vec2i pos)
+ {
+ mSS = {};
+ mSS.ErrorDuplicateVarName = false;
+ mSS.HasLeftAG = pos.x >= 1;
+ mSS.HasRightAG = pos.x < mTable->GetTableWidth();
}
void SelectCell(Vec2i cell)
@@ -345,6 +485,14 @@ private:
int i = cell.y * mTable->GetTableWidth() + cell.x;
mUICells[i].Selected = true;
+
+ ResetSS(cell);
+ }
+
+ void ResetAS()
+ {
+ mAS = {};
+ mAS.ErrorDuplicateVarName = false;
}
};
diff --git a/core/src/UI/UI_Utils.cpp b/core/src/UI/UI_Utils.cpp
index e3ac097..0dcde8f 100644
--- a/core/src/UI/UI_Utils.cpp
+++ b/core/src/UI/UI_Utils.cpp
@@ -44,6 +44,15 @@ bool ImGui::Button(const char* label, const ImVec2& sizeArg, bool disabled)
return res;
}
+bool ImGui::MenuItemConditional(const char* name, bool disabled)
+{
+ if (disabled) PushDisabled();
+ bool res = MenuItem(name, nullptr, false, disabled);
+ if (disabled) PopDisabled();
+
+ return res;
+}
+
void ImGui::ErrorIcon()
{
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4{ 237 / 255.0f, 67 / 255.0f, 55 / 255.0f, 1.0f }); // #ED4337