bracket_layout.cpp
6.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
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;
}
}