mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-19 05:40:38 +01:00
153 lines
5.8 KiB
C++
153 lines
5.8 KiB
C++
#include <poincare/bracket_layout.h>
|
|
#include <escher/metric.h>
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
|
|
namespace Poincare {
|
|
|
|
static inline KDCoordinate max(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; }
|
|
|
|
void BracketLayoutNode::moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) {
|
|
assert(cursor->layoutNode() == this);
|
|
if (cursor->position() == LayoutCursor::Position::Right) {
|
|
// Case: Right. Go Left.
|
|
cursor->setPosition(LayoutCursor::Position::Left);
|
|
return;
|
|
}
|
|
assert(cursor->position() == LayoutCursor::Position::Left);
|
|
// Case: Left. Ask the parent.
|
|
LayoutNode * parentLayout = parent();
|
|
if (parentLayout != nullptr) {
|
|
parentLayout->moveCursorLeft(cursor, shouldRecomputeLayout);
|
|
}
|
|
}
|
|
|
|
void BracketLayoutNode::moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) {
|
|
assert(cursor->layoutNode() == this);
|
|
if (cursor->position() == LayoutCursor::Position::Left) {
|
|
// Case: Left. Go Right.
|
|
cursor->setPosition(LayoutCursor::Position::Right);
|
|
return;
|
|
}
|
|
assert(cursor->position() == LayoutCursor::Position::Right);
|
|
// Case: Right. Ask the parent.
|
|
LayoutNode * parentLayout = parent();
|
|
if (parentLayout != nullptr) {
|
|
parentLayout->moveCursorRight(cursor, shouldRecomputeLayout);
|
|
}
|
|
}
|
|
|
|
void BracketLayoutNode::invalidAllSizesPositionsAndBaselines() {
|
|
m_childHeightComputed = false;
|
|
LayoutNode::invalidAllSizesPositionsAndBaselines();
|
|
}
|
|
|
|
KDCoordinate BracketLayoutNode::computeBaseline() {
|
|
LayoutNode * parentLayout = parent();
|
|
assert(parentLayout != nullptr);
|
|
int idxInParent = parentLayout->indexOfChild(this);
|
|
int numberOfSiblings = parentLayout->numberOfChildren();
|
|
if (((isLeftParenthesis() || isLeftBracket()) && idxInParent == numberOfSiblings - 1)
|
|
|| ((isRightParenthesis() || isRightBracket()) && idxInParent == 0)
|
|
|| ((isLeftParenthesis() || isLeftBracket()) && idxInParent < numberOfSiblings - 1 && parentLayout->childAtIndex(idxInParent + 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.*/
|
|
return layoutSize().height()/2;
|
|
}
|
|
|
|
int currentNumberOfOpenBrackets = 1;
|
|
KDCoordinate result = 0;
|
|
int increment = (isLeftParenthesis() || isLeftBracket()) ? 1 : -1;
|
|
for (int i = idxInParent + increment; i >= 0 && i < numberOfSiblings; i+=increment) {
|
|
LayoutNode * sibling = parentLayout->childAtIndex(i);
|
|
if ((isLeftParenthesis() && sibling->isRightParenthesis())
|
|
|| (isLeftBracket() && sibling->isRightBracket())
|
|
|| (isRightParenthesis() && sibling->isLeftParenthesis())
|
|
|| (isRightBracket() && sibling->isLeftBracket()))
|
|
{
|
|
if (i == idxInParent + increment) {
|
|
/* If the bracket is immediately closed, we set the baseline to half the
|
|
* bracket height. */
|
|
return layoutSize().height()/2;
|
|
}
|
|
currentNumberOfOpenBrackets--;
|
|
if (currentNumberOfOpenBrackets == 0) {
|
|
break;
|
|
}
|
|
} else if ((isLeftParenthesis() && sibling->isLeftParenthesis())
|
|
|| (isLeftBracket() && sibling->isLeftBracket())
|
|
|| (isRightParenthesis() && sibling->isRightParenthesis())
|
|
|| (isRightBracket() && sibling->isRightBracket()))
|
|
{
|
|
currentNumberOfOpenBrackets++;
|
|
}
|
|
result = max(result, sibling->baseline());
|
|
}
|
|
return result + (layoutSize().height() - childHeight()) / 2;
|
|
}
|
|
|
|
KDCoordinate BracketLayoutNode::childHeight() {
|
|
if (!m_childHeightComputed) {
|
|
m_childHeight = computeChildHeight();
|
|
m_childHeightComputed = true;
|
|
}
|
|
return m_childHeight;
|
|
}
|
|
|
|
KDCoordinate BracketLayoutNode::computeChildHeight() {
|
|
LayoutNode * parentLayout = parent();
|
|
assert(parentLayout != nullptr);
|
|
KDCoordinate result = Metric::MinimalBracketAndParenthesisHeight;
|
|
int idxInParent = parentLayout->indexOfChild(this);
|
|
int numberOfSiblings = parentLayout->numberOfChildren();
|
|
if ((isLeftParenthesis() || isLeftBracket())
|
|
&& idxInParent < numberOfSiblings - 1
|
|
&& parentLayout->childAtIndex(idxInParent + 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. */
|
|
return result;
|
|
}
|
|
|
|
KDCoordinate maxUnderBaseline = 0;
|
|
KDCoordinate maxAboveBaseline = 0;
|
|
|
|
int currentNumberOfOpenBrackets = 1;
|
|
int increment = (isLeftParenthesis() || isLeftBracket()) ? 1 : -1;
|
|
for (int i = idxInParent + increment; i >= 0 && i < numberOfSiblings; i+= increment) {
|
|
LayoutNode * sibling = parentLayout->childAtIndex(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->layoutSize().height();
|
|
KDCoordinate siblingBaseline = sibling->baseline();
|
|
maxUnderBaseline = max(maxUnderBaseline, siblingHeight - siblingBaseline);
|
|
maxAboveBaseline = max(maxAboveBaseline, siblingBaseline);
|
|
}
|
|
return max(result, maxUnderBaseline + maxAboveBaseline);
|
|
}
|
|
|
|
KDPoint BracketLayoutNode::positionOfChild(LayoutNode * child) {
|
|
assert(false);
|
|
return KDPointZero;
|
|
}
|
|
|
|
}
|