mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-19 05:40:38 +01:00
[escher/poincare] Cleaner way to find the cursored layout in LayoutField
Everything is now in the virtual method LayoutNode::layoutToPointWhenInserting This removes a dirty inclusion of apps/i18n.h in escher
This commit is contained in:
@@ -53,7 +53,7 @@ private:
|
||||
static_assert(k_maxNumberOfLayouts == TextField::maxBufferSize(), "Maximal number of layouts in a layout field should be equal to max number of char in text field");
|
||||
void scrollRightOfLayout(Poincare::Layout layoutR);
|
||||
void scrollToBaselinedRect(KDRect rect, KDCoordinate baseline);
|
||||
void insertLayoutAtCursor(Poincare::Layout layoutR, Poincare::Layout pointedLayout, bool forceCursorRightOfLayout = false);
|
||||
void insertLayoutAtCursor(Poincare::Layout layoutR, Poincare::Expression correspondingExpression, bool forceCursorRightOfLayout = false);
|
||||
|
||||
class ContentView : public View {
|
||||
public:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include <escher/layout_field.h>
|
||||
#include <apps/i18n.h>
|
||||
#include <escher/clipboard.h>
|
||||
#include <escher/text_field.h>
|
||||
#include <poincare/expression.h>
|
||||
@@ -91,6 +90,10 @@ void LayoutField::reload(KDSize previousSize) {
|
||||
}
|
||||
|
||||
bool LayoutField::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText) {
|
||||
/* The text here can be:
|
||||
* - the result of a key pressed, such as "," or "cos(•)"
|
||||
* - the text added after a toolbox selection
|
||||
* - the result of a copy-paste. */
|
||||
if (text[0] == 0) {
|
||||
// The text is empty
|
||||
return true;
|
||||
@@ -122,31 +125,18 @@ bool LayoutField::handleEventWithText(const char * text, bool indentation, bool
|
||||
} else {
|
||||
Expression resultExpression = Expression::Parse(text);
|
||||
if (resultExpression.isUninitialized()) {
|
||||
// The text is not parsable (for instance, ",") and is added char by char.
|
||||
KDSize previousLayoutSize = minimalSizeForOptimalDisplay();
|
||||
m_contentView.cursor()->insertText(text);
|
||||
reload(previousLayoutSize);
|
||||
} else {
|
||||
Layout resultLayout = resultExpression.createLayout(Poincare::Preferences::sharedPreferences()->displayMode(), Poincare::PrintFloat::k_numberOfStoredSignificantDigits);
|
||||
if (currentNumberOfLayouts + resultLayout.numberOfDescendants(true) >= k_maxNumberOfLayouts) {
|
||||
return true;
|
||||
}
|
||||
// Find the pointed layout.
|
||||
Layout pointedLayout;
|
||||
if (!forceCursorRightOfText) {
|
||||
if (strcmp(text, I18n::translate(I18n::Message::RandomCommandWithArg)) == 0) {
|
||||
/* Special case: if the text is "random()", the cursor should not be set
|
||||
* inside the parentheses. */
|
||||
pointedLayout = resultLayout;
|
||||
} else if (resultLayout.type() == LayoutNode::Type::HorizontalLayout) {
|
||||
pointedLayout = resultLayout.recursivelyMatches(
|
||||
[](Poincare::Layout layout) {
|
||||
return layout.type() == LayoutNode::Type::LeftParenthesisLayout || layout.isEmpty();});
|
||||
}
|
||||
}
|
||||
/* Insert the layout. If pointedLayout is uninitialized, the cursor will
|
||||
* be on the right of the inserted layout. */
|
||||
insertLayoutAtCursor(resultLayout, pointedLayout, forceCursorRightOfText);
|
||||
return true;
|
||||
}
|
||||
// The text is parsable, we create its layout an insert it.
|
||||
Layout resultLayout = resultExpression.createLayout(Poincare::Preferences::sharedPreferences()->displayMode(), Poincare::PrintFloat::k_numberOfStoredSignificantDigits);
|
||||
if (currentNumberOfLayouts + resultLayout.numberOfDescendants(true) >= k_maxNumberOfLayouts) {
|
||||
return true;
|
||||
}
|
||||
insertLayoutAtCursor(resultLayout, resultExpression, forceCursorRightOfText);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -285,42 +275,44 @@ void LayoutField::scrollToBaselinedRect(KDRect rect, KDCoordinate baseline) {
|
||||
scrollToContentRect(balancedRect, true);
|
||||
}
|
||||
|
||||
void LayoutField::insertLayoutAtCursor(Layout layoutR, Layout pointedLayoutR, bool forceCursorRightOfLayout) {
|
||||
void LayoutField::insertLayoutAtCursor(Layout layoutR, Poincare::Expression correspondingExpression, bool forceCursorRightOfLayout) {
|
||||
if (layoutR.isUninitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
KDSize previousSize = minimalSizeForOptimalDisplay();
|
||||
Poincare::LayoutCursor * cursor = m_contentView.cursor();
|
||||
|
||||
// Handle empty layouts
|
||||
m_contentView.cursor()->showEmptyLayoutIfNeeded();
|
||||
cursor->showEmptyLayoutIfNeeded();
|
||||
|
||||
bool layoutWillBeMerged = layoutR.type() == LayoutNode::Type::HorizontalLayout;
|
||||
Layout lastMergedLayoutChild = layoutWillBeMerged ? layoutR.childAtIndex(layoutR.numberOfChildren()-1) : Layout();
|
||||
|
||||
// Add the layout
|
||||
m_contentView.cursor()->addLayoutAndMoveCursor(layoutR);
|
||||
// Find the layout where the cursor will point
|
||||
assert(!correspondingExpression.isUninitialized());
|
||||
Layout cursorLayout = forceCursorRightOfLayout ? layoutR : layoutR.layoutToPointWhenInserting(&correspondingExpression);
|
||||
assert(!cursorLayout.isUninitialized());
|
||||
|
||||
// Move the cursor if needed
|
||||
if(!forceCursorRightOfLayout) {
|
||||
if (!pointedLayoutR.isUninitialized() && (!layoutWillBeMerged || pointedLayoutR != layoutR)) {
|
||||
// Make sure the layout was inserted (its parent is not uninitialized)
|
||||
m_contentView.cursor()->setLayout(pointedLayoutR);
|
||||
m_contentView.cursor()->setPosition(LayoutCursor::Position::Right);
|
||||
} else if (!layoutWillBeMerged) {
|
||||
m_contentView.cursor()->setLayout(layoutR.layoutToPointWhenInserting());
|
||||
m_contentView.cursor()->setPosition(LayoutCursor::Position::Right);
|
||||
}
|
||||
} else if (!layoutWillBeMerged) {
|
||||
m_contentView.cursor()->setLayout(layoutR);
|
||||
m_contentView.cursor()->setPosition(LayoutCursor::Position::Right);
|
||||
// Add the layout. This puts the cursor at the right of the added layout
|
||||
cursor->addLayoutAndMoveCursor(layoutR);
|
||||
|
||||
/* Move the cursor if needed.
|
||||
* If the layout to point to has been merged, it means that only its children
|
||||
* have been inserted in the layout, so we must not move the cursor to the
|
||||
* parent. In this case, addLayoutAndMoveCursor made the cursor point to the
|
||||
* last merged child, which is what is wanted.
|
||||
* For other cases, move the cursor to the computed layout. */
|
||||
if (!(layoutWillBeMerged && cursorLayout == layoutR)) {
|
||||
cursor->setLayout(cursorLayout);
|
||||
cursor->setPosition(LayoutCursor::Position::Right);
|
||||
}
|
||||
|
||||
// Handle matrices
|
||||
m_contentView.cursor()->layoutReference().addGreySquaresToAllMatrixAncestors();
|
||||
cursor->layoutReference().addGreySquaresToAllMatrixAncestors();
|
||||
|
||||
// Handle empty layouts
|
||||
m_contentView.cursor()->hideEmptyLayoutIfNeeded();
|
||||
cursor->hideEmptyLayoutIfNeeded();
|
||||
|
||||
// Reload
|
||||
reload(previousSize);
|
||||
|
||||
@@ -26,9 +26,9 @@ public:
|
||||
return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, Sum::s_functionHelper.name());
|
||||
}
|
||||
|
||||
LayoutNode * layoutToPointWhenInserting() override {
|
||||
LayoutNode * layoutToPointWhenInserting(Expression * correspondingExpression) override {
|
||||
assert(false);
|
||||
return nullptr;
|
||||
return this;
|
||||
}
|
||||
|
||||
// TreeNode
|
||||
|
||||
@@ -27,7 +27,7 @@ public:
|
||||
int leftCollapsingAbsorbingChildIndex() const override { return 0; }
|
||||
int rightCollapsingAbsorbingChildIndex() const override { return 1; }
|
||||
void didCollapseSiblings(LayoutCursor * cursor) override;
|
||||
LayoutNode * layoutToPointWhenInserting() override;
|
||||
LayoutNode * layoutToPointWhenInserting(Expression * correspondingExpression) override;
|
||||
bool canBeOmittedMultiplicationRightFactor() const override { return false; }
|
||||
/* WARNING: We need to override this function, else 1/2 3/4 would be
|
||||
* serialized as 1/2**3/4, as the two Fraction layouts think their sibling is
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
void moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
|
||||
LayoutCursor equivalentCursor(LayoutCursor * cursor) override;
|
||||
void deleteBeforeCursor(LayoutCursor * cursor) override;
|
||||
LayoutNode * layoutToPointWhenInserting(Expression * correspondingExpression) override;
|
||||
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
|
||||
bool isEmpty() const override { return m_numberOfChildren == 1 && const_cast<HorizontalLayoutNode *>(this)->childAtIndex(0)->isEmpty(); }
|
||||
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
void moveCursorDown(LayoutCursor * cursor, bool * shouldRecomputeLayout, bool equivalentPositionVisited = false) override;
|
||||
void deleteBeforeCursor(LayoutCursor * cursor) override;
|
||||
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
|
||||
LayoutNode * layoutToPointWhenInserting() override { return lowerBoundLayout(); }
|
||||
LayoutNode * layoutToPointWhenInserting(Expression * correspondingExpression) override { return lowerBoundLayout(); }
|
||||
CodePoint XNTCodePoint() const override { return 'x'; }
|
||||
|
||||
// TreeNode
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
namespace Poincare {
|
||||
|
||||
class LayoutCursor;
|
||||
class Expression;
|
||||
|
||||
class Layout : public TreeHandle {
|
||||
friend class GridLayoutNode;
|
||||
@@ -59,7 +60,11 @@ public:
|
||||
void deleteBeforeCursor(LayoutCursor * cursor) { return node()->deleteBeforeCursor(cursor); }
|
||||
bool removeGreySquaresFromAllMatrixAncestors() { return node()->removeGreySquaresFromAllMatrixAncestors(); }
|
||||
bool addGreySquaresToAllMatrixAncestors() { return node()->addGreySquaresToAllMatrixAncestors(); }
|
||||
Layout layoutToPointWhenInserting() { return Layout(node()->layoutToPointWhenInserting()); }
|
||||
Layout layoutToPointWhenInserting(Expression * correspondingExpression) {
|
||||
// Pointer to correspondingExpr because expression.h includes layout.h
|
||||
assert(correspondingExpression != nullptr);
|
||||
return Layout(node()->layoutToPointWhenInserting(correspondingExpression));
|
||||
}
|
||||
|
||||
// Cursor
|
||||
LayoutCursor cursor() const;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
namespace Poincare {
|
||||
|
||||
class Expression;
|
||||
class LayoutCursor;
|
||||
class Layout;
|
||||
|
||||
@@ -102,9 +103,7 @@ public:
|
||||
virtual void deleteBeforeCursor(LayoutCursor * cursor);
|
||||
|
||||
// Other
|
||||
virtual LayoutNode * layoutToPointWhenInserting() {
|
||||
return numberOfChildren() > 0 ? childAtIndex(0) : this;
|
||||
}
|
||||
virtual LayoutNode * layoutToPointWhenInserting(Expression * correspondingExpression);
|
||||
bool removeGreySquaresFromAllMatrixAncestors() { return changeGreySquaresOfAllMatrixAncestors(false); }
|
||||
bool addGreySquaresToAllMatrixAncestors() { return changeGreySquaresOfAllMatrixAncestors(true); }
|
||||
/* A layout has text if it is not empty and it is not an horizontal layout
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
void moveCursorUp(LayoutCursor * cursor, bool * shouldRecomputeLayout, bool equivalentPositionVisited = false) override;
|
||||
void moveCursorDown(LayoutCursor * cursor, bool * shouldRecomputeLayout, bool equivalentPositionVisited = false) override;
|
||||
void deleteBeforeCursor(LayoutCursor * cursor) override;
|
||||
LayoutNode * layoutToPointWhenInserting() override { return lowerBoundLayout(); }
|
||||
LayoutNode * layoutToPointWhenInserting(Expression * correspondingExpression) override { return lowerBoundLayout(); }
|
||||
CodePoint XNTCodePoint() const override { return 'n'; }
|
||||
|
||||
// TreeNode
|
||||
|
||||
@@ -166,7 +166,7 @@ int FractionLayoutNode::serialize(char * buffer, int bufferSize, Preferences::Pr
|
||||
return numberOfChar;
|
||||
}
|
||||
|
||||
LayoutNode * FractionLayoutNode::layoutToPointWhenInserting() {
|
||||
LayoutNode * FractionLayoutNode::layoutToPointWhenInserting(Expression * correspondingExpression) {
|
||||
if (numeratorLayout()->isEmpty()){
|
||||
return numeratorLayout();
|
||||
}
|
||||
|
||||
@@ -164,6 +164,21 @@ void HorizontalLayoutNode::deleteBeforeCursor(LayoutCursor * cursor) {
|
||||
LayoutNode::deleteBeforeCursor(cursor);
|
||||
}
|
||||
|
||||
LayoutNode * HorizontalLayoutNode::layoutToPointWhenInserting(Expression * correspondingExpression) {
|
||||
assert(correspondingExpression != nullptr);
|
||||
if (correspondingExpression->numberOfChildren() > 0) {
|
||||
Layout layoutToPointTo = Layout(this).recursivelyMatches(
|
||||
[](Poincare::Layout layout) {
|
||||
return layout.type() == LayoutNode::Type::LeftParenthesisLayout || layout.isEmpty();
|
||||
}
|
||||
);
|
||||
if (!layoutToPointTo.isUninitialized()) {
|
||||
return layoutToPointTo.node();
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
int HorizontalLayoutNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
|
||||
if (numberOfChildren() == 0) {
|
||||
if (bufferSize == 0) {
|
||||
|
||||
@@ -110,6 +110,11 @@ void LayoutNode::deleteBeforeCursor(LayoutCursor * cursor) {
|
||||
// WARNING: Do no use "this" afterwards
|
||||
}
|
||||
|
||||
LayoutNode * LayoutNode::layoutToPointWhenInserting(Expression * correspondingExpression) {
|
||||
assert(correspondingExpression != nullptr);
|
||||
return numberOfChildren() > 0 ? childAtIndex(0) : this;
|
||||
}
|
||||
|
||||
bool LayoutNode::willRemoveChild(LayoutNode * l, LayoutCursor * cursor, bool force) {
|
||||
if (!force) {
|
||||
Layout(this).replaceChildWithEmpty(Layout(l), cursor);
|
||||
|
||||
Reference in New Issue
Block a user