[apps/escher] EVWithCursor becomes ELField::ContentView

Change-Id: I719218e4d1d360800e0f1ef3eebeea774c8d5660
This commit is contained in:
Léa Saviot
2018-04-20 16:36:07 +02:00
parent 22ab94209f
commit 894080f1ab
8 changed files with 113 additions and 74 deletions

View File

@@ -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);

View File

@@ -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();
}
}

View File

@@ -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;

View File

@@ -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\

View File

@@ -1,21 +1,26 @@
#ifndef ESCHER_EXPRESSION_LAYOUT_FIELD_H
#define ESCHER_EXPRESSION_LAYOUT_FIELD_H
#include <escher/scrollable_view.h>
#include <escher/expression_view_with_cursor.h>
#include <escher/expression_view.h>
#include <escher/expression_layout_field_delegate.h>
#include <escher/scrollable_view.h>
#include <escher/text_cursor_view.h>
#include <kandinsky/point.h>
#include <poincare/expression_layout.h>
#include <poincare/expression_layout_cursor.h>
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;
};

View File

@@ -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<ExpressionLayoutField *>(&m_expressionLayoutField)->expressionViewWithCursor()->expressionView()->expressionLayout();
return !layout->hasText();
return editionIsInTextField() ? (m_textField.draftTextLength() == 0) : m_expressionLayoutField.hasText();
}
bool ExpressionField::heightIsMaximal() const {

View File

@@ -6,29 +6,29 @@
#include <assert.h>
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<Poincare::MatrixLayout *>(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();
}

View File

@@ -1,10 +1,10 @@
#include <escher/expression_view_with_cursor.h>
#include <escher/expression_layout_field.h>
#include <kandinsky/rect.h>
#include <assert.h>
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;