diff --git a/src/qanTableBorder.cpp b/src/qanTableBorder.cpp index 9be45c75..673bdd95 100644 --- a/src/qanTableBorder.cpp +++ b/src/qanTableBorder.cpp @@ -148,6 +148,8 @@ void TableBorder::layoutCells() // Layout prev/next cells position and size for (auto prevCell: _prevCells) { + if (prevCell == nullptr) + continue; prevCell->setWidth(vCenter - prevCell->x() - spacing2); if (!_prevBorder && // For first column, set cell x too (not prev border will do it). @@ -156,10 +158,12 @@ void TableBorder::layoutCells() } } for (auto nextCell: _nextCells) { + if (nextCell == nullptr) + continue; nextCell->setX(vCenter + spacing2); if (_nextBorder && _nextBorder->verticalCenter() > (x() + spacing)) // nextBorder might still not be initialized... - nextCell->setWidth(_nextBorder->verticalCenter() - x() - spacing); // FIXME #190 secure that + nextCell->setWidth(_nextBorder->verticalCenter() - x() - spacing); if (!_nextBorder && // For last column, set cell witdh too (no next border will do it). _tableGroup && tableGroupItem != nullptr) { @@ -172,6 +176,8 @@ void TableBorder::layoutCells() // Layout prev/next cells position and size for (auto prevCell: _prevCells) { + if (prevCell == nullptr) + continue; prevCell->setHeight(hCenter - prevCell->y() - spacing2); if (!_prevBorder && // For first column, set cell x too (not prev border will do it). @@ -180,10 +186,12 @@ void TableBorder::layoutCells() } } for (auto nextCell: _nextCells) { + if (nextCell == nullptr) + continue; nextCell->setY(hCenter + spacing2); if (_nextBorder && _nextBorder->horizontalCenter() > (y() + spacing)) // nextBorder might still not be initialized... - nextCell->setHeight(_nextBorder->horizontalCenter() - y() - spacing); // FIXME #190 secure that + nextCell->setHeight(_nextBorder->horizontalCenter() - y() - spacing); if (!_nextBorder && // For last column, set cell witdh too (no next border will do it). _tableGroup && tableGroupItem != nullptr) { diff --git a/src/qanTableGroupItem.cpp b/src/qanTableGroupItem.cpp index 79a3f2bf..4b63dbdb 100644 --- a/src/qanTableGroupItem.cpp +++ b/src/qanTableGroupItem.cpp @@ -60,10 +60,6 @@ TableGroupItem::~TableGroupItem() clearLayout(); } -void TableGroupItem::componentComplete() { /* Nil */ } - -void TableGroupItem::classBegin() { } - bool TableGroupItem::setContainer(QQuickItem* container) noexcept { qWarning() << "qan::TableGroupItem::setContainer(): container=" << container; @@ -164,6 +160,8 @@ void TableGroupItem::initialize(int cols, int rows) } borderComponent->deleteLater(); + + initializeTableLayout(); } void TableGroupItem::createCells(int cellsCount) @@ -300,9 +298,9 @@ auto TableGroupItem::createFromComponent(QQmlComponent& component) -> QQuickItem return item; }; -void TableGroupItem::layoutTable() +void TableGroupItem::initializeTableLayout() { - qWarning() << "qan::TableGroupItem::layoutTable()"; + qWarning() << "qan::TableGroupItem::initializeTableLayout()"; const auto tableGroup = getTableGroup(); if (tableGroup == nullptr) return; @@ -314,11 +312,11 @@ void TableGroupItem::layoutTable() 2.; if (cols <= 0 || rows <= 0) { - qWarning() << "qan::TableGroupItem::layoutTable(): Error, rows and columns count can't be <= 0."; + qWarning() << "qan::TableGroupItem::initializeTableLayout(): Error, rows and columns count can't be <= 0."; return; } if (spacing < 0 || padding < 0) { - qWarning() << "qan::TableGroupItem::layoutTable(): Error, padding and spacing can't be < 0."; + qWarning() << "qan::TableGroupItem::initializeTableLayout(): Error, padding and spacing can't be < 0."; return; } @@ -335,7 +333,7 @@ void TableGroupItem::layoutTable() //qWarning() << "cellHeight=" << cellHeight; if (cellWidth < 0. || cellHeight < 0.) { - qWarning() << "qan::TableGroupItem::layoutTable(): Error, invalid cell width/height."; + qWarning() << "qan::TableGroupItem::initializeTableLayout(): Error, invalid cell width/height."; return; } // Note: cells are laid out by their borders, do not set their geometry @@ -360,7 +358,7 @@ void TableGroupItem::layoutTable() verticalBorder->setHeight(height()); } } else - qWarning() << "qan::TableGoupItem::layoutTable(): Invalid vertical border count."; + qWarning() << "qan::TableGoupItem::initializeTableLayout(): Invalid vertical border count."; // Layout horizontal borders if (static_cast(_horizontalBorders.size()) == rows - 1) { @@ -378,12 +376,59 @@ void TableGroupItem::layoutTable() horizontalBorder->setHeight(borderHeight); } } else - qWarning() << "qan::TableGoupItem::layoutTable(): Invalid horizontal border count."; + qWarning() << "qan::TableGoupItem::initializeTableLayout(): Invalid horizontal border count."; // Note: There is no need to manually call borders layoutCells() method // it will be called automatically when border are moved. } +void TableGroupItem::layoutTable() +{ + // Adapt to a new (width, height), keep previous rows/columns ratio + // New position is: + // x = previousX * (actualWidth / previousWidth) + // y = previousY * (actualHeight / previousHeight) + if (_previousSize.isNull()) { + qWarning() << "qan::TableGroupItem::layoutTable(): Invalid initial size."; + _previousSize = size(); + return; + } + if (_previousSize == size()) + return; + + for (const auto verticalBorder: _verticalBorders) { + if (verticalBorder == nullptr) + continue; + const auto previousX = verticalBorder->x(); + verticalBorder->setX(qRound(previousX * width() / _previousSize.width())); + verticalBorder->setY(0.); + verticalBorder->setHeight(height()); + } + + for (const auto horizontalBorder: _horizontalBorders) { + if (horizontalBorder == nullptr) + continue; + const auto previousY = horizontalBorder->y(); + horizontalBorder->setX(0.); + horizontalBorder->setY(qRound(previousY * height() / _previousSize.height())); + horizontalBorder->setWidth(width()); + } + + _previousSize = size(); +} + +void TableGroupItem::layoutCells() +{ + for (const auto verticalBorder: _verticalBorders) { + if (verticalBorder != nullptr) + verticalBorder->layoutCells(); + } + for (const auto horizontalBorder: _horizontalBorders) { + if (horizontalBorder != nullptr) + horizontalBorder->layoutCells(); + } +} + bool TableGroupItem::setGroup(qan::Group* group) noexcept { if (qan::GroupItem::setGroup(group)) { @@ -402,11 +447,11 @@ bool TableGroupItem::setGroup(qan::Group* group) noexcept if (border) border->setTableGroup(tableGroup); connect(tableGroup, &qan::TableGroup::cellSpacingChanged, - this, &qan::TableGroupItem::layoutTable); + this, &qan::TableGroupItem::layoutCells); connect(tableGroup, &qan::TableGroup::cellMinimumSizeChanged, - this, &qan::TableGroupItem::layoutTable); + this, &qan::TableGroupItem::layoutCells); connect(tableGroup, &qan::TableGroup::tablePaddingChanged, - this, &qan::TableGroupItem::layoutTable); + this, &qan::TableGroupItem::layoutCells); // Set cell reference to group for (auto cell: _cells) @@ -449,6 +494,8 @@ void TableGroupItem::groupNodeItem(qan::NodeItem* nodeItem, qan::TableCell* g } else { // Find cell at groupPos and attach node to cell for (const auto& cell: _cells) { + if (cell == nullptr) + continue; const auto cellBr = cell->boundingRect().translated(cell->position()); if (cellBr.contains(groupPos)) { cell->setItem(nodeItem); @@ -465,7 +512,7 @@ void TableGroupItem::ungroupNodeItem(qan::NodeItem* nodeItem, bool transform) { if (nodeItem == nullptr) // A container must have configured in concrete QML group component return; - if (getGraph() && + if (getGraph() != nullptr && getGraph()->getContainerItem() != nullptr) { auto nodeCell = nodeItem->getNode()->getCell(); if (nodeCell != nullptr) { @@ -474,6 +521,7 @@ void TableGroupItem::ungroupNodeItem(qan::NodeItem* nodeItem, bool transform) nodeCell->restoreCache(nodeItem); nodeCell->setItem(nullptr); + nodeCell->setUserProp(QVariant{}); nodeItem->setParentItem(getGraph()->getContainerItem()); if (transform) nodeItem->setPosition(nodeGlobalPos + QPointF{10., 10.}); // A delta to visualize ungroup diff --git a/src/qanTableGroupItem.h b/src/qanTableGroupItem.h index 22b3eece..742228b4 100644 --- a/src/qanTableGroupItem.h +++ b/src/qanTableGroupItem.h @@ -50,7 +50,7 @@ class Graph; class TableGroup; class TableCell; -/*! \brief FIXME #190 +/*! \brief Visual delegate for qan::TableGroup, manage table layout, borders and cells. * * \nosubgrouping */ @@ -59,23 +59,18 @@ class TableGroupItem : public qan::GroupItem /*! \name TableGroupItem Object Management *///---------------------------- //@{ Q_OBJECT - Q_INTERFACES(QQmlParserStatus) public: explicit TableGroupItem(QQuickItem* parent = nullptr); virtual ~TableGroupItem() override; TableGroupItem(const TableGroupItem&) = delete; public: - //! QQmlParserStatus Component.onCompleted() overload to initialize default graph delegate in a valid QQmlEngine. - virtual void componentComplete() override; - - virtual void classBegin() override; - //! Override qan::GroupItem::setContainer() virtual bool setContainer(QQuickItem* container) noexcept override; signals: - void modified(); + //! Emitted when the table geometry has change (border modified for example). + void modified(); //@} //------------------------------------------------------------------------- @@ -91,13 +86,21 @@ class TableGroupItem : public qan::GroupItem void createCells(int cellsCount); void createBorders(int verticalBordersCount, int horizontalBordersCount); + protected: auto createFromComponent(QQmlComponent& component) -> QQuickItem*; +public: + void initializeTableLayout(); public slots: //! Layout current cell after a table geometry change. void layoutTable(); + //! Layout table cells, triggered when table style change. + void layoutCells(); +protected: + QSizeF _previousSize = QSizeF{0., 0.}; + public: virtual bool setGroup(qan::Group* group) noexcept override; protected: