[poincare] Factorize Parenthesis/SquareBracket layout in BracketLayout.

Change-Id: I2aeddb950803f460b75e6e9a0efd3c0e2f16164e
This commit is contained in:
Léa Saviot
2018-04-24 11:25:46 +02:00
parent e622d6aa43
commit 99b320c754
8 changed files with 205 additions and 326 deletions

View File

@@ -91,6 +91,7 @@ objs += $(addprefix poincare/src/layout/,\
absolute_value_layout.o\
binomial_coefficient_layout.o\
bounded_static_layout_hierarchy.o\
bracket_layout.o\
bracket_pair_layout.o\
ceiling_layout.o\
char_layout.o\
@@ -108,12 +109,10 @@ objs += $(addprefix poincare/src/layout/,\
left_square_bracket_layout.o\
matrix_layout.o\
nth_root_layout.o\
parenthesis_layout.o\
product_layout.o\
right_parenthesis_layout.o\
right_square_bracket_layout.o\
sequence_layout.o\
square_bracket_layout.o\
static_layout_hierarchy.o\
sum_layout.o\
vertical_offset_layout.o\

View File

@@ -5,8 +5,6 @@
#include <poincare/src/layout/absolute_value_layout.h>
#include <poincare/src/layout/binomial_coefficient_layout.h>
#include <poincare/src/layout/bracket_pair_layout.h>
#include <poincare/src/layout/left_square_bracket_layout.h>
#include <poincare/src/layout/right_square_bracket_layout.h>
#include <poincare/src/layout/ceiling_layout.h>
#include <poincare/src/layout/char_layout.h>
#include <poincare/src/layout/condensed_sum_layout.h>
@@ -17,10 +15,12 @@
#include <poincare/src/layout/grid_layout.h>
#include <poincare/src/layout/horizontal_layout.h>
#include <poincare/src/layout/integral_layout.h>
#include <poincare/src/layout/left_parenthesis_layout.h>
#include <poincare/src/layout/left_square_bracket_layout.h>
#include <poincare/src/layout/matrix_layout.h>
#include <poincare/src/layout/nth_root_layout.h>
#include <poincare/src/layout/left_parenthesis_layout.h>
#include <poincare/src/layout/right_parenthesis_layout.h>
#include <poincare/src/layout/right_square_bracket_layout.h>
#include <poincare/src/layout/product_layout.h>
#include <poincare/src/layout/sequence_layout.h>
#include <poincare/src/layout/sum_layout.h>

View File

@@ -0,0 +1,164 @@
#include "bracket_layout.h"
#include <escher/metric.h>
#include <poincare/expression_layout_cursor.h>
extern "C" {
#include <assert.h>
#include <stdlib.h>
}
namespace Poincare {
static inline KDCoordinate max(KDCoordinate x, KDCoordinate y) { return (x>y ? x : y); }
BracketLayout::BracketLayout() :
StaticLayoutHierarchy<0>(),
m_operandHeightComputed(false)
{
}
void BracketLayout::invalidAllSizesPositionsAndBaselines() {
m_operandHeightComputed = false;
ExpressionLayout::invalidAllSizesPositionsAndBaselines();
}
ExpressionLayoutCursor BracketLayout::cursorLeftOf(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) {
assert(cursor->pointedExpressionLayout() == this);
// Case: Right. Go Left.
if (cursor->position() == ExpressionLayoutCursor::Position::Right) {
return ExpressionLayoutCursor(this, ExpressionLayoutCursor::Position::Left);
}
assert(cursor->position() == ExpressionLayoutCursor::Position::Left);
// Case: Left. Ask the parent.
if (m_parent) {
return m_parent->cursorLeftOf(cursor, shouldRecomputeLayout);
}
return ExpressionLayoutCursor();
}
ExpressionLayoutCursor BracketLayout::cursorRightOf(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) {
assert(cursor->pointedExpressionLayout() == this);
// Case: Left. Go Right.
if (cursor->position() == ExpressionLayoutCursor::Position::Left) {
return ExpressionLayoutCursor(this, ExpressionLayoutCursor::Position::Right);
}
assert(cursor->position() == ExpressionLayoutCursor::Position::Right);
// Case: Right. Ask the parent.
if (m_parent) {
return m_parent->cursorRightOf(cursor, shouldRecomputeLayout);
}
return ExpressionLayoutCursor();
}
void BracketLayout::computeBaseline() {
assert(m_parent != nullptr);
int indexInParent = m_parent->indexOfChild(this);
int numberOfSiblings = m_parent->numberOfChildren();
if (((isLeftParenthesis() || isLeftBracket()) && indexInParent == numberOfSiblings - 1)
|| ((isRightParenthesis() || isRightBracket()) && indexInParent == 0)
|| ((isLeftParenthesis() || isLeftBracket()) && indexInParent < numberOfSiblings - 1 && m_parent->child(indexInParent + 1)->isVerticalOffset()))
{
/* The bracket does not have siblings on its open direction, or it is a left
* bracket that is base of a superscript layout. In the latter case, it
* should have a default baseline, else it creates an infinite loop as the
* bracket needs the superscript baseline, which needs the bracket baseline.*/
m_baseline = size().height()/2;
m_baselined = true;
return;
}
int currentNumberOfOpenBrackets = 1;
m_baseline = 0;
int increment = (isLeftParenthesis() || isLeftBracket()) ? 1 : -1;
for (int i = indexInParent + increment; i >= 0 && i < numberOfSiblings; i+=increment) {
ExpressionLayout * sibling = m_parent->editableChild(i);
if ((isLeftParenthesis() && sibling->isRightParenthesis())
|| (isLeftBracket() && sibling->isRightBracket())
|| (isRightParenthesis() && sibling->isLeftParenthesis())
|| (isRightBracket() && sibling->isLeftBracket()))
{
if (i == indexInParent + increment) {
/* If the bracket is immediately closed, we set the baseline to half the
* bracket height. */
m_baseline = size().height()/2;
m_baselined = true;
return;
}
currentNumberOfOpenBrackets--;
if (currentNumberOfOpenBrackets == 0) {
break;
}
} else if ((isLeftParenthesis() && sibling->isLeftParenthesis())
|| (isLeftBracket() && sibling->isLeftBracket())
|| (isRightParenthesis() && sibling->isRightParenthesis())
|| (isRightBracket() && sibling->isRightBracket()))
{
currentNumberOfOpenBrackets++;
}
m_baseline = max(m_baseline, sibling->baseline());
}
m_baseline += (size().height() - operandHeight()) / 2;
m_baselined = true;
}
KDCoordinate BracketLayout::operandHeight() {
if (!m_operandHeightComputed) {
computeOperandHeight();
}
return m_operandHeight;
}
void BracketLayout::computeOperandHeight() {
assert(m_parent != nullptr);
m_operandHeight = Metric::MinimalBracketAndParenthesisHeight;
int indexInParent = m_parent->indexOfChild(this);
int numberOfSiblings = m_parent->numberOfChildren();
if ((isLeftParenthesis() || isLeftBracket())
&& indexInParent < numberOfSiblings - 1
&& m_parent->child(indexInParent + 1)->isVerticalOffset())
{
/* If a left bracket is the base of a superscript layout, it should have a
* a default height, else it creates an infinite loop because the bracket
* needs the superscript height, which needs the bracket height. */
m_operandHeightComputed = true;
return;
}
KDCoordinate maxUnderBaseline = 0;
KDCoordinate maxAboveBaseline = 0;
int currentNumberOfOpenBrackets = 1;
int increment = (isLeftParenthesis() || isLeftBracket()) ? 1 : -1;
for (int i = indexInParent + increment; i >= 0 && i < numberOfSiblings; i+= increment) {
ExpressionLayout * sibling = m_parent->editableChild(i);
if ((isLeftParenthesis() && sibling->isRightParenthesis())
|| (isLeftBracket() && sibling->isRightBracket())
|| (isRightParenthesis() && sibling->isLeftParenthesis())
|| (isRightBracket() && sibling->isLeftBracket()))
{
currentNumberOfOpenBrackets--;
if (currentNumberOfOpenBrackets == 0) {
break;
}
} else if ((isLeftParenthesis() && sibling->isLeftParenthesis())
|| (isLeftBracket() && sibling->isLeftBracket())
|| (isRightParenthesis() && sibling->isRightParenthesis())
|| (isRightBracket() && sibling->isRightBracket()))
{
currentNumberOfOpenBrackets++;
}
KDCoordinate siblingHeight = sibling->size().height();
KDCoordinate siblingBaseline = sibling->baseline();
maxUnderBaseline = max(maxUnderBaseline, siblingHeight - siblingBaseline);
maxAboveBaseline = max(maxAboveBaseline, siblingBaseline);
}
m_operandHeight = max(m_operandHeight, maxUnderBaseline + maxAboveBaseline);
m_operandHeightComputed = true;
}
KDPoint BracketLayout::positionOfChild(ExpressionLayout * child) {
assert(false);
return KDPointZero;
}
}

View File

@@ -0,0 +1,24 @@
#ifndef POINCARE_BRACKET_LAYOUT_H
#define POINCARE_BRACKET_LAYOUT_H
#include <poincare/static_layout_hierarchy.h>
namespace Poincare {
class BracketLayout : public StaticLayoutHierarchy<0> {
public:
BracketLayout();
void invalidAllSizesPositionsAndBaselines() override;
ExpressionLayoutCursor cursorLeftOf(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override;
ExpressionLayoutCursor cursorRightOf(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override;
protected:
void computeBaseline() override;
KDCoordinate operandHeight();
void computeOperandHeight();
KDPoint positionOfChild(ExpressionLayout * child) override;
bool m_operandHeightComputed;
uint16_t m_operandHeight;
};
}
#endif

View File

@@ -1,174 +0,0 @@
#include "parenthesis_layout.h"
#include <escher/metric.h>
#include <poincare/expression_layout_cursor.h>
extern "C" {
#include <assert.h>
#include <stdlib.h>
}
namespace Poincare {
static inline int max(int x, int y) { return (x>y ? x : y); }
ParenthesisLayout::ParenthesisLayout() :
StaticLayoutHierarchy<0>(),
m_operandHeightComputed(false)
{
}
void ParenthesisLayout::invalidAllSizesPositionsAndBaselines() {
m_operandHeightComputed = false;
ExpressionLayout::invalidAllSizesPositionsAndBaselines();
}
ExpressionLayoutCursor ParenthesisLayout::cursorLeftOf(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) {
assert(cursor->pointedExpressionLayout() == this);
// Case: Right. Go Left.
if (cursor->position() == ExpressionLayoutCursor::Position::Right) {
return ExpressionLayoutCursor(this, ExpressionLayoutCursor::Position::Left);
}
assert(cursor->position() == ExpressionLayoutCursor::Position::Left);
// Case: Left. Ask the parent.
if (m_parent) {
return m_parent->cursorLeftOf(cursor, shouldRecomputeLayout);
}
return ExpressionLayoutCursor();
}
ExpressionLayoutCursor ParenthesisLayout::cursorRightOf(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) {
assert(cursor->pointedExpressionLayout() == this);
// Case: Left. Go Right.
if (cursor->position() == ExpressionLayoutCursor::Position::Left) {
return ExpressionLayoutCursor(this, ExpressionLayoutCursor::Position::Right);
}
assert(cursor->position() == ExpressionLayoutCursor::Position::Right);
// Case: Right. Ask the parent.
if (m_parent) {
return m_parent->cursorRightOf(cursor, shouldRecomputeLayout);
}
return ExpressionLayoutCursor();
}
KDSize ParenthesisLayout::computeSize() {
return KDSize(parenthesisWidth(), operandHeight() + k_verticalMargin);
}
void ParenthesisLayout::computeBaseline() {
assert(m_parent != nullptr);
bool isParenthesisLeft = isLeftParenthesis();
int indexInParent = m_parent->indexOfChild(this);
int numberOfSiblings = m_parent->numberOfChildren();
if ((isParenthesisLeft && indexInParent == numberOfSiblings - 1)
|| (!isParenthesisLeft && indexInParent == 0)
|| (isParenthesisLeft && indexInParent < numberOfSiblings - 1 && m_parent->child(indexInParent + 1)->isVerticalOffset()))
{
/* The parenthesis does not have siblings on its open direction, or it is a
* left parenthesis that is base of a superscript layout. In the latter
* case, it should have a default baseline, else it creates an infinite loop
* because the parenthesis needs the superscript height, which needs the
* parenthesis baseline. */
m_baseline = size().height()/2;
m_baselined = true;
return;
}
int currentNumberOfOpenParentheses = 1;
m_baseline = 0;
int increment = isParenthesisLeft ? 1 : -1;
for (int i = indexInParent + increment; i >= 0 && i <= numberOfSiblings - 1; i+= increment) {
ExpressionLayout * sibling = m_parent->editableChild(i);
if ((isParenthesisLeft && sibling->isRightParenthesis())
|| (!isParenthesisLeft && sibling->isLeftParenthesis()))
{
if (i == indexInParent + increment) {
/* If the parenthesis is immediately closed, we set the baseline to half
* the parenthesis height. */
m_baseline = size().height()/2;
m_baselined = true;
return;
}
currentNumberOfOpenParentheses--;
if (currentNumberOfOpenParentheses == 0) {
break;
}
} else if ((isParenthesisLeft && sibling->isLeftParenthesis())
|| (!isParenthesisLeft && sibling->isRightParenthesis()))
{
currentNumberOfOpenParentheses++;
}
if (sibling->baseline() > m_baseline) {
m_baseline = sibling->baseline();
}
}
m_baseline += (size().height() - operandHeight()) / 2;
m_baselined = true;
}
KDCoordinate ParenthesisLayout::operandHeight() {
if (!m_operandHeightComputed) {
computeOperandHeight();
m_operandHeightComputed = true;
}
return m_operandHeight;
}
void ParenthesisLayout::computeOperandHeight() {
assert(m_parent != nullptr);
m_operandHeight = Metric::MinimalBracketAndParenthesisHeight;
bool isParenthesisLeft = isLeftParenthesis();
int indexInParent = m_parent->indexOfChild(this);
int numberOfSiblings = m_parent->numberOfChildren();
if (isParenthesisLeft
&& indexInParent < numberOfSiblings - 1
&& m_parent->child(indexInParent + 1)->isVerticalOffset())
{
/* If a left parenthesis is the base of a superscript layout, it should have
* a default height, else it creates an infinite loop because the
* parenthesis needs the superscript height, which needs the parenthesis
* height. */
return;
}
KDCoordinate max_under_baseline = 0;
KDCoordinate max_above_baseline = 0;
int currentNumberOfOpenParentheses = 1;
int increment = isParenthesisLeft ? 1 : -1;
for (int i = indexInParent + increment; i >= 0 && i < numberOfSiblings; i+= increment) {
ExpressionLayout * sibling = m_parent->editableChild(i);
if ((!isParenthesisLeft && sibling->isLeftParenthesis())
|| (isParenthesisLeft && sibling->isRightParenthesis()))
{
currentNumberOfOpenParentheses--;
if (currentNumberOfOpenParentheses == 0) {
if (max_under_baseline + max_above_baseline > m_operandHeight) {
m_operandHeight = max_under_baseline + max_above_baseline;
}
return;
}
} else if ((isParenthesisLeft && sibling->isLeftParenthesis())
|| (!isParenthesisLeft && sibling->isRightParenthesis()))
{
currentNumberOfOpenParentheses++;
}
KDCoordinate siblingHeight = sibling->size().height();
KDCoordinate siblingBaseline = sibling->baseline();
if (siblingHeight - siblingBaseline > max_under_baseline) {
max_under_baseline = siblingHeight - siblingBaseline ;
}
if (siblingBaseline > max_above_baseline) {
max_above_baseline = siblingBaseline;
}
}
if (max_under_baseline + max_above_baseline > m_operandHeight) {
m_operandHeight = max_under_baseline + max_above_baseline;
}
}
KDPoint ParenthesisLayout::positionOfChild(ExpressionLayout * child) {
assert(false);
return KDPointZero;
}
}

View File

@@ -1,16 +1,13 @@
#ifndef POINCARE_PARENTHESIS_LAYOUT_H
#define POINCARE_PARENTHESIS_LAYOUT_H
#include <poincare/static_layout_hierarchy.h>
#include "bracket_layout.h"
namespace Poincare {
class ParenthesisLayout : public StaticLayoutHierarchy<0> {
class ParenthesisLayout : public BracketLayout {
public:
ParenthesisLayout();
void invalidAllSizesPositionsAndBaselines() override;
ExpressionLayoutCursor cursorLeftOf(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override;
ExpressionLayoutCursor cursorRightOf(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override;
using BracketLayout::BracketLayout;
constexpr static KDCoordinate parenthesisWidth() { return k_widthMargin + k_lineThickness + k_externWidthMargin; }
constexpr static KDCoordinate k_parenthesisCurveWidth = 5;
constexpr static KDCoordinate k_parenthesisCurveHeight = 7;
@@ -21,14 +18,11 @@ public:
constexpr static KDCoordinate k_verticalMargin = 4;
protected:
KDColor s_parenthesisWorkingBuffer[k_parenthesisCurveHeight*k_parenthesisCurveWidth];
KDSize computeSize() override;
void computeBaseline() override;
KDCoordinate operandHeight();
void computeOperandHeight();
KDPoint positionOfChild(ExpressionLayout * child) override;
bool m_operandHeightComputed;
uint16_t m_operandHeight;
KDSize computeSize() override {
return KDSize(parenthesisWidth(), operandHeight() + k_verticalMargin);
}
};
}
#endif

View File

@@ -1,121 +0,0 @@
#include "square_bracket_layout.h"
#include <escher/metric.h>
#include <poincare/expression_layout_cursor.h>
extern "C" {
#include <assert.h>
#include <stdlib.h>
}
namespace Poincare {
SquareBracketLayout::SquareBracketLayout() :
StaticLayoutHierarchy<0>(),
m_operandHeightComputed(false)
{
}
void SquareBracketLayout::invalidAllSizesPositionsAndBaselines() {
m_operandHeightComputed = false;
ExpressionLayout::invalidAllSizesPositionsAndBaselines();
}
ExpressionLayoutCursor SquareBracketLayout::cursorLeftOf(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) {
assert(cursor->pointedExpressionLayout() == this);
// Case: Right. Go Left.
if (cursor->position() == ExpressionLayoutCursor::Position::Right) {
return ExpressionLayoutCursor(this, ExpressionLayoutCursor::Position::Left);
}
assert(cursor->position() == ExpressionLayoutCursor::Position::Left);
// Case: Left. Ask the parent.
if (m_parent) {
return m_parent->cursorLeftOf(cursor, shouldRecomputeLayout);
}
return ExpressionLayoutCursor();
}
ExpressionLayoutCursor SquareBracketLayout::cursorRightOf(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) {
assert(cursor->pointedExpressionLayout() == this);
// Case: Left. Go Right.
if (cursor->position() == ExpressionLayoutCursor::Position::Left) {
return ExpressionLayoutCursor(this, ExpressionLayoutCursor::Position::Right);
}
assert(cursor->position() == ExpressionLayoutCursor::Position::Right);
// Case: Right. Ask the parent.
if (m_parent) {
return m_parent->cursorRightOf(cursor, shouldRecomputeLayout);
}
return ExpressionLayoutCursor();
}
KDSize SquareBracketLayout::computeSize() {
return KDSize(k_externWidthMargin + k_lineThickness + k_widthMargin, operandHeight() + k_lineThickness);
}
void SquareBracketLayout::computeBaseline() {
assert(m_parent != nullptr);
m_baseline = operandHeight()/2;
int currentNumberOfOpenBrackets = 1;
int increment = isLeftBracket() ? 1 : -1;
int numberOfSiblings = m_parent->numberOfChildren();
for (int i = m_parent->indexOfChild(this) + increment; i >= 0 && i < numberOfSiblings; i+=increment) {
ExpressionLayout * sibling = m_parent->editableChild(i);
if ((isRightBracket() && sibling->isLeftBracket())
|| (isLeftBracket() && sibling->isRightBracket()))
{
currentNumberOfOpenBrackets--;
if (currentNumberOfOpenBrackets == 0) {
break;
}
} else if ((isRightBracket() && sibling->isRightBracket())
|| (isLeftBracket() && sibling->isLeftBracket()))
{
currentNumberOfOpenBrackets++;
}
if (sibling->baseline() > m_baseline) {
m_baseline = sibling->baseline();
}
}
m_baselined = true;
}
KDCoordinate SquareBracketLayout::operandHeight() {
if (!m_operandHeightComputed) {
computeOperandHeight();
}
return m_operandHeight;
}
void SquareBracketLayout::computeOperandHeight() {
assert(m_parent != nullptr);
m_operandHeight = Metric::MinimalBracketAndParenthesisHeight;
int currentNumberOfOpenBrackets = 1;
int increment = isLeftBracket() ? 1 : -1;
int numberOfSiblings = m_parent->numberOfChildren();
for (int i = m_parent->indexOfChild(this) + increment; i >= 0 && i < numberOfSiblings; i+=increment) {
ExpressionLayout * sibling = m_parent->editableChild(i);
if ((isRightBracket() && sibling->isLeftBracket())
|| (isLeftBracket() && sibling->isRightBracket()))
{
currentNumberOfOpenBrackets--;
if (currentNumberOfOpenBrackets == 0) {
break;
}
} else if ((isRightBracket() && sibling->isRightBracket())
|| (isLeftBracket() && sibling->isLeftBracket()))
{
currentNumberOfOpenBrackets++;
}
KDCoordinate siblingHeight = sibling->size().height();
if (siblingHeight > m_operandHeight) {
m_operandHeight = siblingHeight;
}
}
m_operandHeightComputed = true;
}
KDPoint SquareBracketLayout::positionOfChild(ExpressionLayout * child) {
assert(false);
return KDPointZero;
}
}

View File

@@ -1,28 +1,21 @@
#ifndef POINCARE_SQUARE_BRACKET_LAYOUT_H
#define POINCARE_SQUARE_BRACKET_LAYOUT_H
#include <poincare/static_layout_hierarchy.h>
#include "bracket_layout.h"
namespace Poincare {
class SquareBracketLayout : public StaticLayoutHierarchy<0> {
class SquareBracketLayout : public BracketLayout {
public:
SquareBracketLayout();
void invalidAllSizesPositionsAndBaselines() override;
ExpressionLayoutCursor cursorLeftOf(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override;
ExpressionLayoutCursor cursorRightOf(ExpressionLayoutCursor * cursor, bool * shouldRecomputeLayout) override;
using BracketLayout::BracketLayout;
protected:
constexpr static KDCoordinate k_bracketWidth = 5;
constexpr static KDCoordinate k_lineThickness = 1;
constexpr static KDCoordinate k_widthMargin = 5;
constexpr static KDCoordinate k_externWidthMargin = 2;
KDSize computeSize() override;
void computeBaseline() override;
KDCoordinate operandHeight();
void computeOperandHeight();
KDPoint positionOfChild(ExpressionLayout * child) override;
bool m_operandHeightComputed;
uint16_t m_operandHeight;
KDSize computeSize() override {
return KDSize(k_externWidthMargin + k_lineThickness + k_widthMargin, operandHeight() + k_lineThickness);
}
};
}