#pragma once #include "Model/Template/Template.hpp" #include "Utils/Vector.hpp" #include "Utils/VectorHash.hpp" #include "cplt_fwd.hpp" #include #include #include #include #include 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, SingularParametricCell, ArrayParametricCell, }; public: /// Display content of this cell. This doesn't necessarily have to line up with the parameter name (if this cell is one). 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{ -1, -1 }; int SpanX = 0; int SpanY = 0; TextAlignment HorizontalAlignment = AlignCenter; TextAlignment VerticalAlignment = AlignCenter; CellType Type = ConstantCell; /// The id of the group description object, if this cell isn't a constant or singular parameter cell. Otherwise, this value is -1. int DataId = -1; public: /// Return whether this cell holds meaningful data, i.e. true when this cell is either unmerged or the primary cell of a merged range. bool IsDataHoldingCell() const; /// Return whether this cell is the primary (i.e. top left) cell of a merged range or not. bool IsPrimaryCell() const; /// Return whether this cell is a part of a merged range or not. Includes the primary cell. bool IsMergedCell() const; template void OperateIOProxy(TProxy& proxy); }; // TODO support reverse (bottom to top) filling order // TODO support horizontal filling order /// Parameter group information for a grouped array of cells. When instantiated, an array of 0 or more /// elements shall be provided by the user, which will replace the group of templated cells with a list /// of rows, each instantiated with the n-th element in the provided array. /// \code /// [["foo", "bar", "foobar"], /// ["a", "b", c"], /// ["1", "2", "3"], /// ["x", "y", "z"]] /// // ... may be more /// \endcode /// This would create 4 rows of data in the place of the original parameter group. /// /// If more than one array parameter groups are on the same row, they would share space between each other: /// \code /// | 2 elements was fed to it /// | | 1 element was fed to it /// V V /// {~~~~~~~~~~~~~~~~}{~~~~~~~~~~~~~~} /// +------+---------+---------------+ /// | Foo | Example | Another group | /// +------+---------+---------------+ /// | Cool | Example | | /// +------+---------+---------------+ /// \endcode /// /// \see TableCell /// \see TableInstantiationParameters /// \see TableTemplate class TableArrayGroup { public: /// Parameter name mapped to cell location (index from LeftCell). tsl::array_map mName2Cell; int Row; /// Leftmost cell in this group int LeftCell; /// Rightmost cell in this group int RightCell; 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); bool UpdateCellName(std::string_view oldName, std::string_view newName); template void OperateIOProxy(TProxy& proxy); }; // Forward declaration of libxlsxwriter structs struct lxw_workbook; struct lxw_worksheet; /// An object containing the necessary information to instantiate a table template. /// \see TableTemplate class TableInstantiationParameters { private: const TableTemplate* mTable; public: tsl::robin_map SingularCells; using ArrayGroupRow = std::vector; using ArrayGroupData = std::vector; std::vector ArrayGroups; public: TableInstantiationParameters(const TableTemplate& table); TableInstantiationParameters& ResetTable(const TableTemplate& newTable); TableInstantiationParameters RebindTable(const TableTemplate& newTable) const; const TableTemplate& GetTable() const; }; /// A table template, where individual cells can be filled by workflows instantiating this template. Merged cells, /// parametric rows/columns, and grids are also supported. /// /// This current supports exporting to xlsx files. class TableTemplate : public Template { friend class TableSingleParamsIter; friend class TableArrayGroupsIter; private: /// Map from parameter name to index of the parameter cell (stored in mCells). tsl::array_map mName2Parameters; /// Map from array group name to the index of the array group (stored in mArrayGroups). tsl::array_map mName2ArrayGroups; std::vector mCells; std::vector mArrayGroups; std::vector mRowHeights; std::vector mColumnWidths; public: static bool IsInstance(const Template* tmpl); TableTemplate(); int GetTableWidth() const; int GetTableHeight() const; void Resize(int newWidth, int newHeight); int GetRowHeight(int row) const; void SetRowHeight(int row, int height); int GetColumnWidth(int column) const; void SetColumnWidth(int column, int width); const TableCell& GetCell(Vec2i pos) const; TableCell& GetCell(Vec2i pos); ///
    ///
  • In case of becoming a SingularParametricCell: the parameter name is filled with TableCell::Content. ///
  • In case of becoming a ArrayGroupParametricCell: the array group name is automatically generated as the nth group it would be come. /// i.e., if there aRe currently 3 groups, the newly created group would be named "4". /// If this name collides with an existing group, hyphens \c - will be append to the name until no collision happens. ///
void SetCellType(Vec2i pos, TableCell::CellType type); /// Updates the parameter cell to a new name. Returns true on success and false on failure (param not found or name duplicates). bool UpdateParameterName(std::string_view oldName, std::string_view newName); int GetArrayGroupCount() const; const TableArrayGroup& GetArrayGroup(int id) const; TableArrayGroup& GetArrayGroup(int id); TableArrayGroup* AddArrayGroup(int row, int left, int right); TableArrayGroup* AddArrayGroup(std::string_view name, int row, int left, int right); bool UpdateArrayGroupName(std::string_view oldName, std::string_view newName); 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. TableArrayGroup* FindArrayGroup(std::string_view name); enum MergeCellsResult { MCR_CellAlreadyMerged, MCR_Success, }; MergeCellsResult MergeCells(Vec2i topLeft, Vec2i bottomRight); enum BreakCellsResult { BCR_CellNotMerged, BCR_Success, }; BreakCellsResult BreakCells(Vec2i topLeft); lxw_workbook* InstantiateToExcelWorkbook(const TableInstantiationParameters& params) const; lxw_worksheet* InstantiateToExcelWorksheet(lxw_workbook* workbook, const TableInstantiationParameters& params) const; void ReadFromDataStream(InputDataStream& stream) override; void WriteToDataStream(OutputDataStream& stream) override; private: template void OperateIOProxy(TProxy& proxy); };