mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-27 01:29:58 +01:00
[apps/calculation] EditableExpressionView in calculation app.
Change-Id: I8b67353682652695f7296f0222939930f4b21794
This commit is contained in:
@@ -43,7 +43,7 @@ void App::Snapshot::tidy() {
|
||||
}
|
||||
|
||||
App::App(Container * container, Snapshot * snapshot) :
|
||||
TextFieldDelegateApp(container, snapshot, &m_editExpressionController),
|
||||
TextFieldAndEditableExpressionViewDelegateApp(container, snapshot, &m_editExpressionController),
|
||||
m_localContext((GlobalContext *)((AppsContainer *)container)->globalContext(), snapshot->calculationStore()),
|
||||
m_historyController(&m_editExpressionController, snapshot->calculationStore()),
|
||||
m_editExpressionController(&m_modalViewController, &m_historyController, snapshot->calculationStore())
|
||||
@@ -80,6 +80,36 @@ bool App::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event e
|
||||
return false;
|
||||
}
|
||||
|
||||
bool App::editableExpressionViewDidReceiveEvent(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) {
|
||||
if ((event == Ion::Events::Var || event == Ion::Events::XNT) && TextFieldAndEditableExpressionViewDelegateApp::editableExpressionViewDidReceiveEvent(editableExpressionView, event)) {
|
||||
return true;
|
||||
}
|
||||
/* Here, we check that the expression entered by the user can be printed with
|
||||
* less than k_printedExpressionLength characters. Otherwise, we prevent the
|
||||
* user from adding this expression to the calculation store. */
|
||||
if (editableExpressionView->isEditing() && editableExpressionView->editableExpressionViewShouldFinishEditing(event)) {
|
||||
int bufferLength = TextField::maxBufferSize();
|
||||
char bufferForParsing[bufferLength];
|
||||
Poincare::ExpressionLayout * expressionLayout = editableExpressionView->expressionViewWithCursor()->expressionView()->expressionLayout();
|
||||
expressionLayout->writeTextInBuffer(bufferForParsing, bufferLength);
|
||||
Expression * exp = Expression::parse(bufferForParsing);
|
||||
if (exp == nullptr) {
|
||||
editableExpressionView->app()->displayWarning(I18n::Message::SyntaxError);
|
||||
return true;
|
||||
}
|
||||
char buffer[Calculation::k_printedExpressionSize];
|
||||
int length = exp->writeTextInBuffer(buffer, sizeof(buffer));
|
||||
delete exp;
|
||||
/* if the buffer is totally full, it is VERY likely that writeTextInBuffer
|
||||
* escaped before printing utterly the expression. */
|
||||
if (length >= Calculation::k_printedExpressionSize-1) {
|
||||
displayWarning(I18n::Message::SyntaxError);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char * App::XNT() {
|
||||
return "x";
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
class App : public Shared::TextFieldDelegateApp {
|
||||
class App : public Shared::TextFieldAndEditableExpressionViewDelegateApp {
|
||||
public:
|
||||
class Descriptor : public ::App::Descriptor {
|
||||
public:
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
};
|
||||
Poincare::Context * localContext() override;
|
||||
bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override;
|
||||
bool editableExpressionViewDidReceiveEvent(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) override;
|
||||
const char * XNT() override;
|
||||
private:
|
||||
App(Container * container, Snapshot * snapshot);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "edit_expression_controller.h"
|
||||
#include "../apps_container.h"
|
||||
#include "ion/display.h"
|
||||
#include "app.h"
|
||||
#include <assert.h>
|
||||
|
||||
@@ -7,10 +8,11 @@ using namespace Shared;
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate) :
|
||||
EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, EditableExpressionViewDelegate * editableExpressionViewDelegate) :
|
||||
View(),
|
||||
m_mainView(subview),
|
||||
m_textField(parentResponder, m_textBody, TextField::maxBufferSize(), textFieldDelegate)
|
||||
m_textField(parentResponder, m_textBody, TextField::maxBufferSize(), textFieldDelegate),
|
||||
m_editableExpressionView(parentResponder, new Poincare::HorizontalLayout(), editableExpressionViewDelegate)
|
||||
{
|
||||
m_textBody[0] = 0;
|
||||
}
|
||||
@@ -20,30 +22,55 @@ int EditExpressionController::ContentView::numberOfSubviews() const {
|
||||
}
|
||||
|
||||
View * EditExpressionController::ContentView::subviewAtIndex(int index) {
|
||||
View * views[2] = {m_mainView, &m_textField};
|
||||
return views[index];
|
||||
assert(index >= 0 && index < numberOfSubviews());
|
||||
if (index == 0) {
|
||||
return m_mainView;
|
||||
}
|
||||
assert(index == 1);
|
||||
if (editionIsInTextField()) {
|
||||
return &m_textField;
|
||||
}
|
||||
return &m_editableExpressionView;
|
||||
}
|
||||
|
||||
void EditExpressionController::ContentView::layoutSubviews() {
|
||||
KDRect mainViewFrame(0, 0, bounds().width(), bounds().height() - k_textFieldHeight-k_separatorThickness);
|
||||
KDCoordinate inputViewFrameHeight = inputViewHeight();
|
||||
KDRect mainViewFrame(0, 0, bounds().width(), bounds().height() - inputViewFrameHeight-k_separatorThickness);
|
||||
m_mainView->setFrame(mainViewFrame);
|
||||
KDRect inputViewFrame(k_textMargin, bounds().height() - k_textFieldHeight, bounds().width()-k_textMargin, k_textFieldHeight);
|
||||
m_textField.setFrame(inputViewFrame);
|
||||
if (editionIsInTextField()) {
|
||||
KDRect inputViewFrame(k_leftMargin, bounds().height() - inputViewFrameHeight + k_verticalMargin, bounds().width()-k_leftMargin, k_textFieldHeight - k_verticalMargin);
|
||||
m_textField.setFrame(inputViewFrame);
|
||||
m_editableExpressionView.setFrame(KDRectZero);
|
||||
return;
|
||||
}
|
||||
KDRect inputViewFrame(k_leftMargin, bounds().height() - inputViewFrameHeight, bounds().width() - k_leftMargin, inputViewFrameHeight);
|
||||
m_editableExpressionView.setFrame(inputViewFrame);
|
||||
m_textField.setFrame(KDRectZero);
|
||||
}
|
||||
|
||||
void EditExpressionController::ContentView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
void EditExpressionController::ContentView::reload() {
|
||||
layoutSubviews();
|
||||
markRectAsDirty(bounds());
|
||||
}
|
||||
|
||||
void EditExpressionController::ContentView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
KDCoordinate inputViewFrameHeight = inputViewHeight();
|
||||
// Draw the separator
|
||||
ctx->fillRect(KDRect(0, bounds().height() -k_textFieldHeight-k_separatorThickness, bounds().width(), k_separatorThickness), Palette::GreyMiddle);
|
||||
// Color the margin
|
||||
ctx->fillRect(KDRect(0, bounds().height() -k_textFieldHeight, k_textMargin, k_textFieldHeight), m_textField.backgroundColor());
|
||||
ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight-k_separatorThickness, bounds().width(), k_separatorThickness), Palette::GreyMiddle);
|
||||
// Color the left margin
|
||||
ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight, k_leftMargin, k_textFieldHeight), m_textField.backgroundColor());
|
||||
if (!editionIsInTextField()) {
|
||||
// Color the upper margin
|
||||
ctx->fillRect(KDRect(0, bounds().height() -inputViewFrameHeight, bounds().width(), k_verticalMargin), m_textField.backgroundColor());
|
||||
}
|
||||
}
|
||||
|
||||
TextField * EditExpressionController::ContentView::textField() {
|
||||
return &m_textField;
|
||||
KDCoordinate EditExpressionController::ContentView::inputViewHeight() const {
|
||||
return k_verticalMargin + (editionIsInTextField() ? k_textFieldHeight : editableExpressionViewHeight());
|
||||
}
|
||||
|
||||
TableView * EditExpressionController::ContentView::mainView() {
|
||||
return m_mainView;
|
||||
KDCoordinate EditExpressionController::ContentView::editableExpressionViewHeight() const {
|
||||
return KDCoordinate(min(0.6*Ion::Display::Height, max(k_textFieldHeight, m_editableExpressionView.minimalSizeForOptimalDisplay().height()+k_verticalMargin)));
|
||||
}
|
||||
|
||||
EditExpressionController::EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore) :
|
||||
@@ -67,7 +94,11 @@ void EditExpressionController::insertTextBody(const char * text) {
|
||||
bool EditExpressionController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Up) {
|
||||
if (m_calculationStore->numberOfCalculations() > 0) {
|
||||
((ContentView *)view())->textField()->setEditing(false, false);
|
||||
if (((ContentView *)view())->editionIsInTextField()) {
|
||||
((ContentView *)view())->textField()->setEditing(false, false);
|
||||
} else {
|
||||
((ContentView *)view())->editableExpressionView()->setEditing(false);
|
||||
}
|
||||
app()->setFirstResponder(m_historyController);
|
||||
}
|
||||
return true;
|
||||
@@ -78,8 +109,13 @@ bool EditExpressionController::handleEvent(Ion::Events::Event event) {
|
||||
void EditExpressionController::didBecomeFirstResponder() {
|
||||
int lastRow = m_calculationStore->numberOfCalculations() > 0 ? m_calculationStore->numberOfCalculations()-1 : 0;
|
||||
m_historyController->scrollToCell(0, lastRow);
|
||||
((ContentView *)view())->textField()->setEditing(true, false);
|
||||
app()->setFirstResponder(((ContentView *)view())->textField());
|
||||
if (((ContentView *)view())->editionIsInTextField()) {
|
||||
((ContentView *)view())->textField()->setEditing(true, false);
|
||||
app()->setFirstResponder(((ContentView *)view())->textField());
|
||||
return;
|
||||
}
|
||||
((ContentView *)view())->editableExpressionView()->setEditing(true);
|
||||
app()->setFirstResponder(((ContentView *)view())->editableExpressionView());
|
||||
}
|
||||
|
||||
bool EditExpressionController::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) {
|
||||
@@ -110,21 +146,71 @@ bool EditExpressionController::textFieldDidAbortEditing(::TextField * textField,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EditExpressionController::editableExpressionViewDidReceiveEvent(::EditableExpressionView * editableExpressionView, Ion::Events::Event event) {
|
||||
bool layoutIsEmpty = expressionLayout()->isHorizontal() && expressionLayout()->numberOfChildren() == 0;
|
||||
if (editableExpressionView->isEditing() && editableExpressionView->editableExpressionViewShouldFinishEditing(event) && layoutIsEmpty && m_calculationStore->numberOfCalculations() > 0) {
|
||||
App * calculationApp = (App *)app();
|
||||
const char * lastTextBody = m_calculationStore->calculationAtIndex(m_calculationStore->numberOfCalculations()-1)->inputText();
|
||||
m_calculationStore->push(lastTextBody, calculationApp->localContext());
|
||||
m_historyController->reload();
|
||||
((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1);
|
||||
return true;
|
||||
}
|
||||
return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidReceiveEvent(editableExpressionView, event);
|
||||
}
|
||||
|
||||
bool EditExpressionController::editableExpressionViewDidFinishEditing(::EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) {
|
||||
App * calculationApp = (App *)app();
|
||||
expressionLayout()->writeTextInBuffer(const_cast<char *>(textBody()), ContentView::k_bufferLength);
|
||||
m_calculationStore->push(textBody(), calculationApp->localContext());
|
||||
(const_cast<ExpressionView *>(((ContentView *)view())->editableExpressionView()->expressionViewWithCursor()->expressionView()))->setExpressionLayout(new Poincare::HorizontalLayout());
|
||||
reloadView();
|
||||
((ContentView *)view())->editableExpressionView()->setEditing(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditExpressionController::editableExpressionViewDidAbortEditing(::EditableExpressionView * editableExpressionView, const char * text) {
|
||||
((ContentView *)view())->editableExpressionView()->setEditing(true);
|
||||
//TODO ((ContentView *)view())->editableExpressionView()->editableExpressionView()->expressionViewWithCursor()->expressionView()->setLayout(;
|
||||
return false;
|
||||
}
|
||||
|
||||
void EditExpressionController::editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) {
|
||||
assert(editableExpressionView == ((ContentView *)view())->editableExpressionView());
|
||||
reloadView();
|
||||
}
|
||||
|
||||
TextFieldDelegateApp * EditExpressionController::textFieldDelegateApp() {
|
||||
return (App *)app();
|
||||
}
|
||||
|
||||
TextFieldAndEditableExpressionViewDelegateApp * EditExpressionController::textFieldAndEditableExpressionViewDelegateApp() {
|
||||
return (App *)app();
|
||||
}
|
||||
|
||||
View * EditExpressionController::loadView() {
|
||||
return new ContentView(this, (TableView *)m_historyController->view(), this);
|
||||
return new ContentView(this, (TableView *)m_historyController->view(), this, this);
|
||||
}
|
||||
|
||||
void EditExpressionController::unloadView(View * view) {
|
||||
delete view;
|
||||
}
|
||||
|
||||
void EditExpressionController::reloadView() {
|
||||
((ContentView *)view())->reload();
|
||||
m_historyController->reload();
|
||||
if (m_historyController->numberOfRows() > 0) {
|
||||
((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1);
|
||||
}
|
||||
}
|
||||
|
||||
void EditExpressionController::viewDidDisappear() {
|
||||
DynamicViewController::viewDidDisappear();
|
||||
m_historyController->viewDidDisappear();
|
||||
}
|
||||
|
||||
Poincare::ExpressionLayout * EditExpressionController::expressionLayout() {
|
||||
return ((ContentView *)view())->editableExpressionView()->expressionViewWithCursor()->expressionView()->expressionLayout();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <escher.h>
|
||||
#include "../shared/text_field_delegate.h"
|
||||
#include "../shared/editable_expression_view_delegate.h"
|
||||
#include "history_controller.h"
|
||||
#include "calculation_store.h"
|
||||
#include "text_field.h"
|
||||
@@ -11,7 +12,7 @@ namespace Calculation {
|
||||
class HistoryController;
|
||||
|
||||
/* TODO: implement a split view */
|
||||
class EditExpressionController : public DynamicViewController, public Shared::TextFieldDelegate {
|
||||
class EditExpressionController : public DynamicViewController, public Shared::TextFieldDelegate, public Shared::EditableExpressionViewDelegate {
|
||||
public:
|
||||
EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore);
|
||||
void didBecomeFirstResponder() override;
|
||||
@@ -19,30 +20,50 @@ public:
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
const char * textBody();
|
||||
void insertTextBody(const char * text);
|
||||
bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override;
|
||||
|
||||
/* TextFieldDelegate */
|
||||
bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidFinishEditing(::TextField * textField, const char * text, Ion::Events::Event event) override;
|
||||
bool textFieldDidAbortEditing(::TextField * textField, const char * text) override;
|
||||
|
||||
/* EditableExpressionViewDelegate */
|
||||
bool editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override;
|
||||
bool editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) override;
|
||||
bool editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) override;
|
||||
void editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) override;
|
||||
|
||||
private:
|
||||
class ContentView : public View {
|
||||
public:
|
||||
ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate);
|
||||
ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, EditableExpressionViewDelegate * editableExpressionViewDelegate);
|
||||
int numberOfSubviews() const override;
|
||||
View * subviewAtIndex(int index) override;
|
||||
void layoutSubviews() override;
|
||||
TextField * textField();
|
||||
TableView * mainView();
|
||||
void reload();
|
||||
TextField * textField() { return &m_textField; }
|
||||
EditableExpressionView * editableExpressionView() { return &m_editableExpressionView; }
|
||||
TableView * mainView() { return m_mainView; }
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
bool editionIsInTextField() const { return true; } //TODO
|
||||
static constexpr int k_bufferLength = TextField::maxBufferSize();
|
||||
private:
|
||||
static constexpr KDCoordinate k_textFieldHeight = 37;
|
||||
static constexpr KDCoordinate k_textMargin= 5;
|
||||
static constexpr KDCoordinate k_textFieldHeight = 32; //37
|
||||
static constexpr KDCoordinate k_leftMargin = 5;
|
||||
static constexpr KDCoordinate k_verticalMargin = 9;
|
||||
constexpr static int k_separatorThickness = 1;
|
||||
KDCoordinate inputViewHeight() const;
|
||||
KDCoordinate editableExpressionViewHeight() const;
|
||||
TableView * m_mainView;
|
||||
TextField m_textField;
|
||||
char m_textBody[TextField::maxBufferSize()];
|
||||
EditableExpressionView m_editableExpressionView;
|
||||
char m_textBody[k_bufferLength];
|
||||
};
|
||||
View * loadView() override;
|
||||
void unloadView(View * view) override;
|
||||
void reloadView();
|
||||
Shared::TextFieldDelegateApp * textFieldDelegateApp() override;
|
||||
Shared::TextFieldAndEditableExpressionViewDelegateApp * textFieldAndEditableExpressionViewDelegateApp() override;
|
||||
Poincare::ExpressionLayout * expressionLayout();
|
||||
HistoryController * m_historyController;
|
||||
CalculationStore * m_calculationStore;
|
||||
};
|
||||
|
||||
@@ -12,6 +12,22 @@ bool EditableExpressionViewDelegate::editableExpressionViewDidReceiveEvent(::Edi
|
||||
return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidReceiveEvent(editableExpressionView, event);
|
||||
}
|
||||
|
||||
bool EditableExpressionViewDelegate::editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) {
|
||||
return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidFinishEditing(editableExpressionView, text, event);
|
||||
}
|
||||
|
||||
bool EditableExpressionViewDelegate::editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) {
|
||||
return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidAbortEditing(editableExpressionView, text);
|
||||
}
|
||||
|
||||
bool EditableExpressionViewDelegate::editableExpressionViewDidHandleEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event, bool returnValue, bool expressionHasChanged) {
|
||||
return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidHandleEvent(editableExpressionView, event, returnValue, expressionHasChanged);
|
||||
}
|
||||
|
||||
void EditableExpressionViewDelegate::editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) {
|
||||
return textFieldAndEditableExpressionViewDelegateApp()->editableExpressionViewDidChangeSize(editableExpressionView);
|
||||
}
|
||||
|
||||
Toolbox * EditableExpressionViewDelegate::toolboxForEditableExpressionView(::EditableExpressionView * editableExpressionView) {
|
||||
return textFieldAndEditableExpressionViewDelegateApp()->toolboxForEditableExpressionView(editableExpressionView);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@ class EditableExpressionViewDelegate : public ::EditableExpressionViewDelegate {
|
||||
public:
|
||||
bool editableExpressionViewShouldFinishEditing(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override;
|
||||
bool editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) override;
|
||||
bool editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) override;
|
||||
bool editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) override;
|
||||
bool editableExpressionViewDidHandleEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event, bool returnValue, bool expressionHasChanged) override;
|
||||
void editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) override;
|
||||
Toolbox * toolboxForEditableExpressionView(EditableExpressionView * editableExpressionView) override;
|
||||
private:
|
||||
virtual TextFieldAndEditableExpressionViewDelegateApp * textFieldAndEditableExpressionViewDelegateApp() = 0;
|
||||
|
||||
@@ -14,6 +14,7 @@ public:
|
||||
bool isEditing() const;
|
||||
void setEditing(bool isEditing);
|
||||
void scrollToCursor();
|
||||
void reload();
|
||||
|
||||
/* Responder */
|
||||
Toolbox * toolbox() override;
|
||||
@@ -29,7 +30,6 @@ public:
|
||||
|
||||
private:
|
||||
bool privateHandleEvent(Ion::Events::Event event);
|
||||
void cursorOrLayoutChanged();
|
||||
ExpressionViewWithCursor m_expressionViewWithCursor;
|
||||
EditableExpressionViewDelegate * m_delegate;
|
||||
};
|
||||
|
||||
@@ -10,9 +10,10 @@ class EditableExpressionViewDelegate {
|
||||
public:
|
||||
virtual bool editableExpressionViewShouldFinishEditing(EditableExpressionView * editableExpressionView, Ion::Events::Event event) = 0;
|
||||
virtual bool editableExpressionViewDidReceiveEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event) = 0;
|
||||
/*virtual bool editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) { return false; };
|
||||
virtual bool editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) {return false;};
|
||||
virtual bool editableExpressionViewDidHandleEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event, bool returnValue, bool textHasChanged) { return returnValue; };*/ // TODO?
|
||||
virtual bool editableExpressionViewDidFinishEditing(EditableExpressionView * editableExpressionView, const char * text, Ion::Events::Event event) { return false; }
|
||||
virtual bool editableExpressionViewDidAbortEditing(EditableExpressionView * editableExpressionView, const char * text) { return false; }
|
||||
virtual bool editableExpressionViewDidHandleEvent(EditableExpressionView * editableExpressionView, Ion::Events::Event event, bool returnValue, bool expressionHasChanged) { return returnValue; }
|
||||
virtual void editableExpressionViewDidChangeSize(EditableExpressionView * editableExpressionView) {}
|
||||
virtual Toolbox * toolboxForEditableExpressionView(EditableExpressionView * editableExpressionView) = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
void setAlignment(float horizontalAlignment, float verticalAlignment);
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
KDPoint drawingOrigin() const;
|
||||
KDPoint absoluteDrawingOrigin() const;
|
||||
private:
|
||||
/* Warning: we do not need to delete the previous expression layout when
|
||||
* deleting object or setting a new expression layout. Indeed, the expression
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
class ExpressionViewWithCursor : public View {
|
||||
public:
|
||||
ExpressionViewWithCursor(Poincare::ExpressionLayout * expressionLayout);
|
||||
Poincare::ExpressionLayoutCursor * cursor() { return &m_cursor; }
|
||||
bool isEditing() const { return m_isEditing; }
|
||||
void setEditing(bool isEditing) { m_isEditing = isEditing; }
|
||||
void cursorPositionChanged();
|
||||
KDRect cursorRect();
|
||||
const ExpressionView * expressionView() const { return &m_expressionView; }
|
||||
Poincare::ExpressionLayoutCursor * cursor() { return &m_cursor; }
|
||||
ExpressionView * expressionView() { return &m_expressionView; }
|
||||
/* View */
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
private:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <escher/editable_expression_view.h>
|
||||
#include <escher/text_field.h>
|
||||
#include <assert.h>
|
||||
|
||||
EditableExpressionView::EditableExpressionView(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, EditableExpressionViewDelegate * delegate) :
|
||||
@@ -28,8 +29,13 @@ Toolbox * EditableExpressionView::toolbox() {
|
||||
}
|
||||
|
||||
bool EditableExpressionView::handleEvent(Ion::Events::Event event) {
|
||||
KDSize previousSize = minimalSizeForOptimalDisplay();
|
||||
if (privateHandleEvent(event)) {
|
||||
cursorOrLayoutChanged();
|
||||
reload();
|
||||
KDSize newSize = minimalSizeForOptimalDisplay();
|
||||
if (m_delegate && previousSize.height() != newSize.height()) {
|
||||
m_delegate->editableExpressionViewDidChangeSize(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -44,6 +50,30 @@ KDSize EditableExpressionView::minimalSizeForOptimalDisplay() const {
|
||||
}
|
||||
|
||||
bool EditableExpressionView::privateHandleEvent(Ion::Events::Event event) {
|
||||
if (m_delegate && m_delegate->editableExpressionViewDidReceiveEvent(this, event)) {
|
||||
return true;
|
||||
}
|
||||
if (Responder::handleEvent(event)) {
|
||||
/* The only event Responder handles is 'Toolbox' displaying. In that case,
|
||||
* the EditableExpressionView is forced into editing mode. */
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (isEditing() && editableExpressionViewShouldFinishEditing(event)) {
|
||||
setEditing(false);
|
||||
int bufferSize = TextField::maxBufferSize();
|
||||
char buffer[bufferSize];
|
||||
m_expressionViewWithCursor.expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize);
|
||||
if (m_delegate->editableExpressionViewDidFinishEditing(this, buffer, event)) {
|
||||
delete m_expressionViewWithCursor.expressionView()->expressionLayout();
|
||||
Poincare::ExpressionLayout * newLayout = new Poincare::HorizontalLayout();
|
||||
m_expressionViewWithCursor.expressionView()->setExpressionLayout(newLayout);
|
||||
m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(newLayout);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Left) {
|
||||
return m_expressionViewWithCursor.cursor()->moveLeft();
|
||||
}
|
||||
@@ -121,14 +151,22 @@ void EditableExpressionView::insertLayoutAtCursor(Poincare::ExpressionLayout * l
|
||||
if (layout == nullptr) {
|
||||
return;
|
||||
}
|
||||
KDSize previousSize = minimalSizeForOptimalDisplay();
|
||||
m_expressionViewWithCursor.cursor()->addLayout(layout);
|
||||
m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(pointedLayout);
|
||||
m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right);
|
||||
m_expressionViewWithCursor.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines();
|
||||
cursorOrLayoutChanged();
|
||||
KDSize newSize = minimalSizeForOptimalDisplay();
|
||||
reload();
|
||||
if (m_delegate && previousSize.height() != newSize.height()) {
|
||||
m_delegate->editableExpressionViewDidChangeSize(this);
|
||||
}
|
||||
}
|
||||
|
||||
void EditableExpressionView::cursorOrLayoutChanged() {
|
||||
void EditableExpressionView::reload() {
|
||||
m_expressionViewWithCursor.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines();
|
||||
m_expressionViewWithCursor.cursorPositionChanged();
|
||||
layoutSubviews();
|
||||
scrollToCursor();
|
||||
markRectAsDirty(bounds());
|
||||
}
|
||||
|
||||
@@ -49,8 +49,11 @@ KDSize ExpressionView::minimalSizeForOptimalDisplay() const {
|
||||
|
||||
KDPoint ExpressionView::drawingOrigin() const {
|
||||
KDSize expressionSize = m_expressionLayout->size();
|
||||
return KDPoint(m_horizontalAlignment*(m_frame.width() - expressionSize.width()),
|
||||
0.5f*(m_frame.height() - expressionSize.height()));
|
||||
return KDPoint(m_horizontalAlignment*(m_frame.width() - expressionSize.width()), 0.5f*(m_frame.height() - expressionSize.height()));
|
||||
}
|
||||
|
||||
KDPoint ExpressionView::absoluteDrawingOrigin() const {
|
||||
return drawingOrigin().translatedBy(m_frame.topLeft());
|
||||
}
|
||||
|
||||
void ExpressionView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
|
||||
@@ -25,7 +25,10 @@ KDRect ExpressionViewWithCursor::cursorRect() {
|
||||
|
||||
KDSize ExpressionViewWithCursor::minimalSizeForOptimalDisplay() const {
|
||||
KDSize expressionViewSize = m_expressionView.minimalSizeForOptimalDisplay();
|
||||
return KDSize(expressionViewSize.width()+1, m_expressionView.minimalSizeForOptimalDisplay().height()); // +1 for the cursor
|
||||
KDSize cursorSize = isEditing() ? m_cursorView.minimalSizeForOptimalDisplay() : KDSizeZero;
|
||||
KDCoordinate resultWidth = expressionViewSize.width() + cursorSize.width();
|
||||
KDCoordinate resultHeight = expressionViewSize.height() + cursorSize.height()/2;
|
||||
return KDSize(resultWidth, resultHeight);
|
||||
}
|
||||
|
||||
View * ExpressionViewWithCursor::subviewAtIndex(int index) {
|
||||
@@ -40,7 +43,7 @@ void ExpressionViewWithCursor::layoutSubviews() {
|
||||
}
|
||||
|
||||
void ExpressionViewWithCursor::layoutCursorSubview() {
|
||||
KDPoint expressionViewOrigin = m_expressionView.drawingOrigin();
|
||||
KDPoint expressionViewOrigin = m_expressionView.absoluteDrawingOrigin();
|
||||
KDPoint cursoredExpressionViewOrigin = m_cursor.pointedExpressionLayout()->absoluteOrigin();
|
||||
KDCoordinate cursorX = expressionViewOrigin.x() + cursoredExpressionViewOrigin.x();
|
||||
if (m_cursor.position() == ExpressionLayoutCursor::Position::Right) {
|
||||
|
||||
Reference in New Issue
Block a user