diff --git a/apps/calculation/app.cpp b/apps/calculation/app.cpp index be372c02c..309def628 100644 --- a/apps/calculation/app.cpp +++ b/apps/calculation/app.cpp @@ -97,8 +97,7 @@ bool App::expressionLayoutFieldDidReceiveEvent(::ExpressionLayoutField * express } int bufferLength = TextField::maxBufferSize(); char bufferForParsing[bufferLength]; - Poincare::ExpressionLayout * expressionLayout = expressionLayoutField->expressionViewWithCursor()->expressionView()->expressionLayout(); - expressionLayout->writeTextInBuffer(bufferForParsing, bufferLength); + expressionLayoutField->writeTextInBuffer(bufferForParsing, bufferLength); Expression * exp = Expression::parse(bufferForParsing); if (exp == nullptr) { expressionLayoutField->app()->displayWarning(I18n::Message::SyntaxError); diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp index 80e3f7155..f5c695662 100644 --- a/apps/calculation/edit_expression_controller.cpp +++ b/apps/calculation/edit_expression_controller.cpp @@ -177,7 +177,7 @@ void EditExpressionController::viewDidDisappear() { } Poincare::ExpressionLayout * EditExpressionController::expressionLayout() { - return ((ContentView *)view())->expressionField()->expressionLayoutField()->expressionViewWithCursor()->expressionView()->expressionLayout(); + return ((ContentView *)view())->expressionField()->expressionLayoutField()->expressionLayout(); } } diff --git a/apps/shared/expression_field_delegate_app.cpp b/apps/shared/expression_field_delegate_app.cpp index fc7943b82..870b4e351 100644 --- a/apps/shared/expression_field_delegate_app.cpp +++ b/apps/shared/expression_field_delegate_app.cpp @@ -18,13 +18,13 @@ bool ExpressionFieldDelegateApp::expressionLayoutFieldShouldFinishEditing(Expres bool ExpressionFieldDelegateApp::expressionLayoutFieldDidReceiveEvent(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) { if (expressionLayoutField->isEditing() && expressionLayoutField->expressionLayoutFieldShouldFinishEditing(event)) { - if (!expressionLayoutField->expressionViewWithCursor()->expressionView()->expressionLayout()->hasText()) { + if (!expressionLayoutField->hasText()) { expressionLayoutField->app()->displayWarning(I18n::Message::SyntaxError); return true; } int bufferSize = 256; char buffer[bufferSize]; - expressionLayoutField->expressionViewWithCursor()->expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize); + expressionLayoutField->writeTextInBuffer(buffer, bufferSize); Expression * exp = Expression::parse(buffer); if (exp != nullptr) { delete exp; diff --git a/escher/Makefile b/escher/Makefile index eae5aea8c..6ef22bc66 100644 --- a/escher/Makefile +++ b/escher/Makefile @@ -22,7 +22,6 @@ objs += $(addprefix escher/src/,\ expression_table_cell.o\ expression_table_cell_with_pointer.o\ expression_view.o\ - expression_view_with_cursor.o\ highlight_cell.o\ gauge_view.o\ image_view.o\ @@ -51,6 +50,7 @@ objs += $(addprefix escher/src/,\ scroll_view_indicator.o\ scrollable_view.o\ expression_layout_field.o\ + expression_layout_field_content_view.o\ selectable_table_view.o\ selectable_table_view_data_source.o\ selectable_table_view_delegate.o\ diff --git a/escher/include/escher/expression_layout_field.h b/escher/include/escher/expression_layout_field.h index 8e81e40c3..f8f5a412b 100644 --- a/escher/include/escher/expression_layout_field.h +++ b/escher/include/escher/expression_layout_field.h @@ -1,21 +1,26 @@ #ifndef ESCHER_EXPRESSION_LAYOUT_FIELD_H #define ESCHER_EXPRESSION_LAYOUT_FIELD_H -#include -#include +#include #include +#include +#include +#include +#include #include class ExpressionLayoutField : public ScrollableView, public ScrollViewDataSource { public: ExpressionLayoutField(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, ExpressionLayoutFieldDelegate * delegate = nullptr); void setDelegate(ExpressionLayoutFieldDelegate * delegate) { m_delegate = delegate; } - ExpressionViewWithCursor * expressionViewWithCursor() { return &m_expressionViewWithCursor; } bool isEditing() const; void setEditing(bool isEditing); void clearLayout(); void scrollToCursor(); void reload(); + bool hasText() const; + void writeTextInBuffer(char * buffer, int bufferLength); + Poincare::ExpressionLayout * expressionLayout(); /* Responder */ Toolbox * toolbox() override; @@ -32,8 +37,35 @@ public: protected: virtual bool privateHandleEvent(Ion::Events::Event event); bool privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout); - ExpressionViewWithCursor m_expressionViewWithCursor; private: + class ContentView : public View { + public: + ContentView(Poincare::ExpressionLayout * expressionLayout); + bool isEditing() const { return m_isEditing; } + void setEditing(bool isEditing); + void setCursor(Poincare::ExpressionLayoutCursor cursor) { m_cursor = cursor; } + void cursorPositionChanged(); + KDRect cursorRect(); + Poincare::ExpressionLayoutCursor * cursor() { return &m_cursor; } + const ExpressionView * expressionView() const { return &m_expressionView; } + ExpressionView * editableExpressionView() { return &m_expressionView; } + /* View */ + KDSize minimalSizeForOptimalDisplay() const override; + private: + enum class Position { + Top, + Bottom + }; + int numberOfSubviews() const override { return 2; } + View * subviewAtIndex(int index) override; + void layoutSubviews() override; + void layoutCursorSubview(); + Poincare::ExpressionLayoutCursor m_cursor; + ExpressionView m_expressionView; + TextCursorView m_cursorView; + bool m_isEditing; + }; + ContentView m_contentView; ExpressionLayoutFieldDelegate * m_delegate; }; diff --git a/escher/src/expression_field.cpp b/escher/src/expression_field.cpp index d4e0f384d..ef172771b 100644 --- a/escher/src/expression_field.cpp +++ b/escher/src/expression_field.cpp @@ -28,7 +28,7 @@ bool ExpressionField::isEditing() const { const char * ExpressionField::text() { if (!editionIsInTextField()) { - m_expressionLayoutField.expressionViewWithCursor()->expressionView()->expressionLayout()->writeTextInBuffer(m_textBody, k_bufferLength); + m_expressionLayoutField.writeTextInBuffer(m_textBody, k_bufferLength); } return m_textBody; } @@ -101,11 +101,7 @@ bool ExpressionField::editionIsInTextField() const { } bool ExpressionField::isEmpty() const { - if (editionIsInTextField()) { - return m_textField.draftTextLength() == 0; - } - Poincare::ExpressionLayout * layout = const_cast(&m_expressionLayoutField)->expressionViewWithCursor()->expressionView()->expressionLayout(); - return !layout->hasText(); + return editionIsInTextField() ? (m_textField.draftTextLength() == 0) : m_expressionLayoutField.hasText(); } bool ExpressionField::heightIsMaximal() const { diff --git a/escher/src/expression_layout_field.cpp b/escher/src/expression_layout_field.cpp index 7c5fd81f4..712fe52e7 100644 --- a/escher/src/expression_layout_field.cpp +++ b/escher/src/expression_layout_field.cpp @@ -6,29 +6,29 @@ #include ExpressionLayoutField::ExpressionLayoutField(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, ExpressionLayoutFieldDelegate * delegate) : - ScrollableView(parentResponder, &m_expressionViewWithCursor, this), - m_expressionViewWithCursor(expressionLayout), + ScrollableView(parentResponder, &m_contentView, this), + m_contentView(expressionLayout), m_delegate(delegate) { } bool ExpressionLayoutField::isEditing() const { - return m_expressionViewWithCursor.isEditing(); + return m_contentView.isEditing(); } void ExpressionLayoutField::setEditing(bool isEditing) { - m_expressionViewWithCursor.setEditing(isEditing); + m_contentView.setEditing(isEditing); } void ExpressionLayoutField::clearLayout() { - delete m_expressionViewWithCursor.expressionView()->expressionLayout(); + delete m_contentView.expressionView()->expressionLayout(); Poincare::ExpressionLayout * newLayout = new Poincare::HorizontalLayout(); - m_expressionViewWithCursor.expressionView()->setExpressionLayout(newLayout); - m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(newLayout); + m_contentView.editableExpressionView()->setExpressionLayout(newLayout); + m_contentView.cursor()->setPointedExpressionLayout(newLayout); } void ExpressionLayoutField::scrollToCursor() { - scrollToContentRect(m_expressionViewWithCursor.cursorRect(), true); + scrollToContentRect(m_contentView.cursorRect(), true); } Toolbox * ExpressionLayoutField::toolbox() { @@ -41,7 +41,7 @@ Toolbox * ExpressionLayoutField::toolbox() { bool ExpressionLayoutField::handleEvent(Ion::Events::Event event) { KDSize previousSize = minimalSizeForOptimalDisplay(); bool didHandleEvent = false; - bool shouldRecomputeLayout = m_expressionViewWithCursor.cursor()->showEmptyLayoutIfNeeded(); + bool shouldRecomputeLayout = m_contentView.cursor()->showEmptyLayoutIfNeeded(); bool moveEventChangedLayout = false; if (privateHandleMoveEvent(event, &moveEventChangedLayout)) { shouldRecomputeLayout = shouldRecomputeLayout || moveEventChangedLayout; @@ -54,9 +54,9 @@ bool ExpressionLayoutField::handleEvent(Ion::Events::Event event) { if (!isEditing()) { setEditing(true); } - shouldRecomputeLayout = m_expressionViewWithCursor.cursor()->hideEmptyLayoutIfNeeded() || shouldRecomputeLayout; + shouldRecomputeLayout = m_contentView.cursor()->hideEmptyLayoutIfNeeded() || shouldRecomputeLayout; if (!shouldRecomputeLayout) { - m_expressionViewWithCursor.cursorPositionChanged(); + m_contentView.cursorPositionChanged(); scrollToCursor(); return true; } @@ -76,28 +76,28 @@ bool ExpressionLayoutField::expressionLayoutFieldShouldFinishEditing(Ion::Events } KDSize ExpressionLayoutField::minimalSizeForOptimalDisplay() const { - return m_expressionViewWithCursor.minimalSizeForOptimalDisplay(); + return m_contentView.minimalSizeForOptimalDisplay(); } bool ExpressionLayoutField::privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout) { Poincare::ExpressionLayoutCursor result; if (event == Ion::Events::Left) { - result = m_expressionViewWithCursor.cursor()->cursorOnLeft(shouldRecomputeLayout); + result = m_contentView.cursor()->cursorOnLeft(shouldRecomputeLayout); } else if (event == Ion::Events::Right) { - result = m_expressionViewWithCursor.cursor()->cursorOnRight(shouldRecomputeLayout); + result = m_contentView.cursor()->cursorOnRight(shouldRecomputeLayout); } else if (event == Ion::Events::Up) { - result = m_expressionViewWithCursor.cursor()->cursorAbove(shouldRecomputeLayout); + result = m_contentView.cursor()->cursorAbove(shouldRecomputeLayout); } else if (event == Ion::Events::Down) { - result = m_expressionViewWithCursor.cursor()->cursorUnder(shouldRecomputeLayout); + result = m_contentView.cursor()->cursorUnder(shouldRecomputeLayout); } else if (event == Ion::Events::ShiftLeft) { - result.setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout()); + result.setPointedExpressionLayout(m_contentView.expressionView()->expressionLayout()); result.setPosition(Poincare::ExpressionLayoutCursor::Position::Left); } else if (event == Ion::Events::ShiftRight) { - result.setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout()); + result.setPointedExpressionLayout(m_contentView.expressionView()->expressionLayout()); result.setPosition(Poincare::ExpressionLayoutCursor::Position::Right); } if (result.isDefined()) { - m_expressionViewWithCursor.setCursor(result); + m_contentView.setCursor(result); return true; } return false; @@ -119,19 +119,19 @@ bool ExpressionLayoutField::privateHandleEvent(Ion::Events::Event event) { setEditing(false); int bufferSize = TextField::maxBufferSize(); char buffer[bufferSize]; - m_expressionViewWithCursor.expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize); + m_contentView.expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize); if (m_delegate->expressionLayoutFieldDidFinishEditing(this, buffer, event)) { - delete m_expressionViewWithCursor.expressionView()->expressionLayout(); + delete m_contentView.expressionView()->expressionLayout(); Poincare::ExpressionLayout * newLayout = new Poincare::HorizontalLayout(); - m_expressionViewWithCursor.expressionView()->setExpressionLayout(newLayout); - m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(newLayout); + m_contentView.editableExpressionView()->setExpressionLayout(newLayout); + m_contentView.cursor()->setPointedExpressionLayout(newLayout); } return true; } if ((event == Ion::Events::OK || event == Ion::Events::EXE) && !isEditing()) { setEditing(true); - m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout()); - m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); + m_contentView.cursor()->setPointedExpressionLayout(m_contentView.expressionView()->expressionLayout()); + m_contentView.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); return true; } if (event == Ion::Events::Back && isEditing()) { @@ -140,27 +140,27 @@ bool ExpressionLayoutField::privateHandleEvent(Ion::Events::Event event) { return true; } if (event == Ion::Events::Division) { - m_expressionViewWithCursor.cursor()->addFractionLayoutAndCollapseSiblings(); + m_contentView.cursor()->addFractionLayoutAndCollapseSiblings(); return true; } if (event == Ion::Events::XNT) { - m_expressionViewWithCursor.cursor()->addXNTCharLayout(); + m_contentView.cursor()->addXNTCharLayout(); return true; } if (event == Ion::Events::Exp) { - m_expressionViewWithCursor.cursor()->addEmptyExponentialLayout(); + m_contentView.cursor()->addEmptyExponentialLayout(); return true; } if (event == Ion::Events::Power) { - m_expressionViewWithCursor.cursor()->addEmptyPowerLayout(); + m_contentView.cursor()->addEmptyPowerLayout(); return true; } if (event == Ion::Events::Sqrt) { - m_expressionViewWithCursor.cursor()->addEmptySquareRootLayout(); + m_contentView.cursor()->addEmptySquareRootLayout(); return true; } if (event == Ion::Events::Square) { - m_expressionViewWithCursor.cursor()->addEmptySquarePowerLayout(); + m_contentView.cursor()->addEmptySquarePowerLayout(); return true; } if (event.hasText()) { @@ -168,19 +168,19 @@ bool ExpressionLayoutField::privateHandleEvent(Ion::Events::Event event) { if (textToInsert[1] == 0) { if (textToInsert[0] == Ion::Charset::MultiplicationSign) { const char middleDotString[] = {Ion::Charset::MiddleDot, 0}; - m_expressionViewWithCursor.cursor()->insertText(middleDotString); + m_contentView.cursor()->insertText(middleDotString); return true; } if (textToInsert[0] == '[' || textToInsert[0] == ']') { - m_expressionViewWithCursor.cursor()->addEmptyMatrixLayout(); + m_contentView.cursor()->addEmptyMatrixLayout(); return true; } } - m_expressionViewWithCursor.cursor()->insertText(textToInsert); + m_contentView.cursor()->insertText(textToInsert); return true; } if (event == Ion::Events::Backspace) { - m_expressionViewWithCursor.cursor()->performBackspace(); + m_contentView.cursor()->performBackspace(); return true; } if (event == Ion::Events::Paste) { @@ -201,21 +201,21 @@ void ExpressionLayoutField::insertLayoutAtCursor(Poincare::ExpressionLayout * la if (layout == nullptr) { return; } - m_expressionViewWithCursor.cursor()->showEmptyLayoutIfNeeded(); + m_contentView.cursor()->showEmptyLayoutIfNeeded(); KDSize previousSize = minimalSizeForOptimalDisplay(); if (layout->isMatrix() && pointedLayout && pointedLayout->hasAncestor(layout)) { static_cast(layout)->addGreySquares(); } bool layoutWillBeMerged = layout->isHorizontal(); - m_expressionViewWithCursor.cursor()->addLayoutAndMoveCursor(layout); + m_contentView.cursor()->addLayoutAndMoveCursor(layout); if (pointedLayout != nullptr) { - m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(pointedLayout); - m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); + m_contentView.cursor()->setPointedExpressionLayout(pointedLayout); + m_contentView.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); } else if (!layoutWillBeMerged) { - m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(layout->layoutToPointWhenInserting()); - m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); + m_contentView.cursor()->setPointedExpressionLayout(layout->layoutToPointWhenInserting()); + m_contentView.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right); } - m_expressionViewWithCursor.cursor()->hideEmptyLayoutIfNeeded(); + m_contentView.cursor()->hideEmptyLayoutIfNeeded(); reload(); KDSize newSize = minimalSizeForOptimalDisplay(); if (m_delegate && previousSize.height() != newSize.height()) { @@ -228,23 +228,35 @@ void ExpressionLayoutField::insertLayoutFromTextAtCursor(const char * text) { if (expression != nullptr) { Poincare::ExpressionLayout * layout = expression->createLayout(); delete expression; - m_expressionViewWithCursor.cursor()->showEmptyLayoutIfNeeded(); + m_contentView.cursor()->showEmptyLayoutIfNeeded(); insertLayoutAtCursor(layout, nullptr); - m_expressionViewWithCursor.cursor()->hideEmptyLayoutIfNeeded(); + m_contentView.cursor()->hideEmptyLayoutIfNeeded(); reload(); return; } - m_expressionViewWithCursor.cursor()->showEmptyLayoutIfNeeded(); - m_expressionViewWithCursor.cursor()->insertText(text); - m_expressionViewWithCursor.cursor()->hideEmptyLayoutIfNeeded(); + m_contentView.cursor()->showEmptyLayoutIfNeeded(); + m_contentView.cursor()->insertText(text); + m_contentView.cursor()->hideEmptyLayoutIfNeeded(); reload(); } void ExpressionLayoutField::reload() { - m_expressionViewWithCursor.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines(); + m_contentView.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines(); layoutSubviews(); m_delegate->expressionLayoutFieldDidChangeSize(this); scrollToCursor(); - m_expressionViewWithCursor.cursorPositionChanged(); + m_contentView.cursorPositionChanged(); markRectAsDirty(bounds()); } + +bool ExpressionLayoutField::hasText() const { + return m_contentView.expressionView()->expressionLayout()->isEmpty(); +} + +void ExpressionLayoutField::writeTextInBuffer(char * buffer, int bufferLength) { + m_contentView.expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferLength); +} + +Poincare::ExpressionLayout * ExpressionLayoutField::expressionLayout() { + return m_contentView.expressionView()->expressionLayout(); +} diff --git a/escher/src/expression_view_with_cursor.cpp b/escher/src/expression_layout_field_content_view.cpp similarity index 74% rename from escher/src/expression_view_with_cursor.cpp rename to escher/src/expression_layout_field_content_view.cpp index 657ca5b32..f20dcd1ca 100644 --- a/escher/src/expression_view_with_cursor.cpp +++ b/escher/src/expression_layout_field_content_view.cpp @@ -1,10 +1,10 @@ -#include +#include #include #include using namespace Poincare; -ExpressionViewWithCursor::ExpressionViewWithCursor(ExpressionLayout * expressionLayout) : +ExpressionLayoutField::ContentView::ContentView(ExpressionLayout * expressionLayout) : m_cursor(), m_expressionView(), m_cursorView(), @@ -15,21 +15,21 @@ ExpressionViewWithCursor::ExpressionViewWithCursor(ExpressionLayout * expression m_expressionView.setExpressionLayout(expressionLayout); } -void ExpressionViewWithCursor::setEditing(bool isEditing) { +void ExpressionLayoutField::ContentView::setEditing(bool isEditing) { m_isEditing = isEditing; markRectAsDirty(bounds()); layoutSubviews(); } -void ExpressionViewWithCursor::cursorPositionChanged() { +void ExpressionLayoutField::ContentView::cursorPositionChanged() { layoutCursorSubview(); } -KDRect ExpressionViewWithCursor::cursorRect() { +KDRect ExpressionLayoutField::ContentView::cursorRect() { return m_cursorView.frame(); } -KDSize ExpressionViewWithCursor::minimalSizeForOptimalDisplay() const { +KDSize ExpressionLayoutField::ContentView::minimalSizeForOptimalDisplay() const { KDSize expressionViewSize = m_expressionView.minimalSizeForOptimalDisplay(); KDSize cursorSize = isEditing() ? m_cursorView.minimalSizeForOptimalDisplay() : KDSizeZero; KDCoordinate resultWidth = expressionViewSize.width() + cursorSize.width(); @@ -37,18 +37,18 @@ KDSize ExpressionViewWithCursor::minimalSizeForOptimalDisplay() const { return KDSize(resultWidth, resultHeight); } -View * ExpressionViewWithCursor::subviewAtIndex(int index) { +View * ExpressionLayoutField::ContentView::subviewAtIndex(int index) { assert(index >= 0 && index < 2); View * m_views[] = {&m_expressionView, &m_cursorView}; return m_views[index]; } -void ExpressionViewWithCursor::layoutSubviews() { +void ExpressionLayoutField::ContentView::layoutSubviews() { m_expressionView.setFrame(bounds()); layoutCursorSubview(); } -void ExpressionViewWithCursor::layoutCursorSubview() { +void ExpressionLayoutField::ContentView::layoutCursorSubview() { if (!m_isEditing) { m_cursorView.setFrame(KDRectZero); return;