diff options
-rw-r--r-- | core/CMakeLists.txt | 5 | ||||
-rw-r--r-- | core/src/Model/Template/TableTemplate.cpp | 119 | ||||
-rw-r--r-- | core/src/Model/Template/TableTemplate.hpp | 89 | ||||
-rw-r--r-- | core/src/Model/Template/fwd.hpp | 7 | ||||
-rw-r--r-- | core/src/Model/Workflow/Workflow.hpp | 4 | ||||
-rw-r--r-- | core/src/Model/Workflow/Workflow_Main.cpp | 4 | ||||
-rw-r--r-- | core/src/Model/fwd.hpp | 1 | ||||
-rw-r--r-- | core/src/Utils/Hash.hpp | 15 | ||||
-rw-r--r-- | core/src/Utils/Vector.hpp | 6 | ||||
-rw-r--r-- | core/src/Utils/VectorHash.hpp | 46 |
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; + } +}; |