summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/CMakeLists.txt5
-rw-r--r--core/src/Model/Template/TableTemplate.cpp119
-rw-r--r--core/src/Model/Template/TableTemplate.hpp89
-rw-r--r--core/src/Model/Template/fwd.hpp7
-rw-r--r--core/src/Model/Workflow/Workflow.hpp4
-rw-r--r--core/src/Model/Workflow/Workflow_Main.cpp4
-rw-r--r--core/src/Model/fwd.hpp1
-rw-r--r--core/src/Utils/Hash.hpp15
-rw-r--r--core/src/Utils/Vector.hpp6
-rw-r--r--core/src/Utils/VectorHash.hpp46
10 files changed, 292 insertions, 4 deletions
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index eabd701..84f331e 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -40,6 +40,10 @@ add_source_group(MODEL_MODULE_SOURCES
src/Model/TransactionsModel.cpp
)
+add_source_group(MODEL_TEMPLATE_SOURCES
+ src/Model/Template/TableTemplate.cpp
+)
+
add_source_group(MODEL_WORKFLOW_MODULE_SOURCES
src/Model/Workflow/Evaluation.cpp
src/Model/Workflow/Value_Main.cpp
@@ -97,6 +101,7 @@ function(add_executable_variant TARGET_NAME)
add_executable(${TARGET_NAME}
${ENTRYPOINT_MODULE_SOURCES}
${MODEL_MODULE_SOURCES}
+ ${MODEL_TEMPLATE_SOURCES}
${MODEL_WORKFLOW_MODULE_SOURCES}
${MODEL_WORKFLOW_NODES_MODULE_SOURCES}
${MODEL_WORKFLOW_VALUES_MODULE_SOURCES}
diff --git a/core/src/Model/Template/TableTemplate.cpp b/core/src/Model/Template/TableTemplate.cpp
new file mode 100644
index 0000000..caf0e21
--- /dev/null
+++ b/core/src/Model/Template/TableTemplate.cpp
@@ -0,0 +1,119 @@
+#include "TableTemplate.hpp"
+
+bool TableCell::IsPrimaryCell() const
+{
+ return PrimaryCellLocation == Location;
+}
+
+bool TableCell::IsMergedCell() const
+{
+ return PrimaryCellLocation.x == -1 || PrimaryCellLocation.y == -1;
+}
+
+int TableTemplate::GetTableWidth() const
+{
+ return mTableWidth;
+}
+
+int TableTemplate::GetTableHeight() const
+{
+ return mTableHeight;
+}
+
+void TableTemplate::Resize(int newWidth, int newHeight)
+{
+ // TODO this doesn't gracefully handle resizing to a smaller size which trims some merged cells
+
+ std::vector<TableCell> cells;
+ cells.reserve(newWidth * newHeight);
+
+ int yEnd = std::min(mTableHeight, newHeight);
+ int xEnd = std::min(mTableWidth, newWidth);
+ for (int y = 0; y < yEnd; ++y) {
+ if (y >= mTableHeight) {
+ for (int x = 0; x < xEnd; ++x) {
+ cells.push_back(TableCell{});
+ }
+ continue;
+ }
+
+ for (int x = 0; x < xEnd; ++x) {
+ if (x >= mTableWidth) {
+ cells.push_back(TableCell{});
+ } else {
+ auto& cell = GetCell({ x, y });
+ cells.push_back(std::move(cell));
+ }
+ }
+ }
+
+ mCells = std::move(cells);
+}
+
+const TableCell& TableTemplate::GetCell(Vec2i pos) const
+{
+ return mCells[pos.y * mTableWidth + pos.x];
+}
+
+TableCell& TableTemplate::GetCell(Vec2i pos)
+{
+ return const_cast<TableCell&>(const_cast<const TableTemplate*>(this)->GetCell(pos));
+}
+
+TableTemplate::MergeCellsResult TableTemplate::MergeCells(Vec2i topLeft, Vec2i bottomRight)
+{
+ auto SortTwo = [](int& a, int& b) {
+ if (a > b) {
+ std::swap(a, b);
+ }
+ };
+ SortTwo(topLeft.x, bottomRight.x);
+ SortTwo(topLeft.y, bottomRight.y);
+
+ auto ResetProgress = [&]() {
+ for (int y = topLeft.y; y < bottomRight.y; ++y) {
+ for (int x = topLeft.x; x < bottomRight.x; ++x) {
+ auto& cell = GetCell({ x, y });
+ cell.PrimaryCellLocation = { -1, -1 };
+ }
+ }
+ };
+
+ for (int y = topLeft.y; y < bottomRight.y; ++y) {
+ for (int x = topLeft.x; x < bottomRight.x; ++x) {
+ auto& cell = GetCell({ x, y });
+ if (cell.IsMergedCell()) {
+ ResetProgress();
+ return MCR_CellAlreadyMerged;
+ }
+
+ cell.PrimaryCellLocation = topLeft;
+ }
+ }
+
+ auto& primaryCell = GetCell(topLeft);
+ primaryCell.SpanX = bottomRight.x - topLeft.x;
+ primaryCell.SpanY = bottomRight.y - topLeft.y;
+
+ return MCR_Success;
+}
+
+TableTemplate::BreakCellsResult TableTemplate::BreakCells(Vec2i topLeft)
+{
+ auto& primaryCell = GetCell(topLeft);
+ if (!primaryCell.IsMergedCell()) {
+ return BCR_CellNotMerged;
+ }
+
+ for (int dy = 0; dy < primaryCell.SpanY; ++dy) {
+ for (int dx = 0; dx < primaryCell.SpanX; ++dx) {
+ auto& cell = GetCell({ topLeft.x + dx, topLeft.y + dy });
+ cell.PrimaryCellLocation = { -1, -1 };
+ }
+ }
+
+ primaryCell.SpanX = 1;
+ primaryCell.SpanY = 1;
+
+ return BCR_Success;
+}
diff --git a/core/src/Model/Template/TableTemplate.hpp b/core/src/Model/Template/TableTemplate.hpp
new file mode 100644
index 0000000..d704b1f
--- /dev/null
+++ b/core/src/Model/Template/TableTemplate.hpp
@@ -0,0 +1,89 @@
+#pragma once
+
+#include "Utils/Vector.hpp"
+#include "Utils/VectorHash.hpp"
+
+#include <string>
+#include <vector>
+
+class TableCell
+{
+public:
+ enum TextAlignment
+ {
+ /// For horizontal alignment, this means align left. For vertical alignment, this means align top.
+ AlignAxisMin,
+ /// Align middle of the text to the middle of the axis.
+ AlignCenter,
+ /// For horizontal alignment, this means align right. For vertical alignment, this means align bottom.
+ AlignAxisMax,
+ };
+
+ enum CellType
+ {
+ ConstantCell,
+ ParametricCell,
+ };
+
+public:
+ std::string Content;
+ Vec2i Location;
+ /// Location of the primary (top left) cell, if this cell is a part of a merged group.
+ /// Otherwise, either component of this field shall be -1.
+ Vec2i PrimaryCellLocation;
+ int SpanX;
+ int SpanY;
+ TextAlignment HorizontalAlignment = AlignAxisMin;
+ TextAlignment VerticalAlignment = AlignAxisMin;
+ CellType Type;
+
+public:
+ bool IsPrimaryCell() const;
+ bool IsMergedCell() const;
+};
+
+class TableArrayParameterGroup
+{
+public:
+ enum ExpansionDirection
+ {
+ ExpandUp,
+ ExpandDown,
+ ExpandLeft,
+ ExpandRight,
+ };
+
+public:
+ ExpansionDirection ExpandDirection;
+};
+
+class TableTemplate
+{
+private:
+ std::vector<TableCell> mCells;
+ std::vector<TableArrayParameterGroup> mArrayGroups;
+ int mTableWidth;
+ int mTableHeight;
+
+public:
+ int GetTableWidth() const;
+ int GetTableHeight() const;
+ void Resize(int newWidth, int newHeight);
+
+ const TableCell& GetCell(Vec2i pos) const;
+ TableCell& GetCell(Vec2i pos);
+
+ enum MergeCellsResult
+ {
+ MCR_CellAlreadyMerged,
+ MCR_Success,
+ };
+ MergeCellsResult MergeCells(Vec2i topLeft, Vec2i bottomRight);
+
+ enum BreakCellsResult
+ {
+ BCR_CellNotMerged,
+ BCR_Success,
+ };
+ BreakCellsResult BreakCells(Vec2i topLeft);
+};
diff --git a/core/src/Model/Template/fwd.hpp b/core/src/Model/Template/fwd.hpp
new file mode 100644
index 0000000..2bf6814
--- /dev/null
+++ b/core/src/Model/Template/fwd.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+// TableTemplate.hpp
+class TableCell;
+class ConstantTableCell;
+class ParametricTableCell;
+class TableTemplate;
diff --git a/core/src/Model/Workflow/Workflow.hpp b/core/src/Model/Workflow/Workflow.hpp
index 847aa72..0aabcdc 100644
--- a/core/src/Model/Workflow/Workflow.hpp
+++ b/core/src/Model/Workflow/Workflow.hpp
@@ -263,8 +263,8 @@ public:
enum ReadResult
{
- ReadSuccess,
- ReadInvalidVersion,
+ RR_Success,
+ RR_InvalidVersion,
};
ReadResult ReadFrom(std::istream& stream);
void WriteTo(std::ostream& stream);
diff --git a/core/src/Model/Workflow/Workflow_Main.cpp b/core/src/Model/Workflow/Workflow_Main.cpp
index 1b50064..c9ae328 100644
--- a/core/src/Model/Workflow/Workflow_Main.cpp
+++ b/core/src/Model/Workflow/Workflow_Main.cpp
@@ -653,9 +653,9 @@ Workflow::ReadResult Workflow::ReadFrom(std::istream& stream)
switch (version) {
case 0: DeserializeV0(); break;
- default: return ReadInvalidVersion;
+ default: return RR_InvalidVersion;
}
- return ReadSuccess;
+ return RR_Success;
}
void Workflow::WriteTo(std::ostream& stream)
diff --git a/core/src/Model/fwd.hpp b/core/src/Model/fwd.hpp
index 594599c..6fa29c5 100644
--- a/core/src/Model/fwd.hpp
+++ b/core/src/Model/fwd.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include "Model/Template/fwd.hpp"
#include "Model/Workflow/fwd.hpp"
// Filter.hpp
diff --git a/core/src/Utils/Hash.hpp b/core/src/Utils/Hash.hpp
new file mode 100644
index 0000000..cf7713a
--- /dev/null
+++ b/core/src/Utils/Hash.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <cstddef>
+#include <functional>
+
+namespace HashUtils {
+
+template <class T>
+void Combine(size_t& seed, const T& v)
+{
+ std::hash<T> hasher;
+ seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+}
+
+} // namespace HashUtils
diff --git a/core/src/Utils/Vector.hpp b/core/src/Utils/Vector.hpp
index bf75fd1..f49965e 100644
--- a/core/src/Utils/Vector.hpp
+++ b/core/src/Utils/Vector.hpp
@@ -6,6 +6,8 @@ struct Vec2
T x = 0;
T y = 0;
+ friend constexpr bool operator==(const Vec2& a, const Vec2& b) = default;
+
friend constexpr Vec2 operator+(const Vec2& a, const Vec2& b) { return { a.x + b.x, a.y + b.y }; }
friend constexpr Vec2 operator-(const Vec2& a, const Vec2& b) { return { a.x - b.x, a.y - b.y }; }
friend constexpr Vec2 operator*(const Vec2& a, const Vec2& b) { return { a.x * b.x, a.y * b.y }; }
@@ -27,6 +29,8 @@ struct Vec3
T y = 0;
T z = 0;
+ friend constexpr bool operator==(const Vec3& a, const Vec3& b) = default;
+
friend constexpr Vec3 operator+(const Vec3& a, const Vec3& b) { return { a.x + b.x, a.y + b.y, a.z + b.z }; }
friend constexpr Vec3 operator-(const Vec3& a, const Vec3& b) { return { a.x - b.x, a.y - b.y, a.z - b.z }; }
friend constexpr Vec3 operator*(const Vec3& a, const Vec3& b) { return { a.x * b.x, a.y * b.y, a.z * b.z }; }
@@ -49,6 +53,8 @@ struct Vec4
T z = 0;
T w = 0;
+ friend constexpr bool operator==(const Vec4& a, const Vec4& b) = default;
+
friend constexpr Vec4 operator+(const Vec4& a, const Vec4& b) { return { a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
friend constexpr Vec4 operator-(const Vec4& a, const Vec4& b) { return { a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
friend constexpr Vec4 operator*(const Vec4& a, const Vec4& b) { return { a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
diff --git a/core/src/Utils/VectorHash.hpp b/core/src/Utils/VectorHash.hpp
new file mode 100644
index 0000000..7df9c35
--- /dev/null
+++ b/core/src/Utils/VectorHash.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "Utils/Hash.hpp"
+#include "Utils/Vector.hpp"
+
+#include <cstddef>
+#include <functional>
+
+template <class T>
+struct std::hash<Vec2<T>>
+{
+ size_t operator()(const Vec2<T>& vec) const
+ {
+ size_t result;
+ HashUtils::Combine(result, vec.x);
+ HashUtils::Combine(result, vec.y);
+ return result;
+ }
+};
+
+template <class T>
+struct std::hash<Vec3<T>>
+{
+ size_t operator()(const Vec3<T>& vec) const
+ {
+ size_t result;
+ HashUtils::Combine(result, vec.x);
+ HashUtils::Combine(result, vec.y);
+ HashUtils::Combine(result, vec.z);
+ return result;
+ }
+};
+
+template <class T>
+struct std::hash<Vec4<T>>
+{
+ size_t operator()(const Vec4<T>& vec) const
+ {
+ size_t result;
+ HashUtils::Combine(result, vec.x);
+ HashUtils::Combine(result, vec.y);
+ HashUtils::Combine(result, vec.z);
+ HashUtils::Combine(result, vec.w);
+ return result;
+ }
+};