mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-29 03:29:58 +02:00
[escher/layout_field] Better handling of layout recomputation
After a selection event, there is no need to recompute the layout. We still need to dirty the union of the previous and next selection rectangles.
This commit is contained in:
@@ -86,6 +86,7 @@ private:
|
||||
View * subviewAtIndex(int index) override;
|
||||
void layoutSubviews(bool force = false) override;
|
||||
void layoutCursorSubview(bool force);
|
||||
KDRect computeSelectionRect() const;
|
||||
Poincare::LayoutCursor m_cursor;
|
||||
ExpressionView m_expressionView;
|
||||
TextCursorView m_cursorView;
|
||||
|
||||
@@ -56,6 +56,7 @@ bool IsBefore(Layout& l1, Layout& l2, bool strict) {
|
||||
}
|
||||
|
||||
void LayoutField::ContentView::addSelection(Layout addedLayout) {
|
||||
KDRect rectBefore = computeSelectionRect();
|
||||
if (selectionIsEmpty()) {
|
||||
/*
|
||||
* ---------- -> +++ is the previous previous selection
|
||||
@@ -121,7 +122,10 @@ void LayoutField::ContentView::addSelection(Layout addedLayout) {
|
||||
}
|
||||
}
|
||||
}
|
||||
//reloadRectFromAndToPositions(left, right); TODO LEA
|
||||
|
||||
KDRect rectAfter = computeSelectionRect();
|
||||
// We need to update the background color for selected/unselected layouts
|
||||
markRectAsDirty(rectBefore.unionedWith(rectAfter));
|
||||
}
|
||||
|
||||
bool LayoutField::ContentView::resetSelection() {
|
||||
@@ -222,6 +226,20 @@ void LayoutField::ContentView::layoutCursorSubview(bool force) {
|
||||
m_cursorView.setFrame(KDRect(cursorTopLeftPosition, LayoutCursor::k_cursorWidth, m_cursor.cursorHeight()), force);
|
||||
}
|
||||
|
||||
KDRect LayoutField::ContentView::computeSelectionRect() const {
|
||||
if (selectionIsEmpty()) {
|
||||
return KDRectZero;
|
||||
}
|
||||
if (m_selectionStart == m_selectionEnd) {
|
||||
return KDRect(m_selectionStart.absoluteOrigin(), m_selectionStart.layoutSize());
|
||||
}
|
||||
Layout selectionParent = m_selectionStart.parent();
|
||||
assert(m_selectionEnd.parent() == selectionParent);
|
||||
assert(selectionParent.type() == LayoutNode::Type::HorizontalLayout);
|
||||
KDRect selectionRectInParent = static_cast<HorizontalLayout &>(selectionParent).relativeSelectionRect(&m_selectionStart, &m_selectionEnd);
|
||||
return selectionRectInParent.translatedBy(selectionParent.absoluteOrigin());
|
||||
}
|
||||
|
||||
void LayoutField::setEditing(bool isEditing) {
|
||||
KDSize previousLayoutSize = m_contentView.minimalSizeForOptimalDisplay();
|
||||
if (m_contentView.setEditing(isEditing)) {
|
||||
@@ -317,7 +335,6 @@ bool LayoutField::handleEvent(Ion::Events::Event event) {
|
||||
didHandleEvent = true;
|
||||
} else if (privateHandleSelectionEvent(event, &shouldRecomputeLayout)) {
|
||||
didHandleEvent = true;
|
||||
shouldRecomputeLayout = true; //TODO LEA
|
||||
} else if (privateHandleEvent(event)) {
|
||||
shouldRecomputeLayout = true;
|
||||
didHandleEvent = true;
|
||||
|
||||
@@ -8,9 +8,11 @@ namespace Poincare {
|
||||
|
||||
/* WARNING: A HorizontalLayout should never have a HorizontalLayout child. For
|
||||
* instance, use addOrMergeChildAtIndex to add a LayoutNode safely. */
|
||||
class HorizontalLayout;
|
||||
|
||||
class HorizontalLayoutNode final : public LayoutNode {
|
||||
friend class Layout;
|
||||
friend class HorizontalLayout;
|
||||
public:
|
||||
|
||||
HorizontalLayoutNode() :
|
||||
@@ -55,6 +57,7 @@ protected:
|
||||
KDSize computeSize() override;
|
||||
KDCoordinate computeBaseline() override;
|
||||
KDPoint positionOfChild(LayoutNode * l) override;
|
||||
KDRect relativeSelectionRect(const Layout * selectionStart, const Layout * selectionEnd) const;
|
||||
|
||||
private:
|
||||
bool willAddChildAtIndex(LayoutNode * l, int * index, int * currentNumberOfChildren, LayoutCursor * cursor) override;
|
||||
@@ -93,6 +96,8 @@ public:
|
||||
Layout squashUnaryHierarchyInPlace();
|
||||
|
||||
void serializeChildren(int firstIndex, int lastIndex, char * buffer, int bufferSize);
|
||||
|
||||
KDRect relativeSelectionRect(const Layout * selectionStart, const Layout * selectionEnd) const { return static_cast<HorizontalLayoutNode *>(node())->relativeSelectionRect(selectionStart, selectionEnd); }
|
||||
private:
|
||||
void removeEmptyChildBeforeInsertionAtIndex(int * index, int * currentNumberOfChildren, bool shouldRemoveOnLeft, LayoutCursor * cursor = nullptr);
|
||||
};
|
||||
|
||||
@@ -37,8 +37,8 @@ public:
|
||||
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor, Layout * selectionStart = nullptr, Layout * selectionEnd = nullptr, KDColor selectionColor = KDColorRed) {
|
||||
return node()->render(ctx, p, expressionColor, backgroundColor, selectionStart, selectionEnd, selectionColor);
|
||||
}
|
||||
KDSize layoutSize() { return node()->layoutSize(); }
|
||||
KDPoint absoluteOrigin() { return node()->absoluteOrigin(); }
|
||||
KDSize layoutSize() const { return node()->layoutSize(); }
|
||||
KDPoint absoluteOrigin() const { return node()->absoluteOrigin(); }
|
||||
KDCoordinate baseline() { return node()->baseline(); }
|
||||
void invalidAllSizesPositionsAndBaselines() { return node()->invalidAllSizesPositionsAndBaselines(); }
|
||||
|
||||
|
||||
@@ -56,8 +56,8 @@ public:
|
||||
}
|
||||
|
||||
/* Comparison */
|
||||
inline bool operator==(const TreeHandle& t) { return m_identifier == t.identifier(); }
|
||||
inline bool operator!=(const TreeHandle& t) { return m_identifier != t.identifier(); }
|
||||
inline bool operator==(const TreeHandle& t) const { return m_identifier == t.identifier(); }
|
||||
inline bool operator!=(const TreeHandle& t) const { return m_identifier != t.identifier(); }
|
||||
|
||||
/* Clone */
|
||||
TreeHandle clone() const;
|
||||
|
||||
@@ -287,6 +287,37 @@ KDPoint HorizontalLayoutNode::positionOfChild(LayoutNode * l) {
|
||||
return KDPoint(x, y);
|
||||
}
|
||||
|
||||
KDRect HorizontalLayoutNode::relativeSelectionRect(const Layout * selectionStart, const Layout * selectionEnd) const {
|
||||
assert(selectionStart != nullptr && !selectionStart->isUninitialized());
|
||||
assert(selectionEnd != nullptr && !selectionEnd->isUninitialized());
|
||||
HorizontalLayout thisLayout = HorizontalLayout(const_cast<HorizontalLayoutNode *>(this));
|
||||
assert(thisLayout.hasChild(*selectionStart));
|
||||
assert(thisLayout.hasChild(*selectionEnd));
|
||||
assert(thisLayout.indexOfChild(*selectionStart) <= thisLayout.indexOfChild(*selectionEnd));
|
||||
|
||||
// Compute the positions
|
||||
KDCoordinate selectionXStart = const_cast<HorizontalLayoutNode *>(this)->positionOfChild(selectionStart->node()).x();
|
||||
KDCoordinate selectionXEnd = const_cast<HorizontalLayoutNode *>(this)->positionOfChild(selectionEnd->node()).x() + selectionEnd->layoutSize().width();
|
||||
KDCoordinate drawWidth = selectionXEnd - selectionXStart;
|
||||
|
||||
// Compute the height
|
||||
int firstSelectedNodeIndex = thisLayout.indexOfChild(*selectionStart);
|
||||
int secondSelectedNodeIndex = thisLayout.indexOfChild(*selectionEnd);
|
||||
if (firstSelectedNodeIndex == 0 && secondSelectedNodeIndex == numberOfChildren() - 1) {
|
||||
return KDRect(KDPointZero, const_cast<HorizontalLayoutNode *>(this)->layoutSize());
|
||||
}
|
||||
KDCoordinate maxUnderBaseline = 0;
|
||||
KDCoordinate maxAboveBaseline = 0;
|
||||
for (int i = firstSelectedNodeIndex; i <= secondSelectedNodeIndex; i++) {
|
||||
Layout childi = thisLayout.childAtIndex(i);
|
||||
KDSize childSize = childi.layoutSize();
|
||||
maxUnderBaseline = maxCoordinate(maxUnderBaseline, childSize.height() - childi.baseline());
|
||||
maxAboveBaseline = maxCoordinate(maxAboveBaseline, childi.baseline());
|
||||
}
|
||||
return KDRect(KDPoint(selectionXStart, const_cast<HorizontalLayoutNode *>(this)->baseline() - maxAboveBaseline), KDSize(drawWidth, maxUnderBaseline + maxAboveBaseline));
|
||||
}
|
||||
|
||||
|
||||
// Private
|
||||
|
||||
bool HorizontalLayoutNode::willAddChildAtIndex(LayoutNode * l, int * index, int * currentNumberOfChildren, LayoutCursor * cursor) {
|
||||
@@ -427,29 +458,8 @@ void HorizontalLayoutNode::render(KDContext * ctx, KDPoint p, KDColor expression
|
||||
&& thisLayout.hasChild(*selectionStart);
|
||||
if (childrenAreSelected) {
|
||||
assert(thisLayout.hasChild(*selectionEnd));
|
||||
|
||||
// Compute the positions
|
||||
KDCoordinate selectionXStart = positionOfChild(selectionStart->node()).x();
|
||||
KDCoordinate selectionXEnd = positionOfChild(selectionEnd->node()).x() + selectionEnd->layoutSize().width();
|
||||
KDCoordinate drawX = p.x() + selectionXStart;
|
||||
KDCoordinate drawWidth = selectionXEnd - selectionXStart;
|
||||
|
||||
// Compute the height
|
||||
int firstSelectedNodeIndex = thisLayout.indexOfChild(*selectionStart);
|
||||
int secondSelectedNodeIndex = thisLayout.indexOfChild(*selectionEnd);
|
||||
if (firstSelectedNodeIndex == 0 && secondSelectedNodeIndex == numberOfChildren() - 1) {
|
||||
ctx->fillRect(KDRect(KDPoint(drawX, p.y()), KDSize(drawWidth, s.height())), selectionColor);
|
||||
return;
|
||||
}
|
||||
KDCoordinate maxUnderBaseline = 0;
|
||||
KDCoordinate maxAboveBaseline = 0;
|
||||
for (int i = firstSelectedNodeIndex; i <= secondSelectedNodeIndex; i++) {
|
||||
Layout childi = thisLayout.childAtIndex(i);
|
||||
KDSize childSize = childi.layoutSize();
|
||||
maxUnderBaseline = maxCoordinate(maxUnderBaseline, childSize.height() - childi.baseline());
|
||||
maxAboveBaseline = maxCoordinate(maxAboveBaseline, childi.baseline());
|
||||
}
|
||||
ctx->fillRect(KDRect(KDPoint(drawX, p.y() + baseline() - maxAboveBaseline), KDSize(drawWidth, maxUnderBaseline + maxAboveBaseline)), selectionColor);
|
||||
KDRect selectionRectangle = HorizontalLayout(this).relativeSelectionRect(selectionStart, selectionEnd);
|
||||
ctx->fillRect(selectionRectangle.translatedBy(p), selectionColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,6 @@ void LayoutCursor::select(Direction direction, bool * shouldRecomputeLayout, Lay
|
||||
} else {
|
||||
selectUpDown(direction == Direction::Up, shouldRecomputeLayout, selection);
|
||||
}
|
||||
*shouldRecomputeLayout = true;
|
||||
}
|
||||
|
||||
/* Layout modification */
|
||||
|
||||
Reference in New Issue
Block a user