diff --git a/escher/src/layout_field.cpp b/escher/src/layout_field.cpp index 303f68bdb..dd400fbb9 100644 --- a/escher/src/layout_field.cpp +++ b/escher/src/layout_field.cpp @@ -469,21 +469,24 @@ bool LayoutField::privateHandleMoveEvent(Ion::Events::Event event, bool * should return false; } +bool eventIsSelection(Ion::Events::Event event) { + return event == Ion::Events::ShiftLeft || event == Ion::Events::ShiftRight || event == Ion::Events::ShiftUp || event == Ion::Events::ShiftDown; +} + bool LayoutField::privateHandleSelectionEvent(Ion::Events::Event event, bool * shouldRecomputeLayout) { LayoutCursor result; - if (event == Ion::Events::ShiftLeft || event == Ion::Events::ShiftRight) { + if (eventIsSelection(event)) { Layout addedSelection; - result = m_contentView.cursor()->selectAtDirection(event == Ion::Events::ShiftLeft ? LayoutCursor::MoveDirection::Left : LayoutCursor::MoveDirection::Right, shouldRecomputeLayout, &addedSelection); - if (!addedSelection.isUninitialized()) { //TODO LEA assert? - m_contentView.addSelection(addedSelection); - } else { + LayoutCursor::MoveDirection direction = event == Ion::Events::ShiftLeft ? LayoutCursor::MoveDirection::Left : + (event == Ion::Events::ShiftRight ? LayoutCursor::MoveDirection::Right : + (event == Ion::Events::ShiftUp ? LayoutCursor::MoveDirection::Up : + LayoutCursor::MoveDirection::Down)); + result = m_contentView.cursor()->selectAtDirection(direction, shouldRecomputeLayout, &addedSelection); + if (addedSelection.isUninitialized()) { return false; } - }/* else if (event == Ion::Events::ShiftUp) { - //TODO LEA result = m_contentView.cursor()->cursorAtDirection(LayoutCursor::MoveDirection::Up, shouldRecomputeLayout); - } else if (event == Ion::Events::ShiftDown) { - //TODO LEA result = m_contentView.cursor()->cursorAtDirection(LayoutCursor::MoveDirection::Down, shouldRecomputeLayout); - }*/ + m_contentView.addSelection(addedSelection); + } if (result.isDefined()) { m_contentView.setCursor(result); return true; diff --git a/poincare/include/poincare/layout_cursor.h b/poincare/include/poincare/layout_cursor.h index f78ddc1c3..0cc3fee2f 100644 --- a/poincare/include/poincare/layout_cursor.h +++ b/poincare/include/poincare/layout_cursor.h @@ -145,6 +145,8 @@ private: void privateAddEmptyPowerLayout(VerticalOffsetLayout v); bool baseForNewPowerLayout(); bool privateShowHideEmptyLayoutIfNeeded(bool show); + void selectLeftRight(bool right, bool * shouldRecomputeLayout, Layout * selection); + void selectUpDown(bool up, bool * shouldRecomputeLayout, Layout * selection); Layout m_layout; Position m_position; }; diff --git a/poincare/include/poincare/tree_handle.h b/poincare/include/poincare/tree_handle.h index 44690899c..254a78618 100644 --- a/poincare/include/poincare/tree_handle.h +++ b/poincare/include/poincare/tree_handle.h @@ -75,6 +75,7 @@ public: bool hasChild(TreeHandle t) const; bool hasSibling(TreeHandle t) const { return node()->hasSibling(t.node()); } bool hasAncestor(TreeHandle t, bool includeSelf) const { return node()->hasAncestor(t.node(), includeSelf); } + TreeHandle commonAncestorWith(TreeHandle t) const; int numberOfChildren() const { return node()->numberOfChildren(); } int indexOfChild(TreeHandle t) const; TreeHandle parent() const; diff --git a/poincare/src/layout_cursor.cpp b/poincare/src/layout_cursor.cpp index 94f95e771..ad9762255 100644 --- a/poincare/src/layout_cursor.cpp +++ b/poincare/src/layout_cursor.cpp @@ -80,56 +80,11 @@ bool IsBefore(Layout& l1, Layout& l2) { } void LayoutCursor::select(MoveDirection direction, bool * shouldRecomputeLayout, Layout * selection) { - assert(!m_layout.isUninitialized()); - - // Compute ingoing / outgoing positions - - Position ingoingPosition = direction == MoveDirection::Right ? Position::Left : Position::Right; - Position outgoingPosition = direction == MoveDirection::Right ? Position::Right : Position::Left; - - // Find the layout to select - - LayoutCursor equivalentCursor = m_layout.equivalentCursor(this); - Layout equivalentLayout = equivalentCursor.layoutReference(); - bool currentLayoutIsEmpty = m_layout.type() == LayoutNode::Type::EmptyLayout; - - if (!currentLayoutIsEmpty && m_position == ingoingPosition) { - /* The current cursor is positionned on the ingoing position, for instance - * left a layout if we want to select towards the right. */ - if (!equivalentLayout.isUninitialized() && m_layout.hasChild(equivalentLayout)) { - /* Put the cursor on the inner most equivalent ingoing position : for - * instance, in the layout |1234 , the cursor should be left of the 1, - * not left of the horizontal layout. */ - assert(equivalentCursor.position() == ingoingPosition); - *selection = equivalentLayout; - } else { - /* If there is no adequate equivalent position, just set the ingoing - * layout on the current layout. */ - *selection = m_layout; - } + if (direction == MoveDirection::Right || direction == MoveDirection::Left) { + selectLeftRight(direction == MoveDirection::Right, shouldRecomputeLayout, selection); } else { - assert(currentLayoutIsEmpty || m_position == outgoingPosition); - /* The cursor is on the outgoing position, for instance right of a layout - * when we want to select towards the right. */ - if (!currentLayoutIsEmpty && !equivalentLayout.isUninitialized() && equivalentCursor.position() == ingoingPosition) { - /* If there is an equivalent layout positionned on the ingoing position, - * select it. */ - *selection = equivalentLayout; - } else { - // Else, find the first non horizontal ancestor and select it. - Layout notHorizontalAncestor = m_layout.parent(); - while (!notHorizontalAncestor.isUninitialized() - && notHorizontalAncestor.type() == LayoutNode::Type::HorizontalLayout) - { - notHorizontalAncestor = notHorizontalAncestor.parent(); - } - if (!notHorizontalAncestor.isUninitialized()) { - *selection = notHorizontalAncestor; - } - } + selectUpDown(direction == MoveDirection::Up, shouldRecomputeLayout, selection); } - m_layout = *selection; - m_position = outgoingPosition; } /* Layout modification */ @@ -354,4 +309,69 @@ bool LayoutCursor::privateShowHideEmptyLayoutIfNeeded(bool show) { return true; } +void LayoutCursor::selectLeftRight(bool right, bool * shouldRecomputeLayout, Layout * selection) { + assert(!m_layout.isUninitialized()); + + // Compute ingoing / outgoing positions + Position ingoingPosition = right ? Position::Left : Position::Right; + Position outgoingPosition = right ? Position::Right : Position::Left; + + // Find the layout to select + + LayoutCursor equivalentCursor = m_layout.equivalentCursor(this); + Layout equivalentLayout = equivalentCursor.layoutReference(); + bool currentLayoutIsEmpty = m_layout.type() == LayoutNode::Type::EmptyLayout; + + if (!currentLayoutIsEmpty && m_position == ingoingPosition) { + /* The current cursor is positionned on the ingoing position, for instance + * left a layout if we want to select towards the right. */ + if (!equivalentLayout.isUninitialized() && m_layout.hasChild(equivalentLayout)) { + /* Put the cursor on the inner most equivalent ingoing position: for + * instance, in the layout |1234 , the cursor should be left of the 1, + * not left of the horizontal layout. */ + assert(equivalentCursor.position() == ingoingPosition); + *selection = equivalentLayout; + } else { + /* If there is no adequate equivalent position, just set the ingoing + * layout on the current layout. */ + *selection = m_layout; + } + } else { + assert(currentLayoutIsEmpty || m_position == outgoingPosition); + /* The cursor is on the outgoing position, for instance right of a layout + * when we want to select towards the right. */ + if (!currentLayoutIsEmpty && !equivalentLayout.isUninitialized() && equivalentCursor.position() == ingoingPosition) { + /* If there is an equivalent layout positionned on the ingoing position, + * select it. */ + *selection = equivalentLayout; + } else { + // Else, find the first non horizontal ancestor and select it. + Layout notHorizontalAncestor = m_layout.parent(); + while (!notHorizontalAncestor.isUninitialized() + && notHorizontalAncestor.type() == LayoutNode::Type::HorizontalLayout) + { + notHorizontalAncestor = notHorizontalAncestor.parent(); + } + if (!notHorizontalAncestor.isUninitialized()) { + *selection = notHorizontalAncestor; + } + } + } + m_layout = *selection; //TODO LEA remove selection param + m_position = outgoingPosition; +} + +void LayoutCursor::selectUpDown(bool up, bool * shouldRecomputeLayout, Layout * selection) { + LayoutCursor c = cursorAtDirection(up ? MoveDirection::Up : MoveDirection::Down, shouldRecomputeLayout); + if (!c.isDefined()) { + return; + } + /* Find the first common ancestor between the current layout and the layout of + * the moved cursor. */ + TreeHandle ancestor = m_layout.commonAncestorWith(c.layoutReference()); + *selection = static_cast(ancestor); + m_layout = *selection; + m_position = up ? Position::Left : Position::Right; +} + } diff --git a/poincare/src/tree_handle.cpp b/poincare/src/tree_handle.cpp index 75b371691..1a59ddddc 100644 --- a/poincare/src/tree_handle.cpp +++ b/poincare/src/tree_handle.cpp @@ -28,6 +28,20 @@ int TreeHandle::indexOfChild(TreeHandle t) const { return node()->indexOfChild(t bool TreeHandle::hasChild(TreeHandle t) const { return node()->hasChild(t.node()); } +TreeHandle TreeHandle::commonAncestorWith(TreeHandle t) const { + if (*(const_cast(this)) == t) { + return t; + } + TreeHandle p = *this; + while (!p.isUninitialized()) { + if (t.hasAncestor(p, true)) { + return p; + } + p = p.parent(); + } + return TreeHandle(); +} + TreeHandle TreeHandle::childAtIndex(int i) const { return TreeHandle(node()->childAtIndex(i)); } void TreeHandle::replaceWithInPlace(TreeHandle t) {