diff --git a/poincare/include/poincare/layout_node.h b/poincare/include/poincare/layout_node.h index 0475c14ce..bfa3aaa9c 100644 --- a/poincare/include/poincare/layout_node.h +++ b/poincare/include/poincare/layout_node.h @@ -124,6 +124,7 @@ protected: // Tree Direct children() { return Direct(this); } + Direct childrenFromIndex(int i) { return Direct(this, i); } // Sizing and positioning virtual KDSize computeSize() = 0; diff --git a/poincare/include/poincare/tree_node.h b/poincare/include/poincare/tree_node.h index 26b9efb57..dc207e45f 100644 --- a/poincare/include/poincare/tree_node.h +++ b/poincare/include/poincare/tree_node.h @@ -98,7 +98,7 @@ public: template class Direct final { public: - Direct(const T * node) : m_node(const_cast(node)) {} + Direct(const T * node, int firstIndex = 0) : m_node(const_cast(node)), m_firstIndex(firstIndex) {} class Iterator : public TreeNode::Iterator { public: using TreeNode::Iterator::Iterator; @@ -107,10 +107,17 @@ public: return *this; } }; - Iterator begin() const { return Iterator(static_cast(m_node->next())); } + Iterator begin() const { + TreeNode * n = m_node->next(); + for (int i = 0; i < m_firstIndex; i++) { + n = n->nextSibling(); + } + return Iterator(static_cast(n)); + } Iterator end() const { return Iterator(static_cast(m_node->nextSibling())); } private: T * m_node; + int m_firstIndex; }; template @@ -155,6 +162,7 @@ protected: m_parentIdentifier(NoNodeIdentifier), m_referenceCounter(0) {} + private: void updateParentIdentifierInChildren() const { changeParentIdentifierInChildren(m_identifier); diff --git a/poincare/src/grid_layout.cpp b/poincare/src/grid_layout.cpp index 218ea48c0..f41270699 100644 --- a/poincare/src/grid_layout.cpp +++ b/poincare/src/grid_layout.cpp @@ -43,7 +43,8 @@ void GridLayoutNode::moveCursorRight(LayoutCursor * cursor, bool * shouldRecompu cursor->setLayoutNode(childAtIndex(0)); return; } - int childIndex = indexOfChild(cursor->layoutNode()); + LayoutNode * cursorNode = cursor->layoutNode(); + int childIndex = indexOfChild(cursorNode); if (childIndex >= 0 && cursor->position() == LayoutCursor::Position::Right) { // Case: The cursor points to a grid's child. if (childIsRightOfGrid(childIndex)) { @@ -52,7 +53,7 @@ void GridLayoutNode::moveCursorRight(LayoutCursor * cursor, bool * shouldRecompu return; } // Case: Right of another child. Go Left of its sibling on the right. - cursor->setLayoutNode(childAtIndex(childIndex + 1)); + cursor->setLayoutNode(static_cast(cursorNode->nextSibling())); cursor->setPosition(LayoutCursor::Position::Left); return; } @@ -66,10 +67,10 @@ void GridLayoutNode::moveCursorRight(LayoutCursor * cursor, bool * shouldRecompu void GridLayoutNode::moveCursorUp(LayoutCursor * cursor, bool * shouldRecomputeLayout, bool equivalentPositionVisited) { /* If the cursor is child that is not on the top row, move it inside its upper - * neighbour.*/ + * neighbour. */ int childIndex = m_numberOfColumns; - while (childIndex < numberOfChildren()) { - if (cursor->layoutNode()->hasAncestor(childAtIndex(childIndex), true)) { + for (LayoutNode * l : childrenFromIndex(childIndex)) { + if (cursor->layoutNode()->hasAncestor(l, true)) { childAtIndex(childIndex - m_numberOfColumns)->moveCursorUpInDescendants(cursor, shouldRecomputeLayout); return; } @@ -80,12 +81,16 @@ void GridLayoutNode::moveCursorUp(LayoutCursor * cursor, bool * shouldRecomputeL void GridLayoutNode::moveCursorDown(LayoutCursor * cursor, bool * shouldRecomputeLayout, bool equivalentPositionVisited) { int childIndex = 0; - while (childIndex < numberOfChildren() - m_numberOfColumns) { - if (cursor->layoutNode()->hasAncestor(childAtIndex(childIndex), true)) { + int maxIndex = numberOfChildren() - m_numberOfColumns; + for (LayoutNode * l : children()) { + if (cursor->layoutNode()->hasAncestor(l, true)) { childAtIndex(childIndex + m_numberOfColumns)->moveCursorDownInDescendants(cursor, shouldRecomputeLayout); return; } childIndex++; + if (childIndex >= maxIndex) { + break; + } } LayoutNode::moveCursorDown(cursor, shouldRecomputeLayout, equivalentPositionVisited); } @@ -191,17 +196,9 @@ KDCoordinate GridLayoutNode::computeBaseline() { } KDPoint GridLayoutNode::positionOfChild(LayoutNode * l) { - int rowIndex = 0; - int columnIndex = 0; - for (int i = 0; i < m_numberOfRows; i++) { - for (int j = 0; j < m_numberOfColumns; j++) { - if (l == childAtIndex(i*m_numberOfColumns+j)) { - rowIndex = i; - columnIndex = j; - break; - } - } - } + int childIndex = indexOfChild(l); + int rowIndex = rowAtChildIndex(childIndex); + int columnIndex = columnAtChildIndex(childIndex); KDCoordinate x = 0; for (int j = 0; j < columnIndex; j++) { x += columnWidth(j); @@ -218,21 +215,33 @@ KDPoint GridLayoutNode::positionOfChild(LayoutNode * l) { // Private KDCoordinate GridLayoutNode::rowBaseline(int i) { + assert(m_numberOfColumns > 0); KDCoordinate rowBaseline = 0; - for (int j = 0; j < m_numberOfColumns; j++) { - rowBaseline = maxCoordinate(rowBaseline, childAtIndex(i*m_numberOfColumns+j)->baseline()); + int j = 0; + for (LayoutNode * l : childrenFromIndex(i*m_numberOfColumns)) { + rowBaseline = maxCoordinate(rowBaseline, l->baseline()); + j++; + if (j >= m_numberOfColumns) { + break; + } } return rowBaseline; } KDCoordinate GridLayoutNode::rowHeight(int i) const { - KDCoordinate rowHeight = 0; - KDCoordinate baseline = const_cast(this)->rowBaseline(i); - for (int j = 0; j < m_numberOfColumns; j++) { - LayoutNode * currentChild = const_cast(this)->childAtIndex(i*m_numberOfColumns+j); - rowHeight = maxCoordinate(rowHeight, currentChild->layoutSize().height() - currentChild->baseline()); + KDCoordinate underBaseline = 0; + KDCoordinate aboveBaseline = 0; + int j = 0; + for (LayoutNode * l : const_cast(this)->childrenFromIndex(i*m_numberOfColumns)) { + KDCoordinate b = l->baseline(); + underBaseline = maxCoordinate(underBaseline, l->layoutSize().height() - b); + aboveBaseline = maxCoordinate(aboveBaseline, b); + j++; + if (j >= m_numberOfColumns) { + break; + } } - return baseline+rowHeight; + return aboveBaseline+underBaseline; } KDCoordinate GridLayoutNode::height() const { @@ -240,14 +249,22 @@ KDCoordinate GridLayoutNode::height() const { for (int i = 0; i < m_numberOfRows; i++) { totalHeight += rowHeight(i); } - totalHeight += maxCoordinate((m_numberOfRows-1)*k_gridEntryMargin, 0); + totalHeight += m_numberOfRows > 0 ? (m_numberOfRows-1)*k_gridEntryMargin : 0; return totalHeight; } KDCoordinate GridLayoutNode::columnWidth(int j) const { KDCoordinate columnWidth = 0; - for (int i = 0; i < m_numberOfRows; i++) { - columnWidth = maxCoordinate(columnWidth, const_cast(this)->childAtIndex(i*m_numberOfColumns+j)->layoutSize().width()); + int childIndex = j; + int lastIndex = (m_numberOfRows-1)*m_numberOfColumns + j; + for (LayoutNode * l : const_cast(this)->childrenFromIndex(j)) { + if (childIndex%m_numberOfColumns == j) { + columnWidth = maxCoordinate(columnWidth, l->layoutSize().width()); + if (childIndex >= lastIndex) { + break; + } + } + childIndex++; } return columnWidth; } @@ -257,7 +274,7 @@ KDCoordinate GridLayoutNode::width() const { for (int j = 0; j < m_numberOfColumns; j++) { totalWidth += columnWidth(j); } - totalWidth += maxCoordinate(0, (m_numberOfColumns-1)*k_gridEntryMargin); + totalWidth += m_numberOfColumns > 0 ? (m_numberOfColumns-1)*k_gridEntryMargin : 0; return totalWidth; } @@ -268,4 +285,4 @@ void GridLayout::setDimensions(int rows, int columns) { setNumberOfColumns(columns); } -} \ No newline at end of file +} diff --git a/poincare/src/matrix_layout.cpp b/poincare/src/matrix_layout.cpp index a5d565c6a..659b3682f 100644 --- a/poincare/src/matrix_layout.cpp +++ b/poincare/src/matrix_layout.cpp @@ -142,12 +142,17 @@ void MatrixLayoutNode::moveCursorVertically(VerticalDirection direction, LayoutC bool shouldRemoveGreySquares = false; int firstIndex = direction == VerticalDirection::Up ? 0 : numberOfChildren() - m_numberOfColumns; int lastIndex = direction == VerticalDirection::Up ? m_numberOfColumns : numberOfChildren(); - for (int childIndex = firstIndex; childIndex < lastIndex; childIndex++) { - if (cursor->layoutReference().hasAncestor(thisRef.childAtIndex(childIndex), true)) { + int i = firstIndex; + for (LayoutNode * l : childrenFromIndex(firstIndex)) { + if (i >= lastIndex) { + break; + } + if (cursor->layoutReference().node()->hasAncestor(l, true)) { // The cursor is leaving the matrix, so remove the grey squares. shouldRemoveGreySquares = true; break; } + i++; } GridLayoutNode::moveCursorVertically(direction, cursor, shouldRecomputeLayout, equivalentPositionVisited); if (cursor->isDefined() && shouldRemoveGreySquares) { @@ -160,30 +165,43 @@ void MatrixLayoutNode::moveCursorVertically(VerticalDirection direction, LayoutC // Private void MatrixLayoutNode::newRowOrColumnAtIndex(int index) { - assert(index >= 0 && index < m_numberOfColumns*m_numberOfRows); + assert(index >= 0 && index < m_numberOfColumns * m_numberOfRows); bool shouldAddNewRow = childIsBottomOfGrid(index); // We need to compute this boolean before modifying the layout int correspondingRow = rowAtChildIndex(index); if (childIsRightOfGrid(index)) { + assert(m_numberOfRows >= 2); // Color the grey EmptyLayouts of the column in yellow. int correspondingColumn = m_numberOfColumns - 1; - for (int i = 0; i < m_numberOfRows - 1; i++) { - LayoutNode * lastLayoutOfRow = childAtIndex(i*m_numberOfColumns+correspondingColumn); - if (lastLayoutOfRow->isEmpty()) { - if (!lastLayoutOfRow->isHorizontal()) { - static_cast(lastLayoutOfRow)->setColor(EmptyLayoutNode::Color::Yellow); - } else { - assert(lastLayoutOfRow->numberOfChildren() == 1); - static_cast(lastLayoutOfRow->childAtIndex(0))->setColor(EmptyLayoutNode::Color::Yellow); + int childIndex = correspondingColumn; + int maxIndex = (m_numberOfRows - 2)*m_numberOfColumns+correspondingColumn; + for (LayoutNode * lastLayoutOfRow : childrenFromIndex(correspondingColumn)) { + if (childIndex > maxIndex) { + break; + } + if (childIndex % m_numberOfColumns == correspondingColumn) { + if (lastLayoutOfRow->isEmpty()) { + if (!lastLayoutOfRow->isHorizontal()) { + static_cast(lastLayoutOfRow)->setColor(EmptyLayoutNode::Color::Yellow); + } else { + assert(lastLayoutOfRow->numberOfChildren() == 1); + static_cast(lastLayoutOfRow->childAtIndex(0))->setColor(EmptyLayoutNode::Color::Yellow); + } } } + childIndex++; } // Add a column of grey EmptyLayouts on the right. addEmptyColumn(EmptyLayoutNode::Color::Grey); } if (shouldAddNewRow) { + assert(m_numberOfColumns >= 2); // Color the grey EmptyLayouts of the row in yellow. - for (int i = 0; i < m_numberOfColumns - 1; i++) { - LayoutNode * lastLayoutOfColumn = childAtIndex(correspondingRow*m_numberOfColumns+i); + int childIndex = correspondingRow * m_numberOfColumns; + int maxIndex = correspondingRow * m_numberOfColumns + m_numberOfColumns - 2; + for (LayoutNode * lastLayoutOfColumn : childrenFromIndex(correspondingRow*m_numberOfColumns)) { + if (childIndex > maxIndex) { + break; + } if (lastLayoutOfColumn->isEmpty()) { if (!lastLayoutOfColumn->isHorizontal()) { static_cast(lastLayoutOfColumn)->setColor(EmptyLayoutNode::Color::Yellow); @@ -192,6 +210,7 @@ void MatrixLayoutNode::newRowOrColumnAtIndex(int index) { static_cast(lastLayoutOfColumn->childAtIndex(0))->setColor(EmptyLayoutNode::Color::Yellow); } } + childIndex++; } // Add a row of grey EmptyLayouts at the bottom. addEmptyRow(EmptyLayoutNode::Color::Grey); @@ -200,20 +219,30 @@ void MatrixLayoutNode::newRowOrColumnAtIndex(int index) { bool MatrixLayoutNode::isRowEmpty(int index) const { assert(index >= 0 && index < m_numberOfRows); - for (int i = index * m_numberOfColumns; i < (index+1) * m_numberOfColumns; i++) { - if (!const_cast(this)->childAtIndex(i)->isEmpty()) { + int i = index * m_numberOfColumns; + for (LayoutNode * l : const_cast(this)->childrenFromIndex(index * m_numberOfColumns)) { + if (i >= (index + 1) * m_numberOfColumns) { + break; + } + if (!l->isEmpty()) { return false; } + i++; } return true; } bool MatrixLayoutNode::isColumnEmpty(int index) const { assert(index >= 0 && index < m_numberOfColumns); - for (int i = index; i < m_numberOfRows * m_numberOfColumns; i+= m_numberOfColumns) { - if (!const_cast(this)->childAtIndex(i)->isEmpty()) { + int i = index; + for (LayoutNode * l : const_cast(this)->childrenFromIndex(index)) { + if (i > index + (m_numberOfRows - 1) * m_numberOfColumns) { + break; + } + if (i % m_numberOfColumns == index && !l->isEmpty()) { return false; } + i++; } return true; }