From 8a3be2bac392db9005185fcaa1aeedb7f8dd0283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Thu, 5 Jul 2018 14:26:44 +0200 Subject: [PATCH] [poincare] LayoutReference::deleteBeforeCursor --- .../include/poincare/horizontal_layout_node.h | 3 ++ poincare/include/poincare/layout_cursor.h | 4 +- poincare/include/poincare/layout_node.h | 2 + poincare/include/poincare/layout_reference.h | 2 + poincare/src/horizontal_layout_node.cpp | 54 +++++++++++++++++++ poincare/src/layout_node.cpp | 42 +++++++++++++++ poincare/src/layout_reference.cpp | 1 + 7 files changed, 107 insertions(+), 1 deletion(-) diff --git a/poincare/include/poincare/horizontal_layout_node.h b/poincare/include/poincare/horizontal_layout_node.h index 8b60dbaea..9169daa21 100644 --- a/poincare/include/poincare/horizontal_layout_node.h +++ b/poincare/include/poincare/horizontal_layout_node.h @@ -17,8 +17,11 @@ public: m_numberOfChildren(0) {} + // Tree modification void addOrMergeChildAtIndex(LayoutNode * l, int index, bool removeEmptyChildren); void mergeChildrenAtIndex(HorizontalLayoutNode * horizontalLayout, int index, bool removeEmptyChildren); + void deleteBeforeCursor(LayoutCursor * cursor) override; + void removeChildAndMoveCursor(LayoutNode * l, LayoutCursor * cursor) override; // LayoutNode bool isHorizontal() const override { return true; } diff --git a/poincare/include/poincare/layout_cursor.h b/poincare/include/poincare/layout_cursor.h index 4733e9012..41afc22b0 100644 --- a/poincare/include/poincare/layout_cursor.h +++ b/poincare/include/poincare/layout_cursor.h @@ -108,9 +108,11 @@ public: void addEmptySquarePowerLayout() {} //TODO void addEmptyTenPowerLayout() {} //TODO void addEmptyMatrixLayout() {} //TODO - void performBackspace() {} //TODO bool showEmptyLayoutIfNeeded() { return false; } //TODO bool hideEmptyLayoutIfNeeded() { return false; } //TODO + void performBackspace() { + m_layoutRef.deleteBeforeCursor(this); + } void insertText(const char * text); void addLayoutAndMoveCursor(LayoutRef l); void clearLayout(); diff --git a/poincare/include/poincare/layout_node.h b/poincare/include/poincare/layout_node.h index dadc3c457..88e055c34 100644 --- a/poincare/include/poincare/layout_node.h +++ b/poincare/include/poincare/layout_node.h @@ -71,6 +71,8 @@ public: // Tree modification void addSibling(LayoutCursor * cursor, LayoutNode * sibling); void addSiblingAndMoveCursor(LayoutCursor * cursor, LayoutNode * sibling); + virtual void removeChildAndMoveCursor(LayoutNode * l, LayoutCursor * cursor); + virtual void deleteBeforeCursor(LayoutCursor * cursor); void collapseSiblingsAndMoveCursor(LayoutCursor * cursor) {} //TODO bool removeGreySquaresFromAllMatrixAncestors() { return false; } //TODO bool addGreySquaresToAllMatrixAncestors() { return false; } //TODO diff --git a/poincare/include/poincare/layout_reference.h b/poincare/include/poincare/layout_reference.h index 6bc059334..1129194e9 100644 --- a/poincare/include/poincare/layout_reference.h +++ b/poincare/include/poincare/layout_reference.h @@ -46,6 +46,7 @@ public: char XNTChar() const { return this->typedNode()->XNTChar(); } // Layout modification + void deleteBeforeCursor(LayoutCursor * cursor) { return this->typedNode()->deleteBeforeCursor(cursor); } bool removeGreySquaresFromAllMatrixAncestors() { return this->typedNode()->removeGreySquaresFromAllMatrixAncestors(); } bool addGreySquaresToAllMatrixAncestors() { return this->typedNode()->addGreySquaresToAllMatrixAncestors(); } LayoutReference layoutToPointWhenInserting() { return LayoutReference(this->typedNode()->layoutToPointWhenInserting()); } @@ -68,6 +69,7 @@ public: } void addSibling(LayoutCursor * cursor, LayoutReference sibling) { return this->typedNode()->addSibling(cursor, sibling.typedNode()); } void addSiblingAndMoveCursor(LayoutCursor * cursor, LayoutReference sibling) { return this->typedNode()->addSiblingAndMoveCursor(cursor, sibling.typedNode()); } + void removeChildAndMoveCursor(LayoutReference l, LayoutCursor * cursor) { return this->typedNode()->removeChildAndMoveCursor(l.typedNode(), cursor); } void collapseSiblingsAndMoveCursor(LayoutCursor * cursor) {} //TODO LayoutReference replaceWithJuxtapositionOf(LayoutReference leftChild, LayoutReference rightChild); //TODO diff --git a/poincare/src/horizontal_layout_node.cpp b/poincare/src/horizontal_layout_node.cpp index d2e961c74..5069327ce 100644 --- a/poincare/src/horizontal_layout_node.cpp +++ b/poincare/src/horizontal_layout_node.cpp @@ -25,6 +25,60 @@ void HorizontalLayoutNode::mergeChildrenAtIndex(HorizontalLayoutNode * h, int in LayoutRef(this).mergeChildrenAtIndex(LayoutRef(h), newIndex); } +void HorizontalLayoutNode::deleteBeforeCursor(LayoutCursor * cursor) { + LayoutNode * p = parent(); + if (p == nullptr + && cursor->layoutReference().node() == this + && (cursor->position() == LayoutCursor::Position::Left + || numberOfChildren() == 0)) + { + /* Case: Left and this is the main layout or Right and this is the main + * layout with no children. Return. */ + return; + } + if (cursor->position() == LayoutCursor::Position::Left) { + int indexOfPointedLayout = indexOfChild(cursor->layoutReference().typedNode()); + if (indexOfPointedLayout >= 0) { + /* Case: Left of a child. + * Point Right of the previous child. If there is no previous child, point + * Left of this. Perform another backspace. */ + if (indexOfPointedLayout == 0) { + cursor->setLayoutNode(this); + } else { + assert(indexOfPointedLayout > 0); + cursor->setLayoutNode(childAtIndex(indexOfPointedLayout - 1)); + cursor->setPosition(LayoutCursor::Position::Right); + } + cursor->performBackspace(); + return; + } + } + assert(cursor->layoutReference().node() == this); + if (cursor->position() == LayoutCursor::Position::Right) { + // Case: Right. Point to the last child and perform backspace. + cursor->setLayoutNode(childAtIndex(numberOfChildren() - 1)); + cursor->performBackspace(); + return; + } + LayoutNode::deleteBeforeCursor(cursor); +} + +void HorizontalLayoutNode::removeChildAndMoveCursor(LayoutNode * l, LayoutCursor * cursor) { + if (numberOfChildren() == 1) { + assert(childAtIndex(0) == l); + LayoutNode * p = parent(); + if (p != nullptr) { + p->removeChildAndMoveCursor(this, cursor); + } else { + removeChild(l); + cursor->setLayoutNode(this); + cursor->setPosition(LayoutCursor::Position::Left); + } + return; + } + LayoutNode::removeChildAndMoveCursor(l, cursor); +} + int HorizontalLayoutNode::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const { if (numberOfChildren() == 0) { if (bufferSize == 0) { diff --git a/poincare/src/layout_node.cpp b/poincare/src/layout_node.cpp index bf5177fdb..d355a0cc6 100644 --- a/poincare/src/layout_node.cpp +++ b/poincare/src/layout_node.cpp @@ -81,6 +81,48 @@ void LayoutNode::addSiblingAndMoveCursor(LayoutCursor * cursor, LayoutNode * sib privateAddSibling(cursor, sibling, true); } +void LayoutNode::removeChildAndMoveCursor(LayoutNode * l, LayoutCursor * cursor) { + assert(hasChild(l)); + int index = indexOfChild(l); + removeChild(l); + if (index < numberOfChildren()) { + cursor->setLayoutNode(childAtIndex(index)); + cursor->setPosition(LayoutCursor::Position::Left); + } else { + int newPointedLayoutIndex = index - 1; + assert(newPointedLayoutIndex >= 0); + assert(newPointedLayoutIndex < numberOfChildren()); + cursor->setLayoutNode(childAtIndex(newPointedLayoutIndex)); + cursor->setPosition(LayoutCursor::Position::Right); + } +} + +void LayoutNode::deleteBeforeCursor(LayoutCursor * cursor) { + int indexOfPointedLayout = indexOfChild(cursor->layoutReference().typedNode()); + if (indexOfPointedLayout >= 0) { + // Case: The pointed layout is a child. Move Left. + assert(cursor->position() == LayoutCursor::Position::Left); + bool shouldRecomputeLayout = false; + cursor->moveLeft(&shouldRecomputeLayout); + return; + } + assert(cursor->layoutReference().node() == this); + LayoutNode * p = parent(); + // Case: this is the pointed layout. + if (p == nullptr) { + // Case: No parent. Return. + return; + } + if (cursor->position() == LayoutCursor::Position::Left) { + // Case: Left. Ask the parent. + p->deleteBeforeCursor(cursor); + return; + } + assert(cursor->position() == LayoutCursor::Position::Right); + // Case: Right. Delete the layout. + p->removeChildAndMoveCursor(this, cursor); +} + // Private void LayoutNode::privateAddSibling(LayoutCursor * cursor, LayoutNode * sibling, bool moveCursor) { diff --git a/poincare/src/layout_reference.cpp b/poincare/src/layout_reference.cpp index d701e7a41..787955725 100644 --- a/poincare/src/layout_reference.cpp +++ b/poincare/src/layout_reference.cpp @@ -17,6 +17,7 @@ TreeNode * LayoutRef::FailedAllocationStaticNode() { return &FailureNode; } +// Cursor template LayoutCursor LayoutReference::cursor() const { return LayoutCursor(this->typedNode());