[expression_editor/poincare] Move Down in an ExpressionLayout.

Change-Id: I87f3394cce5eb4936ab926d5e92fdf44d4473cf7
This commit is contained in:
Léa Saviot
2017-12-18 11:14:05 +01:00
parent fc8cd6c06e
commit a4c014c75e
19 changed files with 221 additions and 31 deletions

View File

@@ -32,6 +32,8 @@ public:
virtual bool moveRight(ExpressionLayoutCursor * cursor) { return false; } //TODO should be virtual pure?
virtual bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr);
bool moveUpInside(ExpressionLayoutCursor * cursor);
virtual bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout = nullptr, ExpressionLayout * previousPreviousLayout = nullptr);
bool moveDownInside(ExpressionLayoutCursor * cursor);
protected:
virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) = 0;
virtual KDSize computeSize() = 0;

View File

@@ -17,7 +17,7 @@ bool ExpressionLayoutCursor::moveUp() {
}
bool ExpressionLayoutCursor::moveDown() {
return false; //TODO
return m_pointedExpressionLayout->moveDown(this);
}
bool ExpressionLayoutCursor::positionIsEquivalentTo(ExpressionLayout * expressionLayout, Position position, int positionIndex) {

View File

@@ -125,6 +125,23 @@ bool CondensedSumLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayou
return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout);
}
bool CondensedSumLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) {
// If the cursor is inside the superscript layout, move it to the subscript.
if (m_superscriptLayout && previousLayout == m_superscriptLayout) {
assert(m_subscriptLayout != nullptr);
return m_subscriptLayout->moveUpInside(cursor);
}
// If the cursor is Left of the base layout, move it to the subscript.
if (m_baseLayout
&& previousLayout == m_baseLayout
&& cursor->positionIsEquivalentTo(m_baseLayout, ExpressionLayoutCursor::Position::Left))
{
assert(m_subscriptLayout != nullptr);
return m_subscriptLayout->moveUpInside(cursor);
}
return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout);
}
void CondensedSumLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) {
// Nothing to draw
}

View File

@@ -17,6 +17,7 @@ public:
bool moveLeft(ExpressionLayoutCursor * cursor) override;
bool moveRight(ExpressionLayoutCursor * cursor) override;
bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
protected:
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override;
KDSize computeSize() override;

View File

@@ -132,5 +132,53 @@ bool EditableBaselineRelativeLayout::moveUp(ExpressionLayoutCursor * cursor, Exp
return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout);
}
bool EditableBaselineRelativeLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) {
// If the baseline is a subscript:
if (m_type == BaselineRelativeLayout::Type::Subscript) {
// If the cursor is Right of the base layout, move it to the indice.
if (m_baseLayout
&& previousLayout == m_baseLayout
&& cursor->positionIsEquivalentTo(m_baseLayout, ExpressionLayoutCursor::Position::Right))
{
assert(m_indiceLayout != nullptr);
cursor->setPointedExpressionLayout(m_indiceLayout);
cursor->setPosition(ExpressionLayoutCursor::Position::Left);
cursor->setPositionInside(0);
return true;
}
// If the cursor is Right, move it to the indice.
if (cursor->positionIsEquivalentTo(this, ExpressionLayoutCursor::Position::Right)) {
assert(m_indiceLayout != nullptr);
cursor->setPointedExpressionLayout(m_indiceLayout);
cursor->setPosition(ExpressionLayoutCursor::Position::Right);
cursor->setPositionInside(0);
return true;
}
}
// If the baseline is a superscript:
if (m_type == BaselineRelativeLayout::Type::Superscript
&& m_indiceLayout
&& previousLayout == m_indiceLayout)
{
// If the cursor is Left of the indice layout, move it to the base.
if (cursor->positionIsEquivalentTo(m_indiceLayout, ExpressionLayoutCursor::Position::Left)) {
assert(m_indiceLayout != nullptr);
cursor->setPointedExpressionLayout(m_baseLayout);
cursor->setPosition(ExpressionLayoutCursor::Position::Right);
cursor->setPositionInside(0);
return true;
}
// If the cursor is Right of the indice layout, move it Right.
if (cursor->positionIsEquivalentTo(m_indiceLayout, ExpressionLayoutCursor::Position::Right)) {
assert(m_indiceLayout != nullptr);
cursor->setPointedExpressionLayout(this);
cursor->setPosition(ExpressionLayoutCursor::Position::Right);
cursor->setPositionInside(0);
return true;
}
}
return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout);
}
}

View File

@@ -11,6 +11,7 @@ public:
bool moveLeft(ExpressionLayoutCursor * cursor) override;
bool moveRight(ExpressionLayoutCursor * cursor) override;
bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
};
}

View File

@@ -70,6 +70,17 @@ bool ExpressionLayout::moveUpInside(ExpressionLayoutCursor * cursor) {
return moveInside(VerticalDirection::Up, cursor);
}
bool ExpressionLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) {
if (m_parent) {
return m_parent->moveDown(cursor, this, previousLayout);
}
return false;
}
bool ExpressionLayout::moveDownInside(ExpressionLayoutCursor * cursor) {
return moveInside(VerticalDirection::Down, cursor);
}
bool ExpressionLayout::moveInside(VerticalDirection direction, ExpressionLayoutCursor * cursor) {
ExpressionLayout * chilResult = nullptr;
ExpressionLayout ** childResultPtr = &chilResult;

View File

@@ -86,6 +86,20 @@ bool FractionLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout *
return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout);
}
bool FractionLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) {
// If the cursor is inside numerator, move it to the denominator.
if (m_numerator_layout && previousLayout == m_numerator_layout) {
assert(m_denominator_layout != nullptr);
return m_denominator_layout->moveDownInside(cursor);
}
// If the cursor is Left or Right, move it to the denominator.
if (cursor->pointedExpressionLayout() == this){
assert(m_denominator_layout != nullptr);
return m_denominator_layout->moveDownInside(cursor);
}
return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout);
}
void FractionLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) {
KDCoordinate fractionLineY = p.y() + m_numerator_layout->size().height() + k_fractionLineMargin;
ctx->fillRect(KDRect(p.x()+k_fractionBorderMargin, fractionLineY, size().width()-2*k_fractionBorderMargin, 1), expressionColor);

View File

@@ -17,6 +17,7 @@ public:
bool moveLeft(ExpressionLayoutCursor * cursor) override;
bool moveRight(ExpressionLayoutCursor * cursor) override;
bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
protected:
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override;
KDSize computeSize() override;

View File

@@ -110,6 +110,16 @@ bool GridLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * prev
return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout);
}
bool GridLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) {
// If the cursor is child that is not on the bottom row, move it inside the
// lower neighbourg.
int childIndex = indexOfChild(previousLayout);
if (childIndex >- 1 && !childIsBottomOfGrid(childIndex)) {
return m_entryLayouts[childIndex + m_numberOfColumns]->moveDownInside(cursor);
}
return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout);
}
KDCoordinate GridLayout::rowBaseline(int i) {
KDCoordinate rowBaseline = 0;
for (int j = 0; j < m_numberOfColumns; j++) {
@@ -217,4 +227,9 @@ bool GridLayout::childIsTopOfGrid(int index) const {
return index < m_numberOfColumns;
}
bool GridLayout::childIsBottomOfGrid(int index) const {
assert(index >= 0 && index < m_numberOfRows*m_numberOfColumns);
return index > (m_numberOfRows - 1) * m_numberOfColumns - 1;
}
}

View File

@@ -18,6 +18,7 @@ public:
bool moveLeft(ExpressionLayoutCursor * cursor) override;
bool moveRight(ExpressionLayoutCursor * cursor) override;
bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
protected:
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override;
KDSize computeSize() override;
@@ -34,6 +35,7 @@ private:
bool childIsLeftOfGrid(int index) const;
bool childIsRightOfGrid(int index) const;
bool childIsTopOfGrid(int index) const;
bool childIsBottomOfGrid(int index) const;
ExpressionLayout ** m_entryLayouts;
int m_numberOfRows;
int m_numberOfColumns;

View File

@@ -125,36 +125,11 @@ bool HorizontalLayout::moveRight(ExpressionLayoutCursor * cursor) {
}
bool HorizontalLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) {
// Prevent looping fom child to parent
if (previousPreviousLayout == this) {
return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout);
}
// If the cursor Left or Right of a child, try moving it up from its brother.
int previousLayoutIndex = indexOfChild(previousLayout);
if (previousLayoutIndex > -1) {
ExpressionLayout * brother = nullptr;
ExpressionLayoutCursor::Position newPosition = ExpressionLayoutCursor::Position::Right;
if (cursor->position() == ExpressionLayoutCursor::Position::Left && previousLayoutIndex > 0) {
brother = m_children_layouts[previousLayoutIndex - 1];
newPosition = ExpressionLayoutCursor::Position::Right;
}
if (cursor->position() == ExpressionLayoutCursor::Position::Right && previousLayoutIndex < m_number_of_children - 1) {
brother = m_children_layouts[previousLayoutIndex + 1];
newPosition = ExpressionLayoutCursor::Position::Left;
}
if (brother && cursor->positionIsEquivalentTo(brother, newPosition)) {
ExpressionLayout * previousPointedLayout = cursor->pointedExpressionLayout();
ExpressionLayoutCursor::Position previousPosition = cursor->position();
cursor->setPointedExpressionLayout(brother);
cursor->setPosition(newPosition);
if (brother->moveUp(cursor, this, previousLayout)) {
return true;
}
cursor->setPointedExpressionLayout(previousPointedLayout);
cursor->setPosition(previousPosition);
}
}
return ExpressionLayout::moveUp(cursor, previousLayout);
return moveVertically(ExpressionLayout::VerticalDirection::Up, cursor, previousLayout, previousPreviousLayout);
}
bool HorizontalLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) {
return moveVertically(ExpressionLayout::VerticalDirection::Down, cursor, previousLayout, previousPreviousLayout);
}
void HorizontalLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) {
@@ -200,6 +175,50 @@ KDPoint HorizontalLayout::positionOfChild(ExpressionLayout * child) {
return KDPoint(x, y);
}
bool HorizontalLayout::moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) {
// Prevent looping fom child to parent
if (previousPreviousLayout == this) {
if (direction == ExpressionLayout::VerticalDirection::Up) {
return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout);
}
assert(direction == ExpressionLayout::VerticalDirection::Down);
return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout);
}
// If the cursor Left or Right of a child, try moving it up from its brother.
int previousLayoutIndex = indexOfChild(previousLayout);
if (previousLayoutIndex > -1) {
ExpressionLayout * brother = nullptr;
ExpressionLayoutCursor::Position newPosition = ExpressionLayoutCursor::Position::Right;
if (cursor->position() == ExpressionLayoutCursor::Position::Left && previousLayoutIndex > 0) {
brother = m_children_layouts[previousLayoutIndex - 1];
newPosition = ExpressionLayoutCursor::Position::Right;
}
if (cursor->position() == ExpressionLayoutCursor::Position::Right && previousLayoutIndex < m_number_of_children - 1) {
brother = m_children_layouts[previousLayoutIndex + 1];
newPosition = ExpressionLayoutCursor::Position::Left;
}
if (brother && cursor->positionIsEquivalentTo(brother, newPosition)) {
ExpressionLayout * previousPointedLayout = cursor->pointedExpressionLayout();
ExpressionLayoutCursor::Position previousPosition = cursor->position();
cursor->setPointedExpressionLayout(brother);
cursor->setPosition(newPosition);
if (direction == ExpressionLayout::VerticalDirection::Up && brother->moveUp(cursor, this, previousLayout)) {
return true;
}
if (direction == ExpressionLayout::VerticalDirection::Down && brother->moveDown(cursor, this, previousLayout)) {
return true;
}
cursor->setPointedExpressionLayout(previousPointedLayout);
cursor->setPosition(previousPosition);
}
}
if (direction == ExpressionLayout::VerticalDirection::Up) {
return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout);
}
assert(direction == ExpressionLayout::VerticalDirection::Down);
return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout);
}
int HorizontalLayout::indexOfChild(ExpressionLayout * eL) const {
if (eL == nullptr) {
return -1;

View File

@@ -17,12 +17,14 @@ public:
bool moveLeft(ExpressionLayoutCursor * cursor) override;
bool moveRight(ExpressionLayoutCursor * cursor) override;
bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
protected:
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override;
KDSize computeSize() override;
ExpressionLayout * child(uint16_t index) override;
KDPoint positionOfChild(ExpressionLayout * child) override;
private:
bool moveVertically(ExpressionLayout::VerticalDirection direction, ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout);
int indexOfChild(ExpressionLayout * eL) const;
int m_number_of_children;
ExpressionLayout ** m_children_layouts;

View File

@@ -134,6 +134,23 @@ bool IntegralLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout *
return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout);
}
bool IntegralLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) {
// If the cursor is inside the upper bound, move it to the lower bound.
if (m_upperBoundLayout && previousLayout == m_upperBoundLayout) {
assert(m_lowerBoundLayout != nullptr);
return m_lowerBoundLayout->moveDownInside(cursor);
}
// If the cursor is Left of the integrand, move it to the lower bound.
if (m_integrandLayout
&& previousLayout == m_integrandLayout
&& cursor->positionIsEquivalentTo(m_integrandLayout, ExpressionLayoutCursor::Position::Left))
{
assert(m_lowerBoundLayout != nullptr);
return m_lowerBoundLayout->moveDownInside(cursor);
}
return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout);
}
void IntegralLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) {
KDSize integrandSize = m_integrandLayout->size();
KDSize upperBoundSize = m_upperBoundLayout->size();

View File

@@ -19,6 +19,7 @@ public:
bool moveLeft(ExpressionLayoutCursor * cursor) override;
bool moveRight(ExpressionLayoutCursor * cursor) override;
bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
protected:
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override;
KDSize computeSize() override;

View File

@@ -146,6 +146,27 @@ bool NthRootLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * p
return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout);
}
bool NthRootLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) {
if (m_indexLayout && previousLayout == m_indexLayout) {
// If the cursor is Right of the index, move it to the radicand.
if (cursor->positionIsEquivalentTo(m_indexLayout, ExpressionLayoutCursor::Position::Right)) {
assert(m_radicandLayout != nullptr);
cursor->setPointedExpressionLayout(m_radicandLayout);
cursor->setPosition(ExpressionLayoutCursor::Position::Left);
cursor->setPositionInside(0);
return true;
}
// If the cursor is Left of the index, move it Left .
if (cursor->positionIsEquivalentTo(m_indexLayout, ExpressionLayoutCursor::Position::Left)) {
cursor->setPointedExpressionLayout(this);
cursor->setPosition(ExpressionLayoutCursor::Position::Left);
cursor->setPositionInside(0);
return true;
}
}
return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout);
}
void NthRootLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) {
KDSize radicandSize = m_radicandLayout->size();
KDSize indexSize = m_indexLayout != nullptr ? m_indexLayout->size() : KDSize(k_leftRadixWidth,0);

View File

@@ -19,6 +19,7 @@ public:
bool moveLeft(ExpressionLayoutCursor * cursor) override;
bool moveRight(ExpressionLayoutCursor * cursor) override;
bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
protected:
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override;
KDSize computeSize() override;

View File

@@ -123,6 +123,22 @@ bool SequenceLayout::moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout *
}
return ExpressionLayout::moveUp(cursor, previousLayout, previousPreviousLayout);
}
bool SequenceLayout::moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) {
// If the cursor is inside the upper bound, move it to the lower bound.
if (m_upperBoundLayout && previousLayout == m_upperBoundLayout) {
assert(m_lowerBoundLayout != nullptr);
return m_lowerBoundLayout->moveDownInside(cursor);
}
// If the cursor is Left of the argument, move it to the lower bound.
if (m_argumentLayout
&& previousLayout == m_argumentLayout
&& cursor->positionIsEquivalentTo(m_argumentLayout, ExpressionLayoutCursor::Position::Left))
{
assert(m_lowerBoundLayout != nullptr);
return m_lowerBoundLayout->moveDownInside(cursor);
}
return ExpressionLayout::moveDown(cursor, previousLayout, previousPreviousLayout);
}
KDSize SequenceLayout::computeSize() {
KDSize argumentSize = m_argumentLayout->size();

View File

@@ -19,6 +19,7 @@ public:
bool moveLeft(ExpressionLayoutCursor * cursor) override;
bool moveRight(ExpressionLayoutCursor * cursor) override;
bool moveUp(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
bool moveDown(ExpressionLayoutCursor * cursor, ExpressionLayout * previousLayout, ExpressionLayout * previousPreviousLayout) override;
protected:
constexpr static KDCoordinate k_boundHeightMargin = 2;
ExpressionLayout * m_lowerBoundLayout;