From fccd9b484b810992fa0bde800cac5dd53a4e82d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9a=20Saviot?= Date: Fri, 22 Dec 2017 13:19:15 +0100 Subject: [PATCH] [poincare] Added UneditableHorizontalTrioLayout. Change-Id: Ifd9fd6a0a0714853c1a8cd428b65076b704a8211 --- poincare/Makefile | 1 + poincare/include/poincare_layouts.h | 1 + .../uneditable_horizontal_trio_layout.cpp | 156 ++++++++++++++++++ .../uneditable_horizontal_trio_layout.h | 42 +++++ 4 files changed, 200 insertions(+) create mode 100644 poincare/src/layout/uneditable_horizontal_trio_layout.cpp create mode 100644 poincare/src/layout/uneditable_horizontal_trio_layout.h diff --git a/poincare/Makefile b/poincare/Makefile index d20f96750..b49e17a2c 100644 --- a/poincare/Makefile +++ b/poincare/Makefile @@ -114,6 +114,7 @@ objs += $(addprefix poincare/src/layout/,\ static_layout_hierarchy.o\ string_layout.o\ sum_layout.o\ + uneditable_horizontal_trio_layout.o\ uneditable_parenthesis_left_layout.o\ uneditable_parenthesis_right_layout.o\ ) diff --git a/poincare/include/poincare_layouts.h b/poincare/include/poincare_layouts.h index f3d71feae..4c339e285 100644 --- a/poincare/include/poincare_layouts.h +++ b/poincare/include/poincare_layouts.h @@ -28,5 +28,6 @@ #include #include #include +#include #endif diff --git a/poincare/src/layout/uneditable_horizontal_trio_layout.cpp b/poincare/src/layout/uneditable_horizontal_trio_layout.cpp new file mode 100644 index 000000000..15b03993c --- /dev/null +++ b/poincare/src/layout/uneditable_horizontal_trio_layout.cpp @@ -0,0 +1,156 @@ +#include "uneditable_horizontal_trio_layout.h" +#include "empty_visible_layout.h" +#include +extern "C" { +#include +} + +namespace Poincare { + +ExpressionLayout * UneditableHorizontalTrioLayout::clone() const { + UneditableHorizontalTrioLayout * layout = new UneditableHorizontalTrioLayout( + const_cast(this)->leftLayout(), + const_cast(this)->centerLayout(), + const_cast(this)->rightLayout(), + true); + return layout; +} + +void UneditableHorizontalTrioLayout::backspaceAtCursor(ExpressionLayoutCursor * cursor) { + if (cursor->pointedExpressionLayout() == this + && cursor->position() == ExpressionLayoutCursor::Position::Right) + { + ExpressionLayout * previousParent = m_parent; + int indexInParent = previousParent->indexOfChild(this); + replaceWith(new EmptyVisibleLayout(), true); + if (indexInParent == 0) { + cursor->setPointedExpressionLayout(previousParent); + return; + } + cursor->setPointedExpressionLayout(previousParent->editableChild(indexInParent - 1)); + cursor->setPosition(ExpressionLayoutCursor::Position::Right); + return; + } + ExpressionLayout::backspaceAtCursor(cursor); +} + +bool UneditableHorizontalTrioLayout::moveLeft(ExpressionLayoutCursor * cursor) { + if (cursor->pointedExpressionLayout() == centerLayout()) { + // Case: Center layout. + // Go Left. + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + cursor->setPointedExpressionLayout(this); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + if (cursor->position() == ExpressionLayoutCursor::Position::Right) { + // Case: Right. + // Go Right of the center layout's last child if it has one, else go Right + // of the center layout. + ExpressionLayout * grandChild = centerLayout()->editableChild(centerLayout()->numberOfChildren()-1); + if (grandChild != nullptr) { + cursor->setPointedExpressionLayout(grandChild); + return true; + } + cursor->setPointedExpressionLayout(centerLayout()); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Left); + // Case: Left. + // Ask the parent. + if (m_parent) { + return m_parent->moveLeft(cursor); + } + return false; +} + +bool UneditableHorizontalTrioLayout::moveRight(ExpressionLayoutCursor * cursor) { + if (cursor->pointedExpressionLayout() == centerLayout()) { + // Case: Center layout. + // Go Right. + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + cursor->setPointedExpressionLayout(this); + return true; + } + assert(cursor->pointedExpressionLayout() == this); + if (cursor->position() == ExpressionLayoutCursor::Position::Left) { + // Case: Left. + // Go Left of the center layout's first child if it has one, else go Left of + // the center layout. + ExpressionLayout * grandChild = centerLayout()->editableChild(0); + if (grandChild != nullptr) { + cursor->setPointedExpressionLayout(grandChild); + return true; + } + cursor->setPointedExpressionLayout(centerLayout()); + return true; + } + assert(cursor->position() == ExpressionLayoutCursor::Position::Right); + // Case: Right. + // Ask the parent. + if (m_parent) { + return m_parent->moveRight(cursor); + } + return false; +} + +void UneditableHorizontalTrioLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { +} + +KDSize UneditableHorizontalTrioLayout::computeSize() { + // TODO: This code is duplicated from horizontal_layout.cpp. + KDCoordinate totalWidth = 0; + int i = 0; + KDCoordinate max_under_baseline = 0; + KDCoordinate max_above_baseline = 0; + while (ExpressionLayout * c = editableChild(i++)) { + KDSize childSize = c->size(); + totalWidth += childSize.width(); + if (childSize.height() - c->baseline() > max_under_baseline) { + max_under_baseline = childSize.height() - c->baseline() ; + } + if (c->baseline() > max_above_baseline) { + max_above_baseline = c->baseline(); + } + } + return KDSize(totalWidth, max_under_baseline + max_above_baseline); +} + +void UneditableHorizontalTrioLayout::computeBaseline() { + // TODO: This code is duplicated from horizontal_layout.cpp. + m_baseline = 0; + for (int i = 0; i < numberOfChildren(); i++) { + if (editableChild(i)->baseline() > m_baseline) { + m_baseline = editableChild(i)->baseline(); + } + } + m_baselined = true; +} + +KDPoint UneditableHorizontalTrioLayout::positionOfChild(ExpressionLayout * child) { + // TODO: This code is duplicated from horizontal_layout.cpp. + KDCoordinate x = 0; + KDCoordinate y = 0; + int index = indexOfChild(child); + if (index > 0) { + ExpressionLayout * previousChild = editableChild(index-1); + assert(previousChild != nullptr); + x = previousChild->origin().x() + previousChild->size().width(); + } + y = baseline() - child->baseline(); + return KDPoint(x, y); +} + +ExpressionLayout * UneditableHorizontalTrioLayout::leftLayout() { + return editableChild(0); +} + +ExpressionLayout * UneditableHorizontalTrioLayout::centerLayout() { + return editableChild(1); +} + +ExpressionLayout * UneditableHorizontalTrioLayout::rightLayout() { + return editableChild(2); +} + +} diff --git a/poincare/src/layout/uneditable_horizontal_trio_layout.h b/poincare/src/layout/uneditable_horizontal_trio_layout.h new file mode 100644 index 000000000..d0a356c14 --- /dev/null +++ b/poincare/src/layout/uneditable_horizontal_trio_layout.h @@ -0,0 +1,42 @@ +#ifndef POINCARE_UNEDITABLE_HORIZONTAL_TRIO_LAYOUT_H +#define POINCARE_UNEDITABLE_HORIZONTAL_TRIO_LAYOUT_H + +#include + +namespace Poincare { + +/* UneditableHorizontalTrioLayout has 3 children: a left and a right layout + * (usually parentheses or brackets), and a central layout. + * The cursor can only be: + * - Left or Right of the UneditableHorizontalTrioLayout, + * - Left or Right of the central layout if it is not an horizontal layout, + * - Inside the central layout if it is an horizontal layout. + * This way, the lateral children of an UneditableHorizontalTrioLayout cannot be + * edited, and it it will always have only 3 children. + * This layout can be used to create binomial coefficient layouts, matrix + * layouts or the argument of sum and product layouts. */ + +class UneditableHorizontalTrioLayout : public StaticLayoutHierarchy<3> { +public: + using StaticLayoutHierarchy::StaticLayoutHierarchy; + ExpressionLayout * clone() const override; + void backspaceAtCursor(ExpressionLayoutCursor * cursor) override; + + /* Navigation */ + bool moveLeft(ExpressionLayoutCursor * cursor) override; + bool moveRight(ExpressionLayoutCursor * cursor) override; + +protected: + void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; + KDSize computeSize() override; + void computeBaseline() override; + KDPoint positionOfChild(ExpressionLayout * child) override; +private: + ExpressionLayout * leftLayout(); + ExpressionLayout * centerLayout(); + ExpressionLayout * rightLayout(); +}; + +} + +#endif