mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
Merge branch 'saisie-jolie' into master-merge-saisie-jolie
This commit is contained in:
@@ -6,13 +6,13 @@ app_objs += $(addprefix apps/calculation/,\
|
||||
calculation.o\
|
||||
calculation_store.o\
|
||||
edit_expression_controller.o\
|
||||
expression_field.o\
|
||||
history_view_cell.o\
|
||||
history_controller.o\
|
||||
output_expressions_view.o\
|
||||
scrollable_expression_view.o\
|
||||
scrollable_output_expressions_view.o\
|
||||
selectable_table_view.o\
|
||||
text_field.o\
|
||||
)
|
||||
|
||||
i18n_files += $(addprefix apps/calculation/,\
|
||||
|
||||
@@ -43,7 +43,7 @@ void App::Snapshot::tidy() {
|
||||
}
|
||||
|
||||
App::App(Container * container, Snapshot * snapshot) :
|
||||
TextFieldDelegateApp(container, snapshot, &m_editExpressionController),
|
||||
ExpressionFieldDelegateApp(container, snapshot, &m_editExpressionController),
|
||||
m_historyController(&m_editExpressionController, snapshot->calculationStore()),
|
||||
m_editExpressionController(&m_modalViewController, &m_historyController, snapshot->calculationStore())
|
||||
{
|
||||
@@ -65,6 +65,27 @@ bool App::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event e
|
||||
return false;
|
||||
}
|
||||
|
||||
bool App::expressionLayoutFieldDidReceiveEvent(::ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) {
|
||||
if ((event == Ion::Events::Var || event == Ion::Events::XNT) && ExpressionFieldDelegateApp::expressionLayoutFieldDidReceiveEvent(expressionLayoutField, event)) {
|
||||
return true;
|
||||
}
|
||||
if (expressionLayoutField->isEditing() && expressionLayoutField->expressionLayoutFieldShouldFinishEditing(event)) {
|
||||
if (!expressionLayoutField->hasText()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int bufferLength = TextField::maxBufferSize();
|
||||
char bufferForParsing[bufferLength];
|
||||
expressionLayoutField->writeTextInBuffer(bufferForParsing, bufferLength);
|
||||
|
||||
if (!textInputIsCorrect(bufferForParsing)) {
|
||||
displayWarning(I18n::Message::SyntaxError);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool App::textInputIsCorrect(const char * text) {
|
||||
/* Here, we check that the expression entered by the user can be printed with
|
||||
* less than k_printedExpressionLength characters. Otherwise, we prevent the
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
class App : public Shared::TextFieldDelegateApp {
|
||||
class App : public Shared::ExpressionFieldDelegateApp {
|
||||
public:
|
||||
class Descriptor : public ::App::Descriptor {
|
||||
public:
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
};
|
||||
bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override;
|
||||
bool textInputIsCorrect(const char * text);
|
||||
bool expressionLayoutFieldDidReceiveEvent(::ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
|
||||
const char * XNT() override;
|
||||
private:
|
||||
App(Container * container, Snapshot * snapshot);
|
||||
|
||||
@@ -1,74 +1,71 @@
|
||||
#include "edit_expression_controller.h"
|
||||
#include "../apps_container.h"
|
||||
#include "app.h"
|
||||
#include "../apps_container.h"
|
||||
#include <ion/display.h>
|
||||
#include <poincare/preferences.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Shared;
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate) :
|
||||
EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, ExpressionLayoutFieldDelegate * expressionLayoutFieldDelegate) :
|
||||
View(),
|
||||
m_mainView(subview),
|
||||
m_textField(parentResponder, m_textBody, TextField::maxBufferSize(), textFieldDelegate)
|
||||
m_layout(new Poincare::HorizontalLayout()),
|
||||
m_expressionField(parentResponder, m_textBody, k_bufferLength, m_layout, textFieldDelegate, expressionLayoutFieldDelegate)
|
||||
{
|
||||
m_textBody[0] = 0;
|
||||
}
|
||||
|
||||
int EditExpressionController::ContentView::numberOfSubviews() const {
|
||||
return 2;
|
||||
EditExpressionController::ContentView::~ContentView() {
|
||||
delete m_layout;
|
||||
}
|
||||
|
||||
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);
|
||||
return &m_expressionField;
|
||||
}
|
||||
|
||||
void EditExpressionController::ContentView::layoutSubviews() {
|
||||
KDRect mainViewFrame(0, 0, bounds().width(), bounds().height() - k_textFieldHeight-k_separatorThickness);
|
||||
KDCoordinate inputViewFrameHeight = m_expressionField.minimalSizeForOptimalDisplay().height();
|
||||
KDRect mainViewFrame(0, 0, bounds().width(), bounds().height() - inputViewFrameHeight);
|
||||
m_mainView->setFrame(mainViewFrame);
|
||||
KDRect inputViewFrame(k_textMargin, bounds().height() - k_textFieldHeight, bounds().width()-k_textMargin, k_textFieldHeight);
|
||||
m_textField.setFrame(inputViewFrame);
|
||||
KDRect inputViewFrame(0, bounds().height() - inputViewFrameHeight, bounds().width(), inputViewFrameHeight);
|
||||
m_expressionField.setFrame(inputViewFrame);
|
||||
}
|
||||
|
||||
void EditExpressionController::ContentView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
// 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());
|
||||
}
|
||||
|
||||
TextField * EditExpressionController::ContentView::textField() {
|
||||
return &m_textField;
|
||||
}
|
||||
|
||||
TableView * EditExpressionController::ContentView::mainView() {
|
||||
return m_mainView;
|
||||
void EditExpressionController::ContentView::reload() {
|
||||
layoutSubviews();
|
||||
markRectAsDirty(bounds());
|
||||
}
|
||||
|
||||
EditExpressionController::EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore) :
|
||||
DynamicViewController(parentResponder),
|
||||
m_historyController(historyController),
|
||||
m_calculationStore(calculationStore)
|
||||
m_calculationStore(calculationStore),
|
||||
m_inputViewHeightIsMaximal(false)
|
||||
{
|
||||
m_cacheBuffer[0] = 0;
|
||||
}
|
||||
|
||||
const char * EditExpressionController::textBody() {
|
||||
return ((ContentView *)view())->textField()->text();
|
||||
return ((ContentView *)view())->expressionField()->text();
|
||||
}
|
||||
|
||||
void EditExpressionController::insertTextBody(const char * text) {
|
||||
TextField * tf = ((ContentView *)view())->textField();
|
||||
tf->setEditing(true, false);
|
||||
tf->handleEventWithText(text);
|
||||
((ContentView *)view())->expressionField()->insertText(text);
|
||||
}
|
||||
|
||||
bool EditExpressionController::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Up) {
|
||||
if (m_calculationStore->numberOfCalculations() > 0) {
|
||||
m_cacheBuffer[0] = 0;
|
||||
((ContentView *)view())->textField()->setEditing(false, false);
|
||||
((ContentView *)view())->expressionField()->setEditing(false, false);
|
||||
app()->setFirstResponder(m_historyController);
|
||||
}
|
||||
return true;
|
||||
@@ -79,55 +76,108 @@ 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());
|
||||
((ContentView *)view())->expressionField()->setEditing(true, false);
|
||||
app()->setFirstResponder(((ContentView *)view())->expressionField());
|
||||
}
|
||||
|
||||
bool EditExpressionController::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) {
|
||||
if (textField->isEditing() && textField->textFieldShouldFinishEditing(event) && textField->draftTextLength() == 0 && m_cacheBuffer[0] != 0) {
|
||||
App * calculationApp = (App *)app();
|
||||
/* The input text store in m_cacheBuffer might have beed correct the first
|
||||
* time but then be too long when replacing ans in another context */
|
||||
if (!calculationApp->textInputIsCorrect(m_cacheBuffer)) {
|
||||
return true;
|
||||
}
|
||||
m_calculationStore->push(m_cacheBuffer, calculationApp->localContext());
|
||||
m_historyController->reload();
|
||||
((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1);
|
||||
return true;
|
||||
return inputViewDidReceiveEvent(event);
|
||||
}
|
||||
return textFieldDelegateApp()->textFieldDidReceiveEvent(textField, event);
|
||||
}
|
||||
|
||||
bool EditExpressionController::textFieldDidFinishEditing(::TextField * textField, const char * text, Ion::Events::Event event) {
|
||||
App * calculationApp = (App *)app();
|
||||
strlcpy(m_cacheBuffer, textBody(), TextField::maxBufferSize());
|
||||
m_calculationStore->push(textBody(), calculationApp->localContext());
|
||||
m_historyController->reload();
|
||||
((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1);
|
||||
((ContentView *)view())->textField()->setEditing(true);
|
||||
((ContentView *)view())->textField()->setText("");
|
||||
return true;
|
||||
return inputViewDidFinishEditing(text, event);
|
||||
}
|
||||
|
||||
bool EditExpressionController::textFieldDidAbortEditing(::TextField * textField, const char * text) {
|
||||
((ContentView *)view())->textField()->setEditing(true);
|
||||
((ContentView *)view())->textField()->setText(text);
|
||||
return false;
|
||||
bool EditExpressionController::textFieldDidAbortEditing(::TextField * textField) {
|
||||
return inputViewDidAbortEditing(textField->text());
|
||||
}
|
||||
|
||||
bool EditExpressionController::expressionLayoutFieldDidReceiveEvent(::ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) {
|
||||
if (expressionLayoutField->isEditing() && expressionLayoutField->expressionLayoutFieldShouldFinishEditing(event) && !expressionLayoutField->hasText() && m_calculationStore->numberOfCalculations() > 0) {
|
||||
return inputViewDidReceiveEvent(event);
|
||||
}
|
||||
return expressionFieldDelegateApp()->expressionLayoutFieldDidReceiveEvent(expressionLayoutField, event);
|
||||
}
|
||||
|
||||
bool EditExpressionController::expressionLayoutFieldDidFinishEditing(::ExpressionLayoutField * expressionLayoutField, const char * text, Ion::Events::Event event) {
|
||||
return inputViewDidFinishEditing(text, event);
|
||||
}
|
||||
|
||||
bool EditExpressionController::expressionLayoutFieldDidAbortEditing(::ExpressionLayoutField * expressionLayoutField) {
|
||||
return inputViewDidAbortEditing(nullptr);
|
||||
}
|
||||
|
||||
void EditExpressionController::expressionLayoutFieldDidChangeSize(::ExpressionLayoutField * expressionLayoutField) {
|
||||
/* Reload the view only if the ExpressionField height actually changes, i.e.
|
||||
* not if the height is already maximal and stays maximal. */
|
||||
if (view()) {
|
||||
bool newInputViewHeightIsMaximal = static_cast<ContentView *>(view())->expressionField()->heightIsMaximal();
|
||||
if (!m_inputViewHeightIsMaximal || !newInputViewHeightIsMaximal) {
|
||||
m_inputViewHeightIsMaximal = newInputViewHeightIsMaximal;
|
||||
reloadView();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldDelegateApp * EditExpressionController::textFieldDelegateApp() {
|
||||
return (App *)app();
|
||||
}
|
||||
|
||||
ExpressionFieldDelegateApp * EditExpressionController::expressionFieldDelegateApp() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
bool EditExpressionController::inputViewDidReceiveEvent(Ion::Events::Event event) {
|
||||
App * calculationApp = (App *)app();
|
||||
/* The input text store in m_cacheBuffer might have beed correct the first
|
||||
* time but then be too long when replacing ans in another context */
|
||||
if (!calculationApp->textInputIsCorrect(m_cacheBuffer)) {
|
||||
return true;
|
||||
}
|
||||
m_calculationStore->push(m_cacheBuffer, calculationApp->localContext());
|
||||
m_historyController->reload();
|
||||
((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditExpressionController::inputViewDidFinishEditing(const char * text, Ion::Events::Event event) {
|
||||
App * calculationApp = (App *)app();
|
||||
strlcpy(m_cacheBuffer, textBody(), TextField::maxBufferSize());
|
||||
m_calculationStore->push(textBody(), calculationApp->localContext());
|
||||
m_historyController->reload();
|
||||
((ContentView *)view())->mainView()->scrollToCell(0, m_historyController->numberOfRows()-1);
|
||||
((ContentView *)view())->expressionField()->setEditing(true);
|
||||
((ContentView *)view())->expressionField()->setText("");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditExpressionController::inputViewDidAbortEditing(const char * text) {
|
||||
if (text != nullptr) {
|
||||
((ContentView *)view())->expressionField()->setEditing(true, true);
|
||||
((ContentView *)view())->expressionField()->setText(text);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EditExpressionController::viewDidDisappear() {
|
||||
DynamicViewController::viewDidDisappear();
|
||||
m_historyController->viewDidDisappear();
|
||||
|
||||
@@ -2,16 +2,18 @@
|
||||
#define CALCULATION_EDIT_EXPRESSION_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include <poincare/expression_layout.h>
|
||||
#include "expression_field.h"
|
||||
#include "../shared/text_field_delegate.h"
|
||||
#include "../shared/expression_layout_field_delegate.h"
|
||||
#include "history_controller.h"
|
||||
#include "calculation_store.h"
|
||||
#include "text_field.h"
|
||||
|
||||
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::ExpressionLayoutFieldDelegate {
|
||||
public:
|
||||
EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore);
|
||||
void didBecomeFirstResponder() override;
|
||||
@@ -19,33 +21,53 @@ 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;
|
||||
bool textFieldDidAbortEditing(::TextField * textField) override;
|
||||
|
||||
/* ExpressionLayoutFieldDelegate */
|
||||
bool expressionLayoutFieldDidReceiveEvent(::ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
|
||||
bool expressionLayoutFieldDidFinishEditing(::ExpressionLayoutField * expressionLayoutField, const char * text, Ion::Events::Event event) override;
|
||||
bool expressionLayoutFieldDidAbortEditing(::ExpressionLayoutField * expressionLayoutField) override;
|
||||
void expressionLayoutFieldDidChangeSize(::ExpressionLayoutField * expressionLayoutField) override;
|
||||
|
||||
private:
|
||||
class ContentView : public View {
|
||||
public:
|
||||
ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate);
|
||||
int numberOfSubviews() const override;
|
||||
ContentView(Responder * parentResponder, TableView * subview, TextFieldDelegate * textFieldDelegate, ExpressionLayoutFieldDelegate * expressionLayoutFieldDelegate);
|
||||
~ContentView();
|
||||
ContentView(const ContentView& other) = delete;
|
||||
ContentView(ContentView&& other) = delete;
|
||||
ContentView& operator=(const ContentView& other) = delete;
|
||||
ContentView& operator=(ContentView&& other) = delete;
|
||||
void reload();
|
||||
TableView * mainView() { return m_mainView; }
|
||||
ExpressionField * expressionField() { return &m_expressionField; }
|
||||
/* View */
|
||||
int numberOfSubviews() const override { return 2; }
|
||||
View * subviewAtIndex(int index) override;
|
||||
void layoutSubviews() override;
|
||||
TextField * textField();
|
||||
TableView * mainView();
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
private:
|
||||
static constexpr KDCoordinate k_textFieldHeight = 37;
|
||||
static constexpr KDCoordinate k_textMargin= 5;
|
||||
constexpr static int k_separatorThickness = 1;
|
||||
static constexpr int k_bufferLength = TextField::maxBufferSize();
|
||||
TableView * m_mainView;
|
||||
TextField m_textField;
|
||||
char m_textBody[TextField::maxBufferSize()];
|
||||
char m_textBody[k_bufferLength];
|
||||
Poincare::ExpressionLayout * m_layout;
|
||||
ExpressionField m_expressionField;
|
||||
};
|
||||
View * loadView() override;
|
||||
void unloadView(View * view) override;
|
||||
void reloadView();
|
||||
bool inputViewDidReceiveEvent(Ion::Events::Event event);
|
||||
bool inputViewDidFinishEditing(const char * text, Ion::Events::Event event);
|
||||
bool inputViewDidAbortEditing(const char * text);
|
||||
Shared::TextFieldDelegateApp * textFieldDelegateApp() override;
|
||||
Shared::ExpressionFieldDelegateApp * expressionFieldDelegateApp() override;
|
||||
char m_cacheBuffer[TextField::maxBufferSize()];
|
||||
HistoryController * m_historyController;
|
||||
CalculationStore * m_calculationStore;
|
||||
bool m_inputViewHeightIsMaximal;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
25
apps/calculation/expression_field.cpp
Normal file
25
apps/calculation/expression_field.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include "expression_field.h"
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
bool ExpressionField::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Back) {
|
||||
return false;
|
||||
}
|
||||
if (event == Ion::Events::Ans) {
|
||||
insertText("ans");
|
||||
return true;
|
||||
}
|
||||
if (isEditing() && isEmpty() &&
|
||||
(event == Ion::Events::Multiplication ||
|
||||
event == Ion::Events::Plus ||
|
||||
event == Ion::Events::Power ||
|
||||
event == Ion::Events::Square ||
|
||||
event == Ion::Events::Division ||
|
||||
event == Ion::Events::Sto)) {
|
||||
insertText("ans");
|
||||
}
|
||||
return(::ExpressionField::handleEvent(event));
|
||||
}
|
||||
|
||||
}
|
||||
17
apps/calculation/expression_field.h
Normal file
17
apps/calculation/expression_field.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef CALCULATION_EXPRESSION_FIELD_H
|
||||
#define CALCULATION_EXPRESSION_FIELD_H
|
||||
|
||||
#include <escher.h>
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
class ExpressionField : public ::ExpressionField {
|
||||
public:
|
||||
using ::ExpressionField::ExpressionField;
|
||||
protected:
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -83,7 +83,7 @@ void HistoryViewCell::layoutSubviews() {
|
||||
}
|
||||
|
||||
void HistoryViewCell::setCalculation(Calculation * calculation) {
|
||||
m_inputView.setExpression(calculation->inputLayout());
|
||||
m_inputView.setExpressionLayout(calculation->inputLayout());
|
||||
App * calculationApp = (App *)app();
|
||||
/* Both output expressions have to be updated at the same time. The
|
||||
* outputView points to deleted layouts and a call to
|
||||
|
||||
@@ -16,8 +16,8 @@ OutputExpressionsView::OutputExpressionsView(Responder * parentResponder) :
|
||||
}
|
||||
|
||||
void OutputExpressionsView::setExpressions(ExpressionLayout ** expressionsLayout) {
|
||||
m_approximateExpressionView.setExpression(expressionsLayout[0]);
|
||||
m_exactExpressionView.setExpression(expressionsLayout[1]);
|
||||
m_approximateExpressionView.setExpressionLayout(expressionsLayout[0]);
|
||||
m_exactExpressionView.setExpressionLayout(expressionsLayout[1]);
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,13 +10,14 @@ ScrollableExpressionView::ScrollableExpressionView(Responder * parentResponder)
|
||||
{
|
||||
}
|
||||
|
||||
void ScrollableExpressionView::setExpression(ExpressionLayout * expressionLayout) {
|
||||
m_expressionView.setExpression(expressionLayout);
|
||||
void ScrollableExpressionView::setExpressionLayout(ExpressionLayout * expressionLayout) {
|
||||
m_expressionView.setExpressionLayout(expressionLayout);
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
void ScrollableExpressionView::setBackgroundColor(KDColor backgroundColor) {
|
||||
m_expressionView.setBackgroundColor(backgroundColor);
|
||||
ScrollableView::setBackgroundColor(backgroundColor);
|
||||
}
|
||||
|
||||
KDSize ScrollableExpressionView::minimalSizeForOptimalDisplay() const {
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace Calculation {
|
||||
class ScrollableExpressionView : public ScrollableView, public ScrollViewDataSource {
|
||||
public:
|
||||
ScrollableExpressionView(Responder * parentResponder);
|
||||
void setExpression(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setBackgroundColor(KDColor backgroundColor);
|
||||
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setBackgroundColor(KDColor backgroundColor) override;
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
private:
|
||||
ExpressionView m_expressionView;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#include "text_field.h"
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
TextField::TextField(Responder * parentResponder, char * textBuffer, size_t textBufferSize, TextFieldDelegate * delegate) :
|
||||
::TextField(parentResponder, textBuffer, textBuffer, textBufferSize, delegate, false)
|
||||
{
|
||||
setEditing(true);
|
||||
}
|
||||
|
||||
bool TextField::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Back) {
|
||||
return false;
|
||||
}
|
||||
if (event == Ion::Events::Ans) {
|
||||
return handleEventWithText("ans");
|
||||
}
|
||||
if (isEditing() && draftTextLength() == 0 &&
|
||||
(event == Ion::Events::Multiplication ||
|
||||
event == Ion::Events::Plus ||
|
||||
event == Ion::Events::Power ||
|
||||
event == Ion::Events::Square ||
|
||||
event == Ion::Events::Division ||
|
||||
event == Ion::Events::Sto)) {
|
||||
handleEventWithText("ans");
|
||||
}
|
||||
return(::TextField::handleEvent(event));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#ifndef CALCULATION_TEXT_FIELD_H
|
||||
#define CALCULATION_TEXT_FIELD_H
|
||||
|
||||
#include <escher.h>
|
||||
|
||||
namespace Calculation {
|
||||
|
||||
class TextField : public ::TextField {
|
||||
public:
|
||||
TextField(Responder * parentResponder, char * textBuffer, size_t textBufferSize, TextFieldDelegate * delegate);
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -19,7 +19,7 @@ PythonCommandBin = "bin(x)"
|
||||
PythonCommandCeil = "ceil(x)"
|
||||
PythonCommandChoice = "choice(list)"
|
||||
PythonCommandCmathFunction = "cmath.function"
|
||||
PythonCommandCmathFunctionWithoutArg = "cmath."
|
||||
PythonCommandCmathFunctionWithoutArg = "cmath.•"
|
||||
PythonCommandColor = "color(r,g,b)"
|
||||
PythonCommandComplex = "complex(a,b)"
|
||||
PythonCommandCopySign = "copysign(x,y)"
|
||||
@@ -57,7 +57,7 @@ PythonCommandIsFinite = "isfinite(x)"
|
||||
PythonCommandIsInfinite = "isinf(x)"
|
||||
PythonCommandIsNaN = "isnan(x)"
|
||||
PythonCommandKandinskyFunction = "kandinsky.function"
|
||||
PythonCommandKandinskyFunctionWithoutArg = "kandinsky."
|
||||
PythonCommandKandinskyFunctionWithoutArg = "kandinsky.•"
|
||||
PythonCommandLdexp = "ldexp(x,i)"
|
||||
PythonCommandLgamma = "lgamma(x)"
|
||||
PythonCommandLength = "len(object)"
|
||||
@@ -66,7 +66,7 @@ PythonCommandLog10 = "log10(x)"
|
||||
PythonCommandLog2 = "log2(x)"
|
||||
PythonCommandLogComplex = "log(z,a)"
|
||||
PythonCommandMathFunction = "math.function"
|
||||
PythonCommandMathFunctionWithoutArg = "math."
|
||||
PythonCommandMathFunctionWithoutArg = "math.•"
|
||||
PythonCommandMax = "max(list)"
|
||||
PythonCommandMin = "min(list)"
|
||||
PythonCommandModf = "modf(x)"
|
||||
@@ -80,7 +80,7 @@ PythonCommandRadians = "radians(x)"
|
||||
PythonCommandRandom = "random()"
|
||||
PythonCommandRandint = "randint(a,b)"
|
||||
PythonCommandRandomFunction = "random.function"
|
||||
PythonCommandRandomFunctionWithoutArg = "random."
|
||||
PythonCommandRandomFunctionWithoutArg = "random.•"
|
||||
PythonCommandRandrange = "randrange(start, stop)"
|
||||
PythonCommandRangeStartStop = "range(start, stop)"
|
||||
PythonCommandRangeStop = "range(stop)"
|
||||
@@ -100,6 +100,6 @@ PythonCommandTanh = "tanh(x)"
|
||||
PythonCommandTrunc = "trunc(x)"
|
||||
PythonCommandImag = "z.imag"
|
||||
PythonCommandReal = "z.real"
|
||||
PythonCommandImagWithoutArg = "().imag"
|
||||
PythonCommandRealWithoutArg = "().real"
|
||||
PythonCommandImagWithoutArg = "•.imag"
|
||||
PythonCommandRealWithoutArg = "•.real"
|
||||
PythonCommandUniform = "uniform(a,b)"
|
||||
|
||||
@@ -279,7 +279,7 @@ bool ConsoleController::textFieldDidFinishEditing(TextField * textField, const c
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConsoleController::textFieldDidAbortEditing(TextField * textField, const char * text) {
|
||||
bool ConsoleController::textFieldDidAbortEditing(TextField * textField) {
|
||||
if (inputRunLoopActive()) {
|
||||
askInputRunLoopTermination();
|
||||
} else {
|
||||
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
|
||||
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;
|
||||
bool textFieldDidAbortEditing(TextField * textField) override;
|
||||
Toolbox * toolboxForTextInput(TextInput * textInput) override;
|
||||
|
||||
// MicroPython::ExecutionEnvironment
|
||||
|
||||
@@ -57,7 +57,7 @@ void MenuController::willExitResponderChain(Responder * nextFirstResponder) {
|
||||
TextField * tf = static_cast<EvenOddEditableTextCell *>(m_selectableTableView.selectedCell())->editableTextCell()->textField();
|
||||
if (tf->isEditing()) {
|
||||
tf->setEditing(false);
|
||||
textFieldDidAbortEditing(tf, tf->text());
|
||||
textFieldDidAbortEditing(tf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -345,8 +345,8 @@ bool MenuController::textFieldDidFinishEditing(TextField * textField, const char
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MenuController::textFieldDidAbortEditing(TextField * textField, const char * text) {
|
||||
if (strlen(text) <= strlen(ScriptStore::k_scriptExtension)) {
|
||||
bool MenuController::textFieldDidAbortEditing(TextField * textField) {
|
||||
if (strlen(textField->text()) <= strlen(ScriptStore::k_scriptExtension)) {
|
||||
// The previous text was an empty name. Use a numbered default script name.
|
||||
char numberedDefaultName[k_defaultScriptNameMaxSize];
|
||||
numberedDefaultScriptName(numberedDefaultName);
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
|
||||
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;
|
||||
bool textFieldDidAbortEditing(TextField * textField) override;
|
||||
bool textFieldDidHandleEvent(TextField * textField, bool returnValue, bool textHasChanged) override;
|
||||
Toolbox * toolboxForTextInput(TextInput * textInput) override { return nullptr; }
|
||||
|
||||
|
||||
@@ -291,10 +291,10 @@ bool PythonToolbox::selectLeaf(ToolboxMessageTree * selectedMessageTree) {
|
||||
m_selectableTableView.deselectTable();
|
||||
ToolboxMessageTree * node = selectedMessageTree;
|
||||
const char * editedText = I18n::translate(node->insertedText());
|
||||
char strippedEditedText[strlen(editedText)+1];
|
||||
Shared::ToolboxHelpers::TextToInsertForCommandMessage(node->insertedText(), strippedEditedText);
|
||||
TextInput * textInput = static_cast<TextInput *>(sender());
|
||||
textInput->handleEventWithText(strippedEditedText, true);
|
||||
int strippedEditedTextMaxLength = strlen(editedText)+1;
|
||||
char strippedEditedText[strippedEditedTextMaxLength];
|
||||
Shared::ToolboxHelpers::TextToInsertForCommandMessage(node->insertedText(), strippedEditedText, strippedEditedTextMaxLength, true);
|
||||
sender()->handleEventWithText(strippedEditedText, true);
|
||||
app()->dismissModalViewController();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -10,10 +10,7 @@ namespace Code {
|
||||
|
||||
class PythonToolbox : public Toolbox {
|
||||
public:
|
||||
typedef void (*Action)(void * sender, const char * text);
|
||||
PythonToolbox();
|
||||
|
||||
// StackViewController
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
protected:
|
||||
KDCoordinate rowHeight(int j) override;
|
||||
|
||||
@@ -20,27 +20,27 @@ NonEqualityCondition = "!="
|
||||
NonEqualityConditionWithArg = "x!=y"
|
||||
EqualityCondition = "=="
|
||||
EqualityConditionWithArg = "x==y"
|
||||
WhileLoop = "while ():\n "
|
||||
WhileLoop = "while •:\n "
|
||||
WhileLoopWithArg = "while condition:\n instruction"
|
||||
IfOrIfElseStatement = "if () or ():\n \nelse:\n "
|
||||
IfOrIfElseStatement = "if • or :\n \nelse:\n "
|
||||
IfOrIfElseStatementWithArg = "if condition1 or condition2:\n instruction1\nelse:\n instruction2"
|
||||
IfAndIfElseStatement = "if () and ():\n \nelse:\n "
|
||||
IfAndIfElseStatement = "if • and :\n \nelse:\n "
|
||||
IfAndIfElseStatementWithArg = "if condition1 and condition2:\n instruction1\nelse:\n instruction2"
|
||||
IfElifElseStatement = "if ():\n \nelif ():\n \nelse:\n "
|
||||
IfElifElseStatement = "if •:\n \nelif :\n \nelse:\n "
|
||||
IfElifElseStatementWithArg = "if condition1:\n instruction1\nelif condition2:\n instruction2\nelse:\n instruction3"
|
||||
IfThenStatement= "if ():\n "
|
||||
IfThenStatement= "if •:\n "
|
||||
IfThenStatementWithArg = "if condition:\n instruction"
|
||||
IfElseStatement = "if ():\n \nelse:\n "
|
||||
IfElseStatement = "if •:\n \nelse:\n "
|
||||
IfElseStatementWithArg = "if condition:\n instruction1\nelse:\n instruction2"
|
||||
ForInListLoop = "for i in ():\n "
|
||||
ForInListLoop = "for i in •:\n "
|
||||
ForInListLoopWithArg = "for i in list:\n instruction"
|
||||
ForInRange3ArgsLoop = "for i in range(,,):\n "
|
||||
ForInRange3ArgsLoop = "for i in range(•,,):\n "
|
||||
ForInRange3ArgsLoopWithArg = "for i in range(start, stop, step):\n instruction"
|
||||
ForInRange2ArgsLoop = "for i in range(,):\n "
|
||||
ForInRange2ArgsLoop = "for i in range(•,):\n "
|
||||
ForInRange2ArgsLoopWithArg = "for i in range(start, stop):\n instruction"
|
||||
ForInRange1ArgLoop = "for i in range():\n "
|
||||
ForInRange1ArgLoop = "for i in range(•):\n "
|
||||
ForInRange1ArgLoopWithArg = "for i in range(size):\n instruction"
|
||||
PythonCommandDef = "def ():\n "
|
||||
PythonCommandDef = "def •():\n "
|
||||
PythonCommandDefWithArg = "def function(x):"
|
||||
PythonCommandReturn = "return "
|
||||
RandomModule = "random"
|
||||
|
||||
@@ -115,8 +115,9 @@ void VariableBoxController::ContentViewController::willDisplayCellForIndex(Highl
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::insertTextInCaller(const char * text) {
|
||||
char commandBuffer[strlen(text)+1];
|
||||
Shared::ToolboxHelpers::TextToInsertForCommandText(text, commandBuffer);
|
||||
int commandBufferMaxSize = strlen(text)+1;
|
||||
char commandBuffer[commandBufferMaxSize];
|
||||
Shared::ToolboxHelpers::TextToInsertForCommandText(text, commandBuffer, commandBufferMaxSize);
|
||||
m_textInputCaller->handleEventWithText(commandBuffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ App::App(Container * container, Snapshot * snapshot) :
|
||||
m_valuesHeader(&m_valuesStackViewController, &m_valuesAlternateEmptyViewController, &m_valuesController),
|
||||
m_valuesStackViewController(&m_tabViewController, &m_valuesHeader),
|
||||
m_tabViewController(&m_inputViewController, snapshot, &m_listStackViewController, &m_graphStackViewController, &m_valuesStackViewController),
|
||||
m_inputViewController(&m_modalViewController, &m_tabViewController, this)
|
||||
m_inputViewController(&m_modalViewController, &m_tabViewController, this, this)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "integral_graph_controller.h"
|
||||
#include "../../shared/text_field_delegate.h"
|
||||
#include "../../../poincare/src/layout/string_layout.h"
|
||||
#include <poincare/layout_engine.h>
|
||||
#include "../app.h"
|
||||
|
||||
#include <assert.h>
|
||||
@@ -39,7 +39,7 @@ double IntegralGraphController::cursorNextStep(double x, int direction) {
|
||||
ExpressionLayout * IntegralGraphController::createFunctionLayout(const char * functionName) {
|
||||
char buffer[7] = "0(x)dx";
|
||||
buffer[0] = functionName[0];
|
||||
return new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small);
|
||||
return LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ void ListController::willDisplayTitleCellAtIndex(HighlightCell * cell, int j) {
|
||||
void ListController::willDisplayExpressionCellAtIndex(HighlightCell * cell, int j) {
|
||||
FunctionExpressionCell * myCell = (FunctionExpressionCell *)cell;
|
||||
Function * f = m_functionStore->functionAtIndex(j);
|
||||
myCell->setExpression(f->layout());
|
||||
myCell->setExpressionLayout(f->layout());
|
||||
bool active = f->isActive();
|
||||
KDColor textColor = active ? KDColorBlack : Palette::GreyDark;
|
||||
myCell->setTextColor(textColor);
|
||||
|
||||
@@ -12,7 +12,8 @@ ion_special_characters = {
|
||||
u'μ': "Ion::Charset::SmallMu",
|
||||
u'σ': "Ion::Charset::SmallSigma",
|
||||
u'≤': "Ion::Charset::LessEqual",
|
||||
u'≈': "Ion::Charset::AlmostEqual"
|
||||
u'≈': "Ion::Charset::AlmostEqual",
|
||||
u'•': "Ion::Charset::Empty"
|
||||
}
|
||||
|
||||
def ion_char(i18n_letter):
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
#include "math_toolbox.h"
|
||||
#include "./shared/toolbox_helpers.h"
|
||||
#include <poincare/expression_layout_array.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
/* TODO: find a shorter way to initialize tree models
|
||||
* We create one model tree: each node keeps the label of the row it refers to
|
||||
* and the text which would be edited by clicking on the row. When the node is a
|
||||
* subtree, the edited text is set at I18n::Message::Default. */
|
||||
|
||||
|
||||
const ToolboxMessageTree calculChildren[4] = {
|
||||
ToolboxMessageTree(I18n::Message::DiffCommandWithArg, I18n::Message::DerivateNumber, I18n::Message::DiffCommandWithArg),
|
||||
ToolboxMessageTree(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommandWithArg),
|
||||
@@ -33,7 +37,8 @@ const ToolboxMessageTree arithmeticChildren[5] = {
|
||||
ToolboxMessageTree(I18n::Message::QuoCommandWithArg, I18n::Message::Quotient, I18n::Message::QuoCommandWithArg)};
|
||||
|
||||
#if MATRICES_ARE_DEFINED
|
||||
const ToolboxMessageTree matricesChildren[5] = {
|
||||
const ToolboxMessageTree matricesChildren[6] = {
|
||||
ToolboxMessageTree(I18n::Message::MatrixCommandWithArg, I18n::Message::NewMatrix, I18n::Message::MatrixCommand),
|
||||
ToolboxMessageTree(I18n::Message::InverseCommandWithArg, I18n::Message::Inverse, I18n::Message::InverseCommandWithArg),
|
||||
ToolboxMessageTree(I18n::Message::DeterminantCommandWithArg, I18n::Message::Determinant, I18n::Message::DeterminantCommandWithArg),
|
||||
ToolboxMessageTree(I18n::Message::TransposeCommandWithArg, I18n::Message::Transpose, I18n::Message::TransposeCommandWithArg),
|
||||
@@ -72,12 +77,13 @@ const ToolboxMessageTree predictionChildren[3] = {
|
||||
ToolboxMessageTree(I18n::Message::ConfidenceCommandWithArg, I18n::Message::Confidence, I18n::Message::ConfidenceCommandWithArg)};
|
||||
|
||||
#if LIST_ARE_DEFINED
|
||||
const ToolboxMessageTree menu[12] = {ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg),
|
||||
const ToolboxMessageTree menu[12] = {
|
||||
#elif MATRICES_ARE_DEFINED
|
||||
const ToolboxMessageTree menu[11] = {ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg),
|
||||
const ToolboxMessageTree menu[11] = {
|
||||
#else
|
||||
const ToolboxMessageTree menu[10] = {ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg),
|
||||
const ToolboxMessageTree menu[10] = {
|
||||
#endif
|
||||
ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommandWithArg),
|
||||
ToolboxMessageTree(I18n::Message::RootCommandWithArg, I18n::Message::NthRoot, I18n::Message::RootCommandWithArg),
|
||||
ToolboxMessageTree(I18n::Message::LogCommandWithArg, I18n::Message::BasedLogarithm, I18n::Message::LogCommandWithArg),
|
||||
ToolboxMessageTree(I18n::Message::Calculation, I18n::Message::Default, I18n::Message::Default, calculChildren, 4),
|
||||
@@ -85,7 +91,7 @@ const ToolboxMessageTree menu[10] = {ToolboxMessageTree(I18n::Message::AbsComman
|
||||
ToolboxMessageTree(I18n::Message::Probability, I18n::Message::Default, I18n::Message::Default, probabilityChildren, 2),
|
||||
ToolboxMessageTree(I18n::Message::Arithmetic, I18n::Message::Default, I18n::Message::Default, arithmeticChildren, 5),
|
||||
#if MATRICES_ARE_DEFINED
|
||||
ToolboxMessageTree(I18n::Message::Matrices, I18n::Message::Default, I18n::Message::Default, matricesChildren, 5),
|
||||
ToolboxMessageTree(I18n::Message::Matrices, I18n::Message::Default, I18n::Message::Default, matricesChildren, 6),
|
||||
#endif
|
||||
#if LIST_ARE_DEFINED
|
||||
ToolboxMessageTree(I18n::Message::Lists, I18n::Message::Default, I18n::Message::Default, listesChildren, 5),
|
||||
@@ -101,21 +107,22 @@ const ToolboxMessageTree toolboxModel = ToolboxMessageTree(I18n::Message::Toolbo
|
||||
const ToolboxMessageTree toolboxModel = ToolboxMessageTree(I18n::Message::Toolbox, I18n::Message::Default, I18n::Message::Default, menu, 10);
|
||||
#endif
|
||||
|
||||
MathToolbox::MathToolbox() : Toolbox(nullptr, I18n::translate(rootModel()->label()))
|
||||
MathToolbox::MathToolbox() :
|
||||
Toolbox(nullptr, I18n::translate(rootModel()->label()))
|
||||
{
|
||||
}
|
||||
|
||||
TextField * MathToolbox::sender() {
|
||||
return (TextField *)Toolbox::sender();
|
||||
}
|
||||
|
||||
bool MathToolbox::selectLeaf(ToolboxMessageTree * selectedMessageTree) {
|
||||
m_selectableTableView.deselectTable();
|
||||
ToolboxMessageTree * messageTree = selectedMessageTree;
|
||||
const char * editedText = I18n::translate(messageTree->insertedText());
|
||||
char strippedEditedText[strlen(editedText)];
|
||||
Shared::ToolboxHelpers::TextToInsertForCommandMessage(messageTree->insertedText(), strippedEditedText);
|
||||
sender()->handleEventWithText(strippedEditedText);
|
||||
m_selectableTableView.deselectTable();
|
||||
|
||||
// Translate the message and remove the arguments
|
||||
const char * text = I18n::translate(messageTree->insertedText());
|
||||
int maxTextToInsertLength = strlen(text) + 1;
|
||||
char textToInsert[maxTextToInsertLength];
|
||||
Shared::ToolboxHelpers::TextToInsertForCommandText(text, textToInsert, maxTextToInsertLength, true);
|
||||
|
||||
sender()->handleEventWithText(textToInsert);
|
||||
app()->dismissModalViewController();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ class MathToolbox : public Toolbox {
|
||||
public:
|
||||
MathToolbox();
|
||||
protected:
|
||||
TextField * sender() override;
|
||||
bool selectLeaf(ToolboxMessageTree * selectedMessageTree) override;
|
||||
const ToolboxMessageTree * rootModel() override;
|
||||
MessageTableCellWithMessage * leafCellAtIndex(int index) override;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "calculation_controller.h"
|
||||
#include "../constant.h"
|
||||
#include "../apps_container.h"
|
||||
#include "../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include "../../poincare/src/layout/string_layout.h"
|
||||
#include "../../poincare/src/layout/char_layout.h"
|
||||
#include "../../poincare/src/layout/horizontal_layout.h"
|
||||
#include "../../poincare/src/layout/vertical_offset_layout.h"
|
||||
#include <poincare.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -21,7 +22,7 @@ CalculationController::CalculationController(Responder * parentResponder, Button
|
||||
m_calculationCells{},
|
||||
m_store(store)
|
||||
{
|
||||
m_r2Layout = new BaselineRelativeLayout(new StringLayout("r", 1, KDText::FontSize::Small), new StringLayout("2", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Superscript);
|
||||
m_r2Layout = new HorizontalLayout(new CharLayout('r', KDText::FontSize::Small), new VerticalOffsetLayout(new CharLayout('2', KDText::FontSize::Small), VerticalOffsetLayout::Type::Superscript, false), false);
|
||||
}
|
||||
|
||||
CalculationController::~CalculationController() {
|
||||
@@ -129,7 +130,7 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int
|
||||
if (i == 0) {
|
||||
if (j == numberOfRows()-1) {
|
||||
EvenOddExpressionCell * myCell = (EvenOddExpressionCell *)cell;
|
||||
myCell->setExpression(m_r2Layout);
|
||||
myCell->setExpressionLayout(m_r2Layout);
|
||||
return;
|
||||
}
|
||||
EvenOddMessageTextCell * myCell = (EvenOddMessageTextCell *)cell;
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
#include "app.h"
|
||||
#include "../apps_container.h"
|
||||
#include "../constant.h"
|
||||
#include "../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include "../../poincare/src/layout/string_layout.h"
|
||||
#include "../../poincare/src/layout/char_layout.h"
|
||||
#include "../../poincare/src/layout/horizontal_layout.h"
|
||||
#include "../../poincare/src/layout/vertical_offset_layout.h"
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Poincare;
|
||||
@@ -15,8 +16,8 @@ StoreController::StoreController(Responder * parentResponder, Store * store, But
|
||||
Shared::StoreController(parentResponder, store, header),
|
||||
m_titleCells{}
|
||||
{
|
||||
m_titleLayout[0] = new BaselineRelativeLayout(new StringLayout("X", 1, KDText::FontSize::Small), new StringLayout("i", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_titleLayout[1] = new BaselineRelativeLayout(new StringLayout("Y", 1, KDText::FontSize::Small), new StringLayout("i", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_titleLayout[0] = new HorizontalLayout(new CharLayout('X', KDText::FontSize::Small), new VerticalOffsetLayout(new CharLayout('i', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), false);
|
||||
m_titleLayout[1] = new HorizontalLayout(new CharLayout('Y', KDText::FontSize::Small), new VerticalOffsetLayout(new CharLayout('i', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false), false);
|
||||
}
|
||||
|
||||
StoreController::~StoreController() {
|
||||
@@ -34,7 +35,7 @@ void StoreController::willDisplayCellAtLocation(HighlightCell * cell, int i, int
|
||||
return;
|
||||
}
|
||||
EvenOddExpressionCell * mytitleCell = (EvenOddExpressionCell *)cell;
|
||||
mytitleCell->setExpression(m_titleLayout[i]);
|
||||
mytitleCell->setExpressionLayout(m_titleLayout[i]);
|
||||
}
|
||||
|
||||
HighlightCell * StoreController::titleCells(int index) {
|
||||
|
||||
@@ -72,7 +72,7 @@ App::App(Container * container, Snapshot * snapshot) :
|
||||
m_valuesHeader(nullptr, &m_valuesAlternateEmptyViewController, &m_valuesController),
|
||||
m_valuesStackViewController(&m_tabViewController, &m_valuesHeader),
|
||||
m_tabViewController(&m_inputViewController, snapshot, &m_listStackViewController, &m_graphStackViewController, &m_valuesStackViewController),
|
||||
m_inputViewController(&m_modalViewController, &m_tabViewController, &m_listController)
|
||||
m_inputViewController(&m_modalViewController, &m_tabViewController, &m_listController, &m_listController)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
#include "term_sum_controller.h"
|
||||
#include "../../shared/text_field_delegate.h"
|
||||
#include "../../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include "../../../poincare/src/layout/string_layout.h"
|
||||
#include "../app.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include "../../../poincare/src/layout/char_layout.h"
|
||||
#include "../../../poincare/src/layout/horizontal_layout.h"
|
||||
#include "../../../poincare/src/layout/vertical_offset_layout.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
extern "C" {
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
}
|
||||
|
||||
using namespace Shared;
|
||||
using namespace Poincare;
|
||||
@@ -46,7 +51,13 @@ double TermSumController::cursorNextStep(double x, int direction) {
|
||||
}
|
||||
|
||||
ExpressionLayout * TermSumController::createFunctionLayout(const char * functionName) {
|
||||
return new BaselineRelativeLayout(new StringLayout(functionName, 1, KDText::FontSize::Small), new StringLayout("n", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
return new HorizontalLayout(
|
||||
new CharLayout(functionName[0], KDText::FontSize::Small),
|
||||
new VerticalOffsetLayout(
|
||||
new CharLayout('n', KDText::FontSize::Small),
|
||||
VerticalOffsetLayout::Type::Subscript,
|
||||
false),
|
||||
false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,20 +24,21 @@ const char * ListController::title() {
|
||||
}
|
||||
|
||||
Toolbox * ListController::toolboxForTextInput(TextInput * textInput) {
|
||||
int recurrenceDepth = -1;
|
||||
int sequenceDefinition = sequenceDefinitionForRow(selectedRow());
|
||||
Sequence * sequence = m_sequenceStore->functionAtIndex(functionIndexForRow(selectedRow()));
|
||||
if (sequenceDefinition == 0) {
|
||||
recurrenceDepth = sequence->numberOfElements()-1;
|
||||
}
|
||||
m_sequenceToolbox.setExtraCells(sequence->name(), recurrenceDepth);
|
||||
return &m_sequenceToolbox;
|
||||
return toolboxForSender(textInput);
|
||||
}
|
||||
|
||||
Toolbox * ListController::toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) {
|
||||
return toolboxForSender(expressionLayoutField);
|
||||
}
|
||||
|
||||
TextFieldDelegateApp * ListController::textFieldDelegateApp() {
|
||||
return (App *)app();
|
||||
}
|
||||
|
||||
ExpressionFieldDelegateApp * ListController::expressionFieldDelegateApp() {
|
||||
return (App *)app();
|
||||
}
|
||||
|
||||
int ListController::numberOfRows() {
|
||||
int numberOfRows = 0;
|
||||
for (int i = 0; i < m_sequenceStore->numberOfFunctions(); i++) {
|
||||
@@ -82,6 +83,20 @@ void ListController::selectPreviousNewSequenceCell() {
|
||||
}
|
||||
}
|
||||
|
||||
Toolbox * ListController::toolboxForSender(Responder * sender) {
|
||||
// Set extra cells
|
||||
int recurrenceDepth = -1;
|
||||
int sequenceDefinition = sequenceDefinitionForRow(selectedRow());
|
||||
Sequence * sequence = m_sequenceStore->functionAtIndex(functionIndexForRow(selectedRow()));
|
||||
if (sequenceDefinition == 0) {
|
||||
recurrenceDepth = sequence->numberOfElements()-1;
|
||||
}
|
||||
m_sequenceToolbox.setExtraCells(sequence->name(), recurrenceDepth);
|
||||
// Set sender
|
||||
m_sequenceToolbox.setSender(sender);
|
||||
return &m_sequenceToolbox;
|
||||
}
|
||||
|
||||
void ListController::editExpression(Sequence * sequence, int sequenceDefinition, Ion::Events::Event event) {
|
||||
char * initialText = nullptr;
|
||||
char initialTextContent[TextField::maxBufferSize()];
|
||||
@@ -169,13 +184,13 @@ void ListController::willDisplayTitleCellAtIndex(HighlightCell * cell, int j) {
|
||||
SequenceTitleCell * myCell = (SequenceTitleCell *)cell;
|
||||
Sequence * sequence = m_sequenceStore->functionAtIndex(functionIndexForRow(j));
|
||||
if (sequenceDefinitionForRow(j) == 0) {
|
||||
myCell->setExpression(sequence->definitionName());
|
||||
myCell->setExpressionLayout(sequence->definitionName());
|
||||
}
|
||||
if (sequenceDefinitionForRow(j) == 1) {
|
||||
myCell->setExpression(sequence->firstInitialConditionName());
|
||||
myCell->setExpressionLayout(sequence->firstInitialConditionName());
|
||||
}
|
||||
if (sequenceDefinitionForRow(j) == 2) {
|
||||
myCell->setExpression(sequence->secondInitialConditionName());
|
||||
myCell->setExpressionLayout(sequence->secondInitialConditionName());
|
||||
}
|
||||
KDColor nameColor = sequence->isActive() ? sequence->color() : Palette::GreyDark;
|
||||
myCell->setColor(nameColor);
|
||||
@@ -185,13 +200,13 @@ void ListController::willDisplayExpressionCellAtIndex(HighlightCell * cell, int
|
||||
FunctionExpressionCell * myCell = (FunctionExpressionCell *)cell;
|
||||
Sequence * sequence = m_sequenceStore->functionAtIndex(functionIndexForRow(j));
|
||||
if (sequenceDefinitionForRow(j) == 0) {
|
||||
myCell->setExpression(sequence->layout());
|
||||
myCell->setExpressionLayout(sequence->layout());
|
||||
}
|
||||
if (sequenceDefinitionForRow(j) == 1) {
|
||||
myCell->setExpression(sequence->firstInitialConditionLayout());
|
||||
myCell->setExpressionLayout(sequence->firstInitialConditionLayout());
|
||||
}
|
||||
if (sequenceDefinitionForRow(j) == 2) {
|
||||
myCell->setExpression(sequence->secondInitialConditionLayout());
|
||||
myCell->setExpressionLayout(sequence->secondInitialConditionLayout());
|
||||
}
|
||||
bool active = sequence->isActive();
|
||||
KDColor textColor = active ? KDColorBlack : Palette::GreyDark;
|
||||
|
||||
@@ -5,16 +5,17 @@
|
||||
#include "../sequence_title_cell.h"
|
||||
#include "../sequence_store.h"
|
||||
#include "../../shared/function_expression_cell.h"
|
||||
#include "type_parameter_controller.h"
|
||||
#include "../../shared/new_function_cell.h"
|
||||
#include "../../shared/list_controller.h"
|
||||
#include "../../shared/new_function_cell.h"
|
||||
#include "../../shared/expression_layout_field_delegate.h"
|
||||
#include "../../shared/text_field_delegate.h"
|
||||
#include "list_parameter_controller.h"
|
||||
#include "sequence_toolbox.h"
|
||||
#include "type_parameter_controller.h"
|
||||
|
||||
namespace Sequence {
|
||||
|
||||
class ListController : public Shared::ListController, public Shared::TextFieldDelegate {
|
||||
class ListController : public Shared::ListController, public Shared::TextFieldDelegate, public Shared::ExpressionLayoutFieldDelegate {
|
||||
public:
|
||||
ListController(Responder * parentResponder, SequenceStore * sequenceStore, ButtonRowController * header, ButtonRowController * footer);
|
||||
const char * title() override;
|
||||
@@ -22,9 +23,12 @@ public:
|
||||
virtual KDCoordinate rowHeight(int j) override;
|
||||
void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override;
|
||||
Toolbox * toolboxForTextInput(TextInput * textInput) override;
|
||||
Toolbox * toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) override;
|
||||
void selectPreviousNewSequenceCell();
|
||||
private:
|
||||
Toolbox * toolboxForSender(Responder * sender);
|
||||
Shared::TextFieldDelegateApp * textFieldDelegateApp() override;
|
||||
Shared::ExpressionFieldDelegateApp * expressionFieldDelegateApp() override;
|
||||
void editExpression(Sequence * sequence, int sequenceDefinitionIndex, Ion::Events::Event event);
|
||||
ListParameterController * parameterController() override;
|
||||
int maxNumberOfRows() override;
|
||||
|
||||
@@ -103,7 +103,7 @@ void ListParameterController::willDisplayCellForIndex(HighlightCell * cell, int
|
||||
cell->setHighlighted(index == selectedRow()); // See FIXME in SelectableTableView::reloadData()
|
||||
Shared::ListParameterController::willDisplayCellForIndex(cell, index);
|
||||
if (cell == &m_typeCell && m_sequence != nullptr) {
|
||||
m_typeCell.setExpression(m_sequence->definitionName());
|
||||
m_typeCell.setExpressionLayout(m_sequence->definitionName());
|
||||
}
|
||||
if (cell == &m_initialRankCell && m_sequence != nullptr) {
|
||||
MessageTableCellWithEditableText * myCell = (MessageTableCellWithEditableText *) cell;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "sequence_toolbox.h"
|
||||
#include "../sequence_store.h"
|
||||
#include "../../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include "../../../poincare/src/layout/string_layout.h"
|
||||
#include "../../../poincare/src/layout/char_layout.h"
|
||||
#include "../../../poincare/src/layout/horizontal_layout.h"
|
||||
#include "../../../poincare/src/layout/vertical_offset_layout.h"
|
||||
#include <poincare/layout_engine.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Poincare;
|
||||
@@ -87,31 +89,31 @@ void SequenceToolbox::setExtraCells(const char * sequenceName, int recurrenceDep
|
||||
const char * otherSequenceName = SequenceStore::k_sequenceNames[1-sequenceIndex];
|
||||
for (int j = 0; j < recurrenceDepth; j++) {
|
||||
const char * indice = j == 0 ? "n" : "n+1";
|
||||
m_addedCellLayout[j] = new BaselineRelativeLayout(new StringLayout(sequenceName, 1, KDText::FontSize::Large), new StringLayout(indice, strlen(indice), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_addedCellLayout[j+recurrenceDepth] = new BaselineRelativeLayout(new StringLayout(otherSequenceName, 1, KDText::FontSize::Large), new StringLayout(indice, strlen(indice), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_addedCellLayout[j] = new HorizontalLayout(
|
||||
new CharLayout(sequenceName[0], KDText::FontSize::Large),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout(indice, strlen(indice), KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
m_addedCellLayout[j+recurrenceDepth] = new HorizontalLayout(
|
||||
new CharLayout(otherSequenceName[0], KDText::FontSize::Large),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout(indice, strlen(indice), KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
if (recurrenceDepth < 2) {
|
||||
const char * indice = recurrenceDepth == 0 ? "n" : (recurrenceDepth == 1 ? "n+1" : "n+2");
|
||||
m_addedCellLayout[2*recurrenceDepth] = new BaselineRelativeLayout(new StringLayout(otherSequenceName, 1, KDText::FontSize::Large), new StringLayout(indice, strlen(indice), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_addedCellLayout[2*recurrenceDepth] = new HorizontalLayout(
|
||||
new CharLayout(otherSequenceName[0], KDText::FontSize::Large),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout(indice, strlen(indice), KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
for (int index = 0; index < k_maxNumberOfDisplayedRows; index++) {
|
||||
m_addedCells[index].setExpression(m_addedCellLayout[index]);
|
||||
m_addedCells[index].setExpressionLayout(m_addedCellLayout[index]);
|
||||
}
|
||||
}
|
||||
|
||||
bool SequenceToolbox::selectAddedCell(int selectedRow){
|
||||
char buffer[10];
|
||||
BaselineRelativeLayout * layout = (BaselineRelativeLayout *)m_addedCellLayout[selectedRow];
|
||||
StringLayout * nameLayout = (StringLayout *)layout->baseLayout();
|
||||
StringLayout * subscriptLayout = (StringLayout *)layout->indiceLayout();
|
||||
int currentChar = 0;
|
||||
strlcpy(buffer, nameLayout->text(), strlen(nameLayout->text())+1);
|
||||
currentChar += strlen(nameLayout->text());
|
||||
buffer[currentChar++] = '(';
|
||||
strlcpy(buffer+currentChar, subscriptLayout->text(), strlen(subscriptLayout->text())+1);
|
||||
currentChar += strlen(subscriptLayout->text());
|
||||
buffer[currentChar++] = ')';
|
||||
buffer[currentChar] = 0;
|
||||
int bufferSize = 10;
|
||||
char buffer[bufferSize];
|
||||
m_addedCellLayout[selectedRow]->writeTextInBuffer(buffer, bufferSize);
|
||||
sender()->handleEventWithText(buffer);
|
||||
app()->dismissModalViewController();
|
||||
return true;
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
#include "list_controller.h"
|
||||
#include "../app.h"
|
||||
#include <assert.h>
|
||||
#include "../../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include "../../../poincare/src/layout/string_layout.h"
|
||||
#include <poincare/layout_engine.h>
|
||||
#include "../../../poincare/src/layout/char_layout.h"
|
||||
#include "../../../poincare/src/layout/horizontal_layout.h"
|
||||
#include "../../../poincare/src/layout/vertical_offset_layout.h"
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
@@ -126,9 +128,12 @@ void TypeParameterController::willDisplayCellAtLocation(HighlightCell * cell, in
|
||||
delete m_expressionLayouts[j];
|
||||
m_expressionLayouts[j] = nullptr;
|
||||
}
|
||||
m_expressionLayouts[j] = new BaselineRelativeLayout(new StringLayout(nextName, 1, size), new StringLayout(subscripts[j], strlen(subscripts[j]), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_expressionLayouts[j] = new HorizontalLayout(
|
||||
new CharLayout(nextName[0], size),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout(subscripts[j], strlen(subscripts[j]), KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
ExpressionTableCellWithPointer * myCell = (ExpressionTableCellWithPointer *)cell;
|
||||
myCell->setExpression(m_expressionLayouts[j]);
|
||||
myCell->setExpressionLayout(m_expressionLayouts[j]);
|
||||
}
|
||||
|
||||
void TypeParameterController::setSequence(Sequence * sequence) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "sequence.h"
|
||||
#include "sequence_store.h"
|
||||
#include "cache_context.h"
|
||||
#include "../../poincare/src/layout/string_layout.h"
|
||||
#include "../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include <poincare/layout_engine.h>
|
||||
#include "../../poincare/src/layout/char_layout.h"
|
||||
#include "../../poincare/src/layout/horizontal_layout.h"
|
||||
#include "../../poincare/src/layout/vertical_offset_layout.h"
|
||||
#include <string.h>
|
||||
#include <cmath>
|
||||
|
||||
@@ -221,7 +223,10 @@ int Sequence::numberOfElements() {
|
||||
|
||||
Poincare::ExpressionLayout * Sequence::nameLayout() {
|
||||
if (m_nameLayout == nullptr) {
|
||||
m_nameLayout = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n", 1, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_nameLayout = new HorizontalLayout(
|
||||
new CharLayout(name()[0], KDText::FontSize::Small),
|
||||
new VerticalOffsetLayout(new CharLayout('n', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
return m_nameLayout;
|
||||
}
|
||||
@@ -229,13 +234,22 @@ Poincare::ExpressionLayout * Sequence::nameLayout() {
|
||||
Poincare::ExpressionLayout * Sequence::definitionName() {
|
||||
if (m_definitionName == nullptr) {
|
||||
if (m_type == Type::Explicit) {
|
||||
m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n ", 2, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_definitionName = new HorizontalLayout(
|
||||
new CharLayout(name()[0], KDText::FontSize::Large),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout("n ", 2, KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
if (m_type == Type::SingleRecurrence) {
|
||||
m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n+1 ", 4, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_definitionName = new HorizontalLayout(
|
||||
new CharLayout(name()[0], KDText::FontSize::Large),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout("n+1 ", 4, KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
if (m_type == Type::DoubleRecurrence) {
|
||||
m_definitionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout("n+2 ", 4, KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
m_definitionName = new HorizontalLayout(
|
||||
new CharLayout(name()[0], KDText::FontSize::Large),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout("n+2 ", 4, KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
}
|
||||
return m_definitionName;
|
||||
@@ -244,13 +258,14 @@ Poincare::ExpressionLayout * Sequence::definitionName() {
|
||||
Poincare::ExpressionLayout * Sequence::firstInitialConditionName() {
|
||||
char buffer[k_initialRankNumberOfDigits+1];
|
||||
Integer(m_initialRank).writeTextInBuffer(buffer, k_initialRankNumberOfDigits+1);
|
||||
if (m_firstInitialConditionName == nullptr) {
|
||||
if (m_type == Type::SingleRecurrence) {
|
||||
m_firstInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
}
|
||||
if (m_type == Type::DoubleRecurrence) {
|
||||
m_firstInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
}
|
||||
if (m_firstInitialConditionName == nullptr
|
||||
&& (m_type == Type::SingleRecurrence
|
||||
|| m_type == Type::DoubleRecurrence))
|
||||
{
|
||||
m_firstInitialConditionName = new HorizontalLayout(
|
||||
new CharLayout(name()[0], KDText::FontSize::Small),
|
||||
new VerticalOffsetLayout(new CharLayout('0', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
return m_firstInitialConditionName;
|
||||
}
|
||||
@@ -260,8 +275,10 @@ Poincare::ExpressionLayout * Sequence::secondInitialConditionName() {
|
||||
Integer(m_initialRank+1).writeTextInBuffer(buffer, k_initialRankNumberOfDigits+1);
|
||||
if (m_secondInitialConditionName == nullptr) {
|
||||
if (m_type == Type::DoubleRecurrence) {
|
||||
m_secondInitialConditionName = new BaselineRelativeLayout(new StringLayout(name(), 1), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript);
|
||||
|
||||
m_secondInitialConditionName = new HorizontalLayout(
|
||||
new CharLayout(name()[0], KDText::FontSize::Small),
|
||||
new VerticalOffsetLayout(new CharLayout('1', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
|
||||
false);
|
||||
}
|
||||
}
|
||||
return m_secondInitialConditionName;
|
||||
|
||||
@@ -12,8 +12,8 @@ SequenceTitleCell::SequenceTitleCell(Orientation orientation) :
|
||||
{
|
||||
}
|
||||
|
||||
void SequenceTitleCell::setExpression(Poincare::ExpressionLayout * expressionLayout) {
|
||||
m_titleTextView.setExpression(expressionLayout);
|
||||
void SequenceTitleCell::setExpressionLayout(Poincare::ExpressionLayout * expressionLayout) {
|
||||
m_titleTextView.setExpressionLayout(expressionLayout);
|
||||
}
|
||||
|
||||
void SequenceTitleCell::setHighlighted(bool highlight) {
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Sequence {
|
||||
class SequenceTitleCell : public Shared::FunctionTitleCell {
|
||||
public:
|
||||
SequenceTitleCell(Orientation orientation);
|
||||
void setExpression(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setEven(bool even) override;
|
||||
void setHighlighted(bool highlight) override;
|
||||
void setColor(KDColor color) override;
|
||||
|
||||
@@ -30,7 +30,7 @@ void ValuesController::willDisplayCellAtLocation(HighlightCell * cell, int i, in
|
||||
if (j == 0 && i > 0) {
|
||||
SequenceTitleCell * myCell = (SequenceTitleCell *)cell;
|
||||
Sequence * sequence = m_sequenceStore->activeFunctionAtIndex(i-1);
|
||||
myCell->setExpression(sequence->nameLayout());
|
||||
myCell->setExpressionLayout(sequence->nameLayout());
|
||||
myCell->setColor(sequence->color());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ snapshot_headers += apps/settings/app.h
|
||||
|
||||
app_objs += $(addprefix apps/settings/,\
|
||||
app.o\
|
||||
helpers.o\
|
||||
language_controller.o\
|
||||
main_controller.o\
|
||||
settings_message_tree.o\
|
||||
|
||||
@@ -2,6 +2,9 @@ SettingsApp = "Einstellungen"
|
||||
SettingsAppCapital = "EINSTELLUNGEN"
|
||||
AngleUnit = "Winkeleinheit"
|
||||
DisplayMode = "Zahlenformat"
|
||||
EditionMode = "Eintrag"
|
||||
EditionLinear = "In Zeilen "
|
||||
Edition2D = "Natürliche "
|
||||
ComplexFormat = "Komplex"
|
||||
ExamMode = "Testmodus"
|
||||
ActivateExamMode = "Start Testmodus"
|
||||
|
||||
@@ -2,6 +2,9 @@ SettingsApp = "Settings"
|
||||
SettingsAppCapital = "SETTINGS"
|
||||
AngleUnit = "Angle measure"
|
||||
DisplayMode = "Result format"
|
||||
EditionMode = "Writing format"
|
||||
EditionLinear = "Linear "
|
||||
Edition2D = "Natural "
|
||||
ComplexFormat = "Complex format"
|
||||
ExamMode = "Exam mode"
|
||||
ActivateExamMode = "Activate exam mode"
|
||||
|
||||
@@ -2,6 +2,9 @@ SettingsApp = "Configuracion"
|
||||
SettingsAppCapital = "CONFIGURACION"
|
||||
AngleUnit = "Medida del angulo"
|
||||
DisplayMode = "Formato resultado"
|
||||
EditionMode = "Formato escritura"
|
||||
EditionLinear = "En línea "
|
||||
Edition2D = "Natural "
|
||||
ComplexFormat = "Formato complejo"
|
||||
ExamMode = "Modo examen"
|
||||
ActivateExamMode = "Activar el modo examen"
|
||||
|
||||
@@ -2,6 +2,9 @@ SettingsApp = "Parametres"
|
||||
SettingsAppCapital = "PARAMETRES"
|
||||
AngleUnit = "Unite d'angle"
|
||||
DisplayMode = "Format resultat"
|
||||
EditionMode = "Format écriture"
|
||||
EditionLinear = "En ligne "
|
||||
Edition2D = "Naturelle "
|
||||
ComplexFormat = "Forme complexe"
|
||||
ExamMode = "Mode examen"
|
||||
ActivateExamMode = "Activer le mode examen"
|
||||
|
||||
@@ -2,6 +2,9 @@ SettingsApp = "Configuracao"
|
||||
SettingsAppCapital = "CONFIGURACAO"
|
||||
AngleUnit = "Valor do angulo"
|
||||
DisplayMode = "Formato numerico"
|
||||
EditionMode = "Formato escrita "
|
||||
EditionLinear = "Em linha "
|
||||
Edition2D = "Natural "
|
||||
ComplexFormat = "Complexos"
|
||||
ExamMode = "Modo de Exame"
|
||||
ActivateExamMode = "Inicio modo de exame"
|
||||
|
||||
27
apps/settings/helpers.cpp
Normal file
27
apps/settings/helpers.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "helpers.h"
|
||||
#include <poincare/layout_engine.h>
|
||||
#include <ion/charset.h>
|
||||
#include "../../poincare/src/layout/horizontal_layout.h"
|
||||
#include "../../poincare/src/layout/vertical_offset_layout.h"
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Settings {
|
||||
namespace Helpers {
|
||||
|
||||
ExpressionLayout * CartesianComplexFormat(KDText::FontSize fontSize) {
|
||||
const char text[] = {'a','+', Ion::Charset::IComplex, 'b', ' '};
|
||||
return LayoutEngine::createStringLayout(text, sizeof(text), fontSize);
|
||||
}
|
||||
|
||||
ExpressionLayout * PolarComplexFormat(KDText::FontSize fontSize) {
|
||||
const char base[] = {'r', Ion::Charset::Exponential};
|
||||
const char superscript[] = {Ion::Charset::IComplex, Ion::Charset::SmallTheta, ' '};
|
||||
return new HorizontalLayout(
|
||||
LayoutEngine::createStringLayout(base, sizeof(base), fontSize),
|
||||
new VerticalOffsetLayout(LayoutEngine::createStringLayout(superscript, sizeof(superscript), fontSize), VerticalOffsetLayout::Type::Superscript, false),
|
||||
false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
15
apps/settings/helpers.h
Normal file
15
apps/settings/helpers.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef SETTINGS_HELPERS_H
|
||||
#define SETTINGS_HELPERS_H
|
||||
|
||||
#include <poincare/expression_layout.h>
|
||||
|
||||
namespace Settings {
|
||||
namespace Helpers {
|
||||
|
||||
Poincare::ExpressionLayout * CartesianComplexFormat(KDText::FontSize fontSize);
|
||||
Poincare::ExpressionLayout * PolarComplexFormat(KDText::FontSize fontSize);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,36 +1,40 @@
|
||||
#include "main_controller.h"
|
||||
#include "helpers.h"
|
||||
#include "../global_preferences.h"
|
||||
#include "../i18n.h"
|
||||
#include "../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include "../../poincare/src/layout/string_layout.h"
|
||||
#include <assert.h>
|
||||
#include <poincare.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Settings {
|
||||
|
||||
const SettingsMessageTree angleChildren[2] = {SettingsMessageTree(I18n::Message::Degres), SettingsMessageTree(I18n::Message::Radian)};
|
||||
const SettingsMessageTree FloatDisplayModeChildren[3] = {SettingsMessageTree(I18n::Message::Auto), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::SignificantFigures)};
|
||||
const SettingsMessageTree editionModeChildren[2] = {SettingsMessageTree(I18n::Message::EditionLinear), SettingsMessageTree(I18n::Message::Edition2D)};
|
||||
const SettingsMessageTree floatDisplayModeChildren[3] = {SettingsMessageTree(I18n::Message::Auto), SettingsMessageTree(I18n::Message::Scientific), SettingsMessageTree(I18n::Message::SignificantFigures)};
|
||||
const SettingsMessageTree complexFormatChildren[2] = {SettingsMessageTree(I18n::Message::Default), SettingsMessageTree(I18n::Message::Default)};
|
||||
const SettingsMessageTree examChildren[1] = {SettingsMessageTree(I18n::Message::ActivateExamMode)};
|
||||
const SettingsMessageTree aboutChildren[3] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId)};
|
||||
|
||||
#if EPSILON_SOFTWARE_UPDATE_PROMPT
|
||||
const SettingsMessageTree menu[8] =
|
||||
const SettingsMessageTree menu[9] =
|
||||
#else
|
||||
const SettingsMessageTree menu[7] =
|
||||
const SettingsMessageTree menu[8] =
|
||||
#endif
|
||||
{SettingsMessageTree(I18n::Message::AngleUnit, angleChildren, 2), SettingsMessageTree(I18n::Message::DisplayMode, FloatDisplayModeChildren, 3), SettingsMessageTree(I18n::Message::ComplexFormat, complexFormatChildren, 2),
|
||||
SettingsMessageTree(I18n::Message::Brightness), SettingsMessageTree(I18n::Message::Language), SettingsMessageTree(I18n::Message::ExamMode, examChildren, 1),
|
||||
{SettingsMessageTree(I18n::Message::AngleUnit, angleChildren, 2),
|
||||
SettingsMessageTree(I18n::Message::DisplayMode, floatDisplayModeChildren, 3),
|
||||
SettingsMessageTree(I18n::Message::EditionMode, editionModeChildren, 2),
|
||||
SettingsMessageTree(I18n::Message::ComplexFormat, complexFormatChildren, 2),
|
||||
SettingsMessageTree(I18n::Message::Brightness),
|
||||
SettingsMessageTree(I18n::Message::Language),
|
||||
SettingsMessageTree(I18n::Message::ExamMode, examChildren, 1),
|
||||
#if EPSILON_SOFTWARE_UPDATE_PROMPT
|
||||
SettingsMessageTree(I18n::Message::UpdatePopUp),
|
||||
#endif
|
||||
SettingsMessageTree(I18n::Message::About, aboutChildren, 3)};
|
||||
#if EPSILON_SOFTWARE_UPDATE_PROMPT
|
||||
const SettingsMessageTree model = SettingsMessageTree(I18n::Message::SettingsApp, menu, 8);
|
||||
const SettingsMessageTree model = SettingsMessageTree(I18n::Message::SettingsApp, menu, 9);
|
||||
#else
|
||||
const SettingsMessageTree model = SettingsMessageTree(I18n::Message::SettingsApp, menu, 7);
|
||||
const SettingsMessageTree model = SettingsMessageTree(I18n::Message::SettingsApp, menu, 8);
|
||||
#endif
|
||||
|
||||
MainController::MainController(Responder * parentResponder) :
|
||||
@@ -150,14 +154,14 @@ int MainController::reusableCellCount(int type) {
|
||||
}
|
||||
|
||||
int MainController::typeAtLocation(int i, int j) {
|
||||
if (j == 2) {
|
||||
if (j == 3) {
|
||||
return 1;
|
||||
}
|
||||
if (j == 3) {
|
||||
if (j == 4) {
|
||||
return 2;
|
||||
}
|
||||
#if EPSILON_SOFTWARE_UPDATE_PROMPT
|
||||
if (j == 6) {
|
||||
if (j == 7) {
|
||||
return 3;
|
||||
}
|
||||
#endif
|
||||
@@ -168,36 +172,33 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) {
|
||||
MessageTableCell * myCell = (MessageTableCell *)cell;
|
||||
myCell->setMessage(m_messageTreeModel->children(index)->label());
|
||||
|
||||
if (index == 2) {
|
||||
if (index == 3) {
|
||||
if (m_complexFormatLayout) {
|
||||
delete m_complexFormatLayout;
|
||||
m_complexFormatLayout = nullptr;
|
||||
}
|
||||
if (Preferences::sharedPreferences()->complexFormat() == Expression::ComplexFormat::Cartesian) {
|
||||
const char text[] = {'a','+', Ion::Charset::IComplex, 'b', ' '};
|
||||
m_complexFormatLayout = new StringLayout(text, sizeof(text), KDText::FontSize::Small);
|
||||
m_complexFormatLayout = Helpers::CartesianComplexFormat(KDText::FontSize::Small);
|
||||
} else {
|
||||
const char base[] = {'r', Ion::Charset::Exponential};
|
||||
const char superscript[] = {Ion::Charset::IComplex, Ion::Charset::SmallTheta, ' '};
|
||||
m_complexFormatLayout = new BaselineRelativeLayout(new StringLayout(base, sizeof(base), KDText::FontSize::Small), new StringLayout(superscript, sizeof(superscript), KDText::FontSize::Small), BaselineRelativeLayout::Type::Superscript);
|
||||
m_complexFormatLayout = Helpers::PolarComplexFormat(KDText::FontSize::Small);
|
||||
}
|
||||
MessageTableCellWithChevronAndExpression * myExpCell = (MessageTableCellWithChevronAndExpression *)cell;
|
||||
myExpCell->setExpression(m_complexFormatLayout);
|
||||
myExpCell->setExpressionLayout(m_complexFormatLayout);
|
||||
return;
|
||||
}
|
||||
if (index == 3) {
|
||||
if (index == 4) {
|
||||
MessageTableCellWithGauge * myGaugeCell = (MessageTableCellWithGauge *)cell;
|
||||
GaugeView * myGauge = (GaugeView *)myGaugeCell->accessoryView();
|
||||
myGauge->setLevel((float)GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()/(float)Ion::Backlight::MaxBrightness);
|
||||
return;
|
||||
}
|
||||
if (index == 4) {
|
||||
if (index == 5) {
|
||||
int index = (int)GlobalPreferences::sharedGlobalPreferences()->language()-1;
|
||||
static_cast<MessageTableCellWithChevronAndMessage *>(cell)->setSubtitle(I18n::LanguageNames[index]);
|
||||
return;
|
||||
}
|
||||
#if EPSILON_SOFTWARE_UPDATE_PROMPT
|
||||
if (index == 6) {
|
||||
if (index == 7) {
|
||||
MessageTableCellWithSwitch * mySwitchCell = (MessageTableCellWithSwitch *)cell;
|
||||
SwitchView * mySwitch = (SwitchView *)mySwitchCell->accessoryView();
|
||||
mySwitch->setState(GlobalPreferences::sharedGlobalPreferences()->showUpdatePopUp());
|
||||
@@ -212,6 +213,9 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) {
|
||||
case 1:
|
||||
myTextCell->setSubtitle(m_messageTreeModel->children(index)->children((int)Preferences::sharedPreferences()->displayMode())->label());
|
||||
break;
|
||||
case 2:
|
||||
myTextCell->setSubtitle(m_messageTreeModel->children(index)->children((int)Preferences::sharedPreferences()->editionMode())->label());
|
||||
break;
|
||||
default:
|
||||
myTextCell->setSubtitle(I18n::Message::Default);
|
||||
break;
|
||||
|
||||
@@ -31,12 +31,12 @@ public:
|
||||
private:
|
||||
StackViewController * stackController() const;
|
||||
#if EPSILON_SOFTWARE_UPDATE_PROMPT
|
||||
constexpr static int k_totalNumberOfCell = 8;
|
||||
constexpr static int k_totalNumberOfCell = 9;
|
||||
MessageTableCellWithSwitch m_updateCell;
|
||||
#else
|
||||
constexpr static int k_totalNumberOfCell = 7;
|
||||
constexpr static int k_totalNumberOfCell = 8;
|
||||
#endif
|
||||
constexpr static int k_numberOfSimpleChevronCells = 5;
|
||||
constexpr static int k_numberOfSimpleChevronCells = 6;
|
||||
MessageTableCellWithChevronAndMessage m_cells[k_numberOfSimpleChevronCells];
|
||||
MessageTableCellWithChevronAndExpression m_complexFormatCell;
|
||||
MessageTableCellWithGauge m_brightnessCell;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "sub_controller.h"
|
||||
#include "helpers.h"
|
||||
#include "../global_preferences.h"
|
||||
#include "../apps_container.h"
|
||||
#include "../../poincare/src/layout/baseline_relative_layout.h"
|
||||
#include "../../poincare/src/layout/string_layout.h"
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
|
||||
@@ -23,13 +22,10 @@ SubController::SubController(Responder * parentResponder) :
|
||||
m_cells[i].setAccessoryFontSize(KDText::FontSize::Small);
|
||||
m_cells[i].setAccessoryTextColor(Palette::GreyDark);
|
||||
}
|
||||
const char text[] = {'a','+', Ion::Charset::IComplex, 'b', ' '};
|
||||
m_complexFormatLayout[0] = new StringLayout(text, sizeof(text));
|
||||
const char base[] = {'r', Ion::Charset::Exponential};
|
||||
const char superscript[] = {Ion::Charset::IComplex, Ion::Charset::SmallTheta, ' '};
|
||||
m_complexFormatLayout[1] = new BaselineRelativeLayout(new StringLayout(base, sizeof(base)), new StringLayout(superscript, sizeof(superscript)), BaselineRelativeLayout::Type::Superscript);
|
||||
m_complexFormatLayout[0] = Helpers::CartesianComplexFormat(KDText::FontSize::Large);
|
||||
m_complexFormatLayout[1] = Helpers::PolarComplexFormat(KDText::FontSize::Large);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
m_complexFormatCells[i].setExpression(m_complexFormatLayout[i]);
|
||||
m_complexFormatCells[i].setExpressionLayout(m_complexFormatLayout[i]);
|
||||
}
|
||||
m_editableCell.setMessage(I18n::Message::SignificantFigures);
|
||||
m_editableCell.setMessageFontSize(KDText::FontSize::Large);
|
||||
@@ -74,7 +70,7 @@ bool SubController::handleEvent(Ion::Events::Event event) {
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
|
||||
/* Behavious of "Exam mode" menu*/
|
||||
/* Behaviour of "Exam mode" menu*/
|
||||
if (m_messageTreeModel->label() == I18n::Message::ExamMode) {
|
||||
if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) {
|
||||
return false;
|
||||
@@ -250,6 +246,9 @@ void SubController::setPreferenceWithValueIndex(I18n::Message message, int value
|
||||
if (message == I18n::Message::DisplayMode) {
|
||||
Preferences::sharedPreferences()->setDisplayMode((PrintFloat::Mode)valueIndex);
|
||||
}
|
||||
if (message == I18n::Message::EditionMode) {
|
||||
Preferences::sharedPreferences()->setEditionMode((Preferences::EditionMode)valueIndex);
|
||||
}
|
||||
if (message == I18n::Message::ComplexFormat) {
|
||||
Preferences::sharedPreferences()->setComplexFormat((Expression::ComplexFormat)valueIndex);
|
||||
}
|
||||
@@ -262,6 +261,9 @@ int SubController::valueIndexForPreference(I18n::Message message) {
|
||||
if (message == I18n::Message::DisplayMode) {
|
||||
return (int)Preferences::sharedPreferences()->displayMode();
|
||||
}
|
||||
if (message == I18n::Message::EditionMode) {
|
||||
return (int)Preferences::sharedPreferences()->editionMode();
|
||||
}
|
||||
if (message == I18n::Message::ComplexFormat) {
|
||||
return (int)Preferences::sharedPreferences()->complexFormat();
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ LcmCommandWithArg = "lcm(p,q)"
|
||||
LeftIntegralFirstLegend = "P(X≤"
|
||||
LeftIntegralSecondLegend = ")="
|
||||
LogCommandWithArg = "log(x,a)"
|
||||
MatrixCommand = "[[•]]"
|
||||
MatrixCommandWithArg = "[[1,2][3,4]]"
|
||||
MaxCommandWithArg = "max(L)"
|
||||
MinCommandWithArg = "min(L)"
|
||||
Mu = "μ"
|
||||
|
||||
@@ -6,6 +6,7 @@ app_objs += $(addprefix apps/shared/,\
|
||||
curve_view_cursor.o\
|
||||
curve_view_range.o\
|
||||
editable_cell_table_view_controller.o\
|
||||
expression_field_delegate_app.o\
|
||||
float_pair_store.o\
|
||||
float_parameter_controller.o\
|
||||
function.o\
|
||||
@@ -37,6 +38,7 @@ app_objs += $(addprefix apps/shared/,\
|
||||
regular_table_view_data_source.o\
|
||||
round_cursor_view.o\
|
||||
simple_interactive_curve_view_controller.o\
|
||||
expression_layout_field_delegate.o\
|
||||
store_controller.o\
|
||||
store_parameter_controller.o\
|
||||
sum_graph_controller.o\
|
||||
|
||||
71
apps/shared/expression_field_delegate_app.cpp
Normal file
71
apps/shared/expression_field_delegate_app.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "expression_field_delegate_app.h"
|
||||
#include "../i18n.h"
|
||||
#include "../apps_container.h"
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
ExpressionFieldDelegateApp::ExpressionFieldDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController) :
|
||||
TextFieldDelegateApp(container, snapshot, rootViewController),
|
||||
ExpressionLayoutFieldDelegate()
|
||||
{
|
||||
}
|
||||
|
||||
char ExpressionFieldDelegateApp::privateXNT(ExpressionLayoutField * expressionLayoutField) {
|
||||
char xntCharFromLayout = expressionLayoutField->XNTChar();
|
||||
if (xntCharFromLayout != Ion::Charset::Empty) {
|
||||
return xntCharFromLayout;
|
||||
}
|
||||
return XNT()[0];
|
||||
}
|
||||
|
||||
bool ExpressionFieldDelegateApp::expressionLayoutFieldShouldFinishEditing(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) {
|
||||
return event == Ion::Events::OK || event == Ion::Events::EXE;
|
||||
}
|
||||
|
||||
bool ExpressionFieldDelegateApp::expressionLayoutFieldDidReceiveEvent(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) {
|
||||
if (expressionLayoutField->isEditing() && expressionLayoutField->expressionLayoutFieldShouldFinishEditing(event)) {
|
||||
if (!expressionLayoutField->hasText()) {
|
||||
expressionLayoutField->app()->displayWarning(I18n::Message::SyntaxError);
|
||||
return true;
|
||||
}
|
||||
int bufferSize = 256;
|
||||
char buffer[bufferSize];
|
||||
expressionLayoutField->writeTextInBuffer(buffer, bufferSize);
|
||||
Expression * exp = Expression::parse(buffer);
|
||||
if (exp != nullptr) {
|
||||
delete exp;
|
||||
}
|
||||
if (exp == nullptr) {
|
||||
expressionLayoutField->app()->displayWarning(I18n::Message::SyntaxError);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (event == Ion::Events::Var) {
|
||||
if (!expressionLayoutField->isEditing()) {
|
||||
expressionLayoutField->setEditing(true);
|
||||
}
|
||||
AppsContainer * appsContainer = (AppsContainer *)expressionLayoutField->app()->container();
|
||||
VariableBoxController * variableBoxController = appsContainer->variableBoxController();
|
||||
variableBoxController->setSender(expressionLayoutField);
|
||||
expressionLayoutField->app()->displayModalViewController(variableBoxController, 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin);
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::XNT) {
|
||||
if (!expressionLayoutField->isEditing()) {
|
||||
expressionLayoutField->setEditing(true);
|
||||
}
|
||||
const char xnt[2] = {privateXNT(expressionLayoutField), 0};
|
||||
return expressionLayoutField->handleEventWithText(xnt);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Toolbox * ExpressionFieldDelegateApp::toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) {
|
||||
Toolbox * toolbox = container()->mathToolbox();
|
||||
toolbox->setSender(expressionLayoutField);
|
||||
return toolbox;
|
||||
}
|
||||
|
||||
}
|
||||
22
apps/shared/expression_field_delegate_app.h
Normal file
22
apps/shared/expression_field_delegate_app.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef SHARED_EXPRESSION_FIELD_DELEGATE_APP_H
|
||||
#define SHARED_EXPRESSION_FIELD_DELEGATE_APP_H
|
||||
|
||||
#include "text_field_delegate_app.h"
|
||||
#include <escher/expression_layout_field_delegate.h>
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class ExpressionFieldDelegateApp : public TextFieldDelegateApp, public ExpressionLayoutFieldDelegate {
|
||||
public:
|
||||
virtual ~ExpressionFieldDelegateApp() = default;
|
||||
bool expressionLayoutFieldShouldFinishEditing(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
|
||||
virtual bool expressionLayoutFieldDidReceiveEvent(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
|
||||
Toolbox * toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) override;
|
||||
protected:
|
||||
char privateXNT(ExpressionLayoutField * expressionLayoutField);
|
||||
ExpressionFieldDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
31
apps/shared/expression_layout_field_delegate.cpp
Normal file
31
apps/shared/expression_layout_field_delegate.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "expression_layout_field_delegate.h"
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
bool ExpressionLayoutFieldDelegate::expressionLayoutFieldShouldFinishEditing(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) {
|
||||
return expressionFieldDelegateApp()->expressionLayoutFieldShouldFinishEditing(expressionLayoutField, event);
|
||||
}
|
||||
|
||||
bool ExpressionLayoutFieldDelegate::expressionLayoutFieldDidReceiveEvent(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) {
|
||||
return expressionFieldDelegateApp()->expressionLayoutFieldDidReceiveEvent(expressionLayoutField, event);
|
||||
}
|
||||
|
||||
bool ExpressionLayoutFieldDelegate::expressionLayoutFieldDidFinishEditing(ExpressionLayoutField * expressionLayoutField, const char * text, Ion::Events::Event event) {
|
||||
return expressionFieldDelegateApp()->expressionLayoutFieldDidFinishEditing(expressionLayoutField, text, event);
|
||||
}
|
||||
|
||||
bool ExpressionLayoutFieldDelegate::expressionLayoutFieldDidAbortEditing(ExpressionLayoutField * expressionLayoutField) {
|
||||
return expressionFieldDelegateApp()->expressionLayoutFieldDidAbortEditing(expressionLayoutField);
|
||||
}
|
||||
|
||||
void ExpressionLayoutFieldDelegate::expressionLayoutFieldDidChangeSize(ExpressionLayoutField * expressionLayoutField) {
|
||||
return expressionFieldDelegateApp()->expressionLayoutFieldDidChangeSize(expressionLayoutField);
|
||||
}
|
||||
|
||||
Toolbox * ExpressionLayoutFieldDelegate::toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) {
|
||||
return expressionFieldDelegateApp()->toolboxForExpressionLayoutField(expressionLayoutField);
|
||||
}
|
||||
|
||||
}
|
||||
23
apps/shared/expression_layout_field_delegate.h
Normal file
23
apps/shared/expression_layout_field_delegate.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef SHARED_EXPRESSION_LAYOUT_FIELD_DELEGATE_H
|
||||
#define SHARED_EXPRESSION_LAYOUT_FIELD_DELEGATE_H
|
||||
|
||||
#include <escher/expression_layout_field_delegate.h>
|
||||
#include "expression_field_delegate_app.h"
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class ExpressionLayoutFieldDelegate : public ::ExpressionLayoutFieldDelegate {
|
||||
public:
|
||||
bool expressionLayoutFieldShouldFinishEditing(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
|
||||
bool expressionLayoutFieldDidReceiveEvent(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
|
||||
bool expressionLayoutFieldDidFinishEditing(ExpressionLayoutField * expressionLayoutField, const char * text, Ion::Events::Event event) override;
|
||||
bool expressionLayoutFieldDidAbortEditing(ExpressionLayoutField * expressionLayoutField) override;
|
||||
void expressionLayoutFieldDidChangeSize(ExpressionLayoutField * expressionLayoutField) override;
|
||||
Toolbox * toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) override;
|
||||
private:
|
||||
virtual ExpressionFieldDelegateApp * expressionFieldDelegateApp() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -53,7 +53,7 @@ void FunctionApp::Snapshot::reset() {
|
||||
}
|
||||
|
||||
FunctionApp::FunctionApp(Container * container, Snapshot * snapshot, ViewController * rootViewController) :
|
||||
TextFieldDelegateApp(container, snapshot, rootViewController)
|
||||
ExpressionFieldDelegateApp(container, snapshot, rootViewController)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ void FunctionApp::willBecomeInactive() {
|
||||
m_modalViewController.dismissModalViewController();
|
||||
}
|
||||
if (inputViewController()->isDisplayingModal()) {
|
||||
inputViewController()->abortTextFieldEditionAndDismiss();
|
||||
inputViewController()->abortEditionAndDismiss();
|
||||
}
|
||||
::App::willBecomeInactive();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define SHARED_FUNCTION_APP_H
|
||||
|
||||
#include <poincare.h>
|
||||
#include "text_field_delegate_app.h"
|
||||
#include "expression_field_delegate_app.h"
|
||||
#include "curve_view_cursor.h"
|
||||
#include "interval.h"
|
||||
|
||||
@@ -10,7 +10,7 @@ class AppsContainer;
|
||||
|
||||
namespace Shared {
|
||||
|
||||
class FunctionApp : public TextFieldDelegateApp {
|
||||
class FunctionApp : public ExpressionFieldDelegateApp {
|
||||
public:
|
||||
class Snapshot : public ::App::Snapshot, public TabViewDataSource {
|
||||
public:
|
||||
|
||||
@@ -11,8 +11,8 @@ FunctionExpressionCell::FunctionExpressionCell() :
|
||||
{
|
||||
}
|
||||
|
||||
void FunctionExpressionCell::setExpression(ExpressionLayout * expressionLayout) {
|
||||
m_expressionView.setExpression(expressionLayout);
|
||||
void FunctionExpressionCell::setExpressionLayout(ExpressionLayout * expressionLayout) {
|
||||
m_expressionView.setExpressionLayout(expressionLayout);
|
||||
}
|
||||
|
||||
void FunctionExpressionCell::setTextColor(KDColor textColor) {
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Shared {
|
||||
class FunctionExpressionCell : public EvenOddCell {
|
||||
public:
|
||||
FunctionExpressionCell();
|
||||
void setExpression(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setTextColor(KDColor color);
|
||||
void setEven(bool even) override;
|
||||
void setHighlighted(bool highlight) override;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "sum_graph_controller.h"
|
||||
#include "../apps_container.h"
|
||||
#include <poincare/layout_engine.h>
|
||||
#include "../../poincare/src/layout/condensed_sum_layout.h"
|
||||
#include "../../poincare/src/layout/string_layout.h"
|
||||
#include "../../poincare/src/layout/horizontal_layout.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
@@ -145,7 +144,7 @@ bool SumGraphController::textFieldDidFinishEditing(TextField * textField, const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SumGraphController::textFieldDidAbortEditing(TextField * textField, const char * text) {
|
||||
bool SumGraphController::textFieldDidAbortEditing(TextField * textField) {
|
||||
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits)];
|
||||
double parameter = NAN;
|
||||
switch(m_step) {
|
||||
@@ -245,28 +244,35 @@ void SumGraphController::LegendView::setSumSymbol(Step step, double start, doubl
|
||||
}
|
||||
const char sigma[] = {' ', m_sumSymbol};
|
||||
if (step == Step::FirstParameter) {
|
||||
m_sumLayout = new StringLayout(sigma, sizeof(sigma));
|
||||
m_sumLayout = LayoutEngine::createStringLayout(sigma, sizeof(sigma));
|
||||
} else if (step == Step::SecondParameter) {
|
||||
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits)];
|
||||
PrintFloat::convertFloatToText<double>(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits, PrintFloat::Mode::Decimal);
|
||||
m_sumLayout = new CondensedSumLayout(new StringLayout(sigma, sizeof(sigma)), new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small), nullptr);
|
||||
m_sumLayout = new CondensedSumLayout(
|
||||
LayoutEngine::createStringLayout(sigma, sizeof(sigma)),
|
||||
LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small),
|
||||
new EmptyLayout(EmptyLayout::Color::Yellow, false, KDText::FontSize::Small, false),
|
||||
false);
|
||||
} else {
|
||||
char buffer[2+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
|
||||
PrintFloat::convertFloatToText<double>(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, PrintFloat::Mode::Decimal);
|
||||
ExpressionLayout * start = new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small);
|
||||
ExpressionLayout * start = LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small);
|
||||
PrintFloat::convertFloatToText<double>(end, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, PrintFloat::Mode::Decimal);
|
||||
ExpressionLayout * end = new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small);
|
||||
m_sumLayout = new CondensedSumLayout(new StringLayout(sigma, sizeof(sigma)), start, end);
|
||||
|
||||
ExpressionLayout * end = LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small);
|
||||
m_sumLayout = new CondensedSumLayout(
|
||||
LayoutEngine::createStringLayout(sigma, sizeof(sigma)),
|
||||
start,
|
||||
end,
|
||||
false);
|
||||
ExpressionLayout * childrenLayouts[3];
|
||||
strlcpy(buffer, "= ", 3);
|
||||
PrintFloat::convertFloatToText<double>(result, buffer+2, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
|
||||
childrenLayouts[2] = new StringLayout(buffer, strlen(buffer), KDText::FontSize::Small);
|
||||
childrenLayouts[2] = LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small);
|
||||
childrenLayouts[1] = functionLayout;
|
||||
childrenLayouts[0] = m_sumLayout;
|
||||
m_sumLayout = new HorizontalLayout(childrenLayouts, 3);
|
||||
m_sumLayout = new HorizontalLayout(childrenLayouts, 3, false);
|
||||
}
|
||||
m_sum.setExpression(m_sumLayout);
|
||||
m_sum.setExpressionLayout(m_sumLayout);
|
||||
if (step == Step::Result) {
|
||||
m_sum.setAlignment(0.5f, 0.5f);
|
||||
} else {
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
void setFunction(Function * function);
|
||||
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
|
||||
bool textFieldDidAbortEditing(TextField * textField, const char * text) override;
|
||||
bool textFieldDidAbortEditing(TextField * textField) override;
|
||||
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
|
||||
protected:
|
||||
virtual bool moveCursorHorizontallyToPosition(double position);
|
||||
|
||||
@@ -93,7 +93,7 @@ bool TextFieldDelegateApp::textFieldDidReceiveEvent(TextField * textField, Ion::
|
||||
}
|
||||
AppsContainer * appsContainer = (AppsContainer *)textField->app()->container();
|
||||
VariableBoxController * variableBoxController = appsContainer->variableBoxController();
|
||||
variableBoxController->setTextFieldCaller(textField);
|
||||
variableBoxController->setSender(textField);
|
||||
textField->app()->displayModalViewController(variableBoxController, 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin);
|
||||
return true;
|
||||
}
|
||||
@@ -108,7 +108,9 @@ bool TextFieldDelegateApp::textFieldDidReceiveEvent(TextField * textField, Ion::
|
||||
}
|
||||
|
||||
Toolbox * TextFieldDelegateApp::toolboxForTextInput(TextInput * textInput) {
|
||||
return container()->mathToolbox();
|
||||
Toolbox * toolbox = container()->mathToolbox();
|
||||
toolbox->setSender(textInput);
|
||||
return toolbox;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,36 +1,62 @@
|
||||
#include "toolbox_helpers.h"
|
||||
#include <ion/charset.h>
|
||||
#include <apps/i18n.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
namespace Shared {
|
||||
namespace ToolboxHelpers {
|
||||
|
||||
int CursorIndexInCommand(const char * text) {
|
||||
for (size_t i = 0; i < strlen(text); i++) {
|
||||
int CursorIndexInCommandText(const char * text) {
|
||||
size_t textLength = strlen(text);
|
||||
for (size_t i = 0; i < textLength; i++) {
|
||||
if (text[i] == '(' || text[i] == '\'') {
|
||||
return i + 1;
|
||||
}
|
||||
if (text[i] == ']') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return strlen(text);
|
||||
return textLength;
|
||||
}
|
||||
|
||||
void TextToInsertForCommandMessage(I18n::Message message, char * buffer) {
|
||||
const char * messageText = I18n::translate(message);
|
||||
TextToInsertForCommandText(messageText, buffer);
|
||||
void TextToInsertForCommandMessage(I18n::Message message, char * buffer, int bufferSize, bool replaceArgsWithEmptyChar) {
|
||||
TextToInsertForCommandText(I18n::translate(message), buffer, bufferSize, replaceArgsWithEmptyChar);
|
||||
}
|
||||
|
||||
void TextToInsertForCommandText(const char * command, char * buffer) {
|
||||
void TextToInsertForCommandText(const char * command, char * buffer, int bufferSize, bool replaceArgsWithEmptyChar) {
|
||||
int currentNewTextIndex = 0;
|
||||
int numberOfOpenParentheses = 0;
|
||||
int numberOfOpenBrackets = 0;
|
||||
bool insideQuote = false;
|
||||
bool argumentAlreadyReplaced = false;
|
||||
size_t commandLength = strlen(command);
|
||||
for (size_t i = 0; i < commandLength; i++) {
|
||||
if (command[i] == ')') {
|
||||
numberOfOpenParentheses--;
|
||||
}
|
||||
if (command[i] == ']') {
|
||||
numberOfOpenBrackets--;
|
||||
}
|
||||
if ((numberOfOpenBrackets == 0 || command[i] == ',') && (!insideQuote || command[i] == '\'')) {
|
||||
if (((numberOfOpenParentheses == 0 && numberOfOpenBrackets == 0)
|
||||
|| command[i] == ','
|
||||
|| (numberOfOpenBrackets > 0 && (command[i] == ',' || command[i] == '[' || command[i] == ']')))
|
||||
&& (!insideQuote || command[i] == '\'')) {
|
||||
assert(currentNewTextIndex < bufferSize);
|
||||
if (argumentAlreadyReplaced) {
|
||||
argumentAlreadyReplaced = false;
|
||||
}
|
||||
buffer[currentNewTextIndex++] = command[i];
|
||||
} else {
|
||||
if (replaceArgsWithEmptyChar && !argumentAlreadyReplaced) {
|
||||
buffer[currentNewTextIndex++] = Ion::Charset::Empty;
|
||||
argumentAlreadyReplaced = true;
|
||||
}
|
||||
}
|
||||
if (command[i] == '(') {
|
||||
numberOfOpenParentheses++;
|
||||
}
|
||||
if (command[i] == '[') {
|
||||
numberOfOpenBrackets++;
|
||||
}
|
||||
if (command[i] == '\'') {
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
namespace Shared {
|
||||
namespace ToolboxHelpers {
|
||||
|
||||
int CursorIndexInCommand(const char * text);
|
||||
/* Returns the index of the cursor position in a Command, which is the smallest
|
||||
int CursorIndexInCommandText(const char * text);
|
||||
/* Returns the index of the cursor position in a command, which is the smallest
|
||||
* index between :
|
||||
* - After the first open parenthesis
|
||||
* - The end of the text */
|
||||
|
||||
|
||||
void TextToInsertForCommandMessage(I18n::Message message, char * buffer);
|
||||
void TextToInsertForCommandText(const char * command, char * buffer);
|
||||
void TextToInsertForCommandMessage(I18n::Message message, char * buffer, int bufferSize, bool replaceArgsWithEmptyChar = false);
|
||||
void TextToInsertForCommandText(const char * command, char * buffer, int bufferSize, bool replaceArgsWithEmptyChar = false);
|
||||
/* Removes the arguments from a command:
|
||||
* - Removes text between parentheses, except commas */
|
||||
* - Removes text between parentheses or brackets, except commas */
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ ComplexNumber = "Komplexen Zahlen"
|
||||
Probability = "Kombinatorik"
|
||||
Arithmetic = "Arithmetisch"
|
||||
Matrices = "Matrizen"
|
||||
NewMatrix = "Neue Matrix"
|
||||
Lists = "Listen"
|
||||
HyperbolicTrigonometry = "Hyperbelfunktionen"
|
||||
Fluctuation = "Konfidenzintervall"
|
||||
|
||||
@@ -7,6 +7,7 @@ ComplexNumber = "Complex numbers"
|
||||
Probability = "Combinatorics"
|
||||
Arithmetic = "Arithmetic"
|
||||
Matrices = "Matrix"
|
||||
NewMatrix = "New matrix"
|
||||
Lists = "List"
|
||||
HyperbolicTrigonometry = "Hyperbolic trigonometry"
|
||||
Fluctuation = "Prediction Interval"
|
||||
|
||||
@@ -7,6 +7,7 @@ ComplexNumber = "Numeros complejos"
|
||||
Probability = "Combinatoria"
|
||||
Arithmetic = "Aritmetica"
|
||||
Matrices = "Matriz"
|
||||
NewMatrix = "Nueva matriz"
|
||||
Lists = "Listas"
|
||||
HyperbolicTrigonometry = "Trigonometria hiperbolica"
|
||||
Fluctuation = "Interval de prediccion"
|
||||
|
||||
@@ -7,6 +7,7 @@ ComplexNumber = "Nombres complexes"
|
||||
Probability = "Denombrement"
|
||||
Arithmetic = "Arithmetique"
|
||||
Matrices = "Matrices"
|
||||
NewMatrix = "Nouvelle matrice"
|
||||
Lists = "Listes"
|
||||
HyperbolicTrigonometry = "Trigonometrie hyperbolique"
|
||||
Fluctuation = "Intervalle fluctuation"
|
||||
|
||||
@@ -7,6 +7,7 @@ ComplexNumber = "Numeros complexos"
|
||||
Probability = "Combinatoria"
|
||||
Arithmetic = "Aritmetica"
|
||||
Matrices = "Matrizes"
|
||||
NewMatrix = "Nova matriz"
|
||||
Lists = "Listas"
|
||||
HyperbolicTrigonometry = "Funcoes hiperbolicas"
|
||||
Fluctuation = "Intervalo de confianca"
|
||||
|
||||
@@ -10,7 +10,7 @@ using namespace Poincare;
|
||||
VariableBoxController::ContentViewController::ContentViewController(Responder * parentResponder, GlobalContext * context) :
|
||||
ViewController(parentResponder),
|
||||
m_context(context),
|
||||
m_textFieldCaller(nullptr),
|
||||
m_sender(nullptr),
|
||||
m_firstSelectedRow(0),
|
||||
m_previousSelectedRow(0),
|
||||
m_currentPage(Page::RootMenu),
|
||||
@@ -20,14 +20,13 @@ VariableBoxController::ContentViewController::ContentViewController(Responder *
|
||||
m_selectableTableView.setShowsIndicators(false);
|
||||
}
|
||||
|
||||
const char * VariableBoxController::ContentViewController::title() {
|
||||
return I18n::translate(I18n::Message::Variables);
|
||||
}
|
||||
|
||||
View * VariableBoxController::ContentViewController::view() {
|
||||
return &m_selectableTableView;
|
||||
}
|
||||
|
||||
const char * VariableBoxController::ContentViewController::title() {
|
||||
return I18n::translate(I18n::Message::Variables);
|
||||
}
|
||||
void VariableBoxController::ContentViewController::didBecomeFirstResponder() {
|
||||
m_selectableTableView.reloadData();
|
||||
m_selectableTableView.scrollToCell(0,0);
|
||||
@@ -67,7 +66,7 @@ bool VariableBoxController::ContentViewController::handleEvent(Ion::Events::Even
|
||||
char label[3];
|
||||
putLabelAtIndexInBuffer(selectedRow(), label);
|
||||
const char * editedText = label;
|
||||
m_textFieldCaller->handleEventWithText(editedText);
|
||||
m_sender->handleEventWithText(editedText);
|
||||
#if MATRIX_VARIABLES
|
||||
m_selectableTableView.deselectTable();
|
||||
m_currentPage = Page::RootMenu;
|
||||
@@ -198,34 +197,21 @@ int VariableBoxController::ContentViewController::typeAtLocation(int i, int j) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Expression * VariableBoxController::ContentViewController::expressionForIndex(int index) {
|
||||
if (m_currentPage == Page::Scalar) {
|
||||
const Symbol symbol = Symbol('A'+index);
|
||||
return m_context->expressionForSymbol(&symbol);
|
||||
}
|
||||
if (m_currentPage == Page::Matrix) {
|
||||
const Symbol symbol = Symbol::matrixSymbol('0'+(char)index);
|
||||
return m_context->expressionForSymbol(&symbol);
|
||||
}
|
||||
#if LIST_VARIABLES
|
||||
if (m_currentPage == Page::List) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
void VariableBoxController::ContentViewController::reloadData() {
|
||||
m_selectableTableView.reloadData();
|
||||
}
|
||||
|
||||
ExpressionLayout * VariableBoxController::ContentViewController::expressionLayoutForIndex(int index) {
|
||||
if (m_currentPage == Page::Matrix) {
|
||||
const Symbol symbol = Symbol::matrixSymbol('0'+(char)index);
|
||||
return m_context->expressionLayoutForSymbol(&symbol);
|
||||
}
|
||||
#if LIST_VARIABLES
|
||||
if (m_currentPage == Page::List) {
|
||||
return nullptr;
|
||||
}
|
||||
void VariableBoxController::ContentViewController::resetPage() {
|
||||
#if MATRIX_VARIABLES
|
||||
m_currentPage = Page::RootMenu;
|
||||
#else
|
||||
m_currentPage = Page::Scalar;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::viewDidDisappear() {
|
||||
m_selectableTableView.deselectTable();
|
||||
ViewController::viewDidDisappear();
|
||||
}
|
||||
|
||||
VariableBoxController::ContentViewController::Page VariableBoxController::ContentViewController::pageAtIndex(int index) {
|
||||
@@ -266,25 +252,34 @@ I18n::Message VariableBoxController::ContentViewController::nodeLabelAtIndex(int
|
||||
return labels[index];
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::setTextFieldCaller(TextField * textField) {
|
||||
m_textFieldCaller = textField;
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::reloadData() {
|
||||
m_selectableTableView.reloadData();
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::resetPage() {
|
||||
#if MATRIX_VARIABLES
|
||||
m_currentPage = Page::RootMenu;
|
||||
#else
|
||||
m_currentPage = Page::Scalar;
|
||||
const Expression * VariableBoxController::ContentViewController::expressionForIndex(int index) {
|
||||
if (m_currentPage == Page::Scalar) {
|
||||
const Symbol symbol = Symbol('A'+index);
|
||||
return m_context->expressionForSymbol(&symbol);
|
||||
}
|
||||
if (m_currentPage == Page::Matrix) {
|
||||
const Symbol symbol = Symbol::matrixSymbol('0'+(char)index);
|
||||
return m_context->expressionForSymbol(&symbol);
|
||||
}
|
||||
#if LIST_VARIABLES
|
||||
if (m_currentPage == Page::List) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void VariableBoxController::ContentViewController::viewDidDisappear() {
|
||||
m_selectableTableView.deselectTable();
|
||||
ViewController::viewDidDisappear();
|
||||
ExpressionLayout * VariableBoxController::ContentViewController::expressionLayoutForIndex(int index) {
|
||||
if (m_currentPage == Page::Matrix) {
|
||||
const Symbol symbol = Symbol::matrixSymbol('0'+(char)index);
|
||||
return m_context->expressionLayoutForSymbol(&symbol);
|
||||
}
|
||||
#if LIST_VARIABLES
|
||||
if (m_currentPage == Page::List) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VariableBoxController::VariableBoxController(GlobalContext * context) :
|
||||
@@ -297,8 +292,8 @@ void VariableBoxController::didBecomeFirstResponder() {
|
||||
app()->setFirstResponder(&m_contentViewController);
|
||||
}
|
||||
|
||||
void VariableBoxController::setTextFieldCaller(TextField * textField) {
|
||||
m_contentViewController.setTextFieldCaller(textField);
|
||||
void VariableBoxController::setSender(Responder * sender) {
|
||||
m_contentViewController.setSender(sender);
|
||||
}
|
||||
|
||||
void VariableBoxController::viewWillAppear() {
|
||||
|
||||
@@ -12,7 +12,7 @@ class VariableBoxController : public StackViewController {
|
||||
public:
|
||||
VariableBoxController(Poincare::GlobalContext * context);
|
||||
void didBecomeFirstResponder() override;
|
||||
void setTextFieldCaller(TextField * textField);
|
||||
void setSender(Responder * sender);
|
||||
void viewWillAppear() override;
|
||||
void viewDidDisappear() override;
|
||||
private:
|
||||
@@ -31,7 +31,7 @@ private:
|
||||
KDCoordinate cumulatedHeightFromIndex(int j) override;
|
||||
int indexFromCumulatedHeight(KDCoordinate offsetY) override;
|
||||
int typeAtLocation(int i, int j) override;
|
||||
void setTextFieldCaller(TextField * textField);
|
||||
void setSender(Responder * responder) { m_sender = responder; }
|
||||
void reloadData();
|
||||
void resetPage();
|
||||
void viewDidDisappear() override;
|
||||
@@ -56,9 +56,8 @@ private:
|
||||
I18n::Message nodeLabelAtIndex(int index);
|
||||
const Poincare::Expression * expressionForIndex(int index);
|
||||
Poincare::ExpressionLayout * expressionLayoutForIndex(int index);
|
||||
|
||||
Poincare::GlobalContext * m_context;
|
||||
TextField * m_textFieldCaller;
|
||||
Responder * m_sender;
|
||||
int m_firstSelectedRow;
|
||||
int m_previousSelectedRow;
|
||||
Page m_currentPage;
|
||||
|
||||
@@ -77,7 +77,7 @@ void VariableBoxLeafCell::setSubtitle(const char * text) {
|
||||
}
|
||||
|
||||
void VariableBoxLeafCell::setExpressionLayout(ExpressionLayout * expressionLayout) {
|
||||
m_expressionView.setExpression(expressionLayout);
|
||||
m_expressionView.setExpressionLayout(expressionLayout);
|
||||
}
|
||||
|
||||
void VariableBoxLeafCell::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
|
||||
@@ -13,6 +13,7 @@ objs += $(addprefix escher/src/,\
|
||||
dynamic_view_controller.o\
|
||||
editable_text_cell.o\
|
||||
ellipsis_view.o\
|
||||
expression_field.o\
|
||||
even_odd_cell.o\
|
||||
even_odd_cell_with_ellipsis.o\
|
||||
even_odd_buffer_text_cell.o\
|
||||
@@ -49,6 +50,8 @@ objs += $(addprefix escher/src/,\
|
||||
scroll_view_data_source.o\
|
||||
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\
|
||||
@@ -74,7 +77,6 @@ objs += $(addprefix escher/src/,\
|
||||
tiled_view.o\
|
||||
timer.o\
|
||||
toolbox.o\
|
||||
toolbox_message_tree.o\
|
||||
transparent_view.o\
|
||||
view.o\
|
||||
view_controller.o\
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <escher/clipboard.h>
|
||||
#include <escher/container.h>
|
||||
#include <escher/dynamic_view_controller.h>
|
||||
#include <escher/expression_field.h>
|
||||
#include <escher/editable_text_cell.h>
|
||||
#include <escher/ellipsis_view.h>
|
||||
#include <escher/even_odd_cell.h>
|
||||
@@ -52,6 +53,8 @@
|
||||
#include <escher/scroll_view_data_source.h>
|
||||
#include <escher/scroll_view_indicator.h>
|
||||
#include <escher/scrollable_view.h>
|
||||
#include <escher/expression_layout_field.h>
|
||||
#include <escher/expression_layout_field_delegate.h>
|
||||
#include <escher/selectable_table_view.h>
|
||||
#include <escher/selectable_table_view_data_source.h>
|
||||
#include <escher/selectable_table_view_delegate.h>
|
||||
|
||||
@@ -10,7 +10,7 @@ public:
|
||||
KDColor textColor = KDColorBlack, KDColor backgroundColor = KDColorWhite);
|
||||
void setEven(bool even) override;
|
||||
void setHighlighted(bool highlight) override;
|
||||
void setExpression(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setBackgroundColor(KDColor backgroundColor);
|
||||
void setTextColor(KDColor textColor);
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
|
||||
48
escher/include/escher/expression_field.h
Normal file
48
escher/include/escher/expression_field.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef ESCHER_EXPRESSION_FIELD_H
|
||||
#define ESCHER_EXPRESSION_FIELD_H
|
||||
|
||||
#include <escher/expression_layout_field.h>
|
||||
#include <escher/expression_layout_field_delegate.h>
|
||||
#include <escher/text_field.h>
|
||||
#include <escher/text_field_delegate.h>
|
||||
#include <poincare/expression_layout.h>
|
||||
|
||||
class ExpressionField : public Responder, public View {
|
||||
public:
|
||||
ExpressionField(Responder * parentResponder, char * textBuffer, int textBufferLength, Poincare::ExpressionLayout * layout, TextFieldDelegate * textFieldDelegate, ExpressionLayoutFieldDelegate * expressionLayoutFieldDelegate);
|
||||
|
||||
void setEditing(bool isEditing, bool reinitDraftBuffer = true);
|
||||
bool isEditing() const;
|
||||
const char * text();
|
||||
void setText(const char * text);
|
||||
void insertText(const char * text);
|
||||
void reload();
|
||||
bool editionIsInTextField() const;
|
||||
bool isEmpty() const;
|
||||
bool heightIsMaximal() const;
|
||||
bool handleEventWithText(const char * text, bool indentation = false) override;
|
||||
|
||||
/* View */
|
||||
int numberOfSubviews() const override { return 1; }
|
||||
View * subviewAtIndex(int index) override;
|
||||
void layoutSubviews() override;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
|
||||
/* Responder */
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
|
||||
private:
|
||||
static constexpr KDCoordinate k_textFieldHeight = 37;
|
||||
static constexpr KDCoordinate k_horizontalMargin = 5;
|
||||
static constexpr KDCoordinate k_verticalMargin = 5;
|
||||
constexpr static int k_separatorThickness = 1;
|
||||
KDCoordinate inputViewHeight() const;
|
||||
KDCoordinate maximalHeight() const;
|
||||
TextField m_textField;
|
||||
ExpressionLayoutField m_expressionLayoutField;
|
||||
char * m_textBuffer;
|
||||
int m_textBufferLength;
|
||||
};
|
||||
|
||||
#endif
|
||||
80
escher/include/escher/expression_layout_field.h
Normal file
80
escher/include/escher/expression_layout_field.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef ESCHER_EXPRESSION_LAYOUT_FIELD_H
|
||||
#define ESCHER_EXPRESSION_LAYOUT_FIELD_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; }
|
||||
bool isEditing() const;
|
||||
void setEditing(bool isEditing);
|
||||
void clearLayout();
|
||||
void scrollToCursor();
|
||||
void reload();
|
||||
bool hasText() const;
|
||||
void writeTextInBuffer(char * buffer, int bufferLength);
|
||||
bool handleEventWithText(const char * text, bool indentation = false) override;
|
||||
Poincare::ExpressionLayout * expressionLayout();
|
||||
char XNTChar();
|
||||
void setBackgroundColor(KDColor c) override;
|
||||
|
||||
/* Responder */
|
||||
Toolbox * toolbox() override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
|
||||
bool expressionLayoutFieldShouldFinishEditing(Ion::Events::Event event);
|
||||
|
||||
void insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout);
|
||||
void insertLayoutFromTextAtCursor(const char * text);
|
||||
|
||||
/* View */
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
|
||||
protected:
|
||||
virtual bool privateHandleEvent(Ion::Events::Event event);
|
||||
bool privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout);
|
||||
private:
|
||||
void scrollRightOfLayout(Poincare::ExpressionLayout * layout);
|
||||
void scrollToBaselinedRect(KDRect rect, KDCoordinate baseline);
|
||||
|
||||
class ContentView : public View {
|
||||
public:
|
||||
ContentView(Poincare::ExpressionLayout * expressionLayout);
|
||||
bool isEditing() const { return m_isEditing; }
|
||||
void setEditing(bool isEditing);
|
||||
void setBackgroundColor(KDColor c);
|
||||
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; }
|
||||
void clearLayout();
|
||||
/* 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;
|
||||
};
|
||||
|
||||
#endif
|
||||
19
escher/include/escher/expression_layout_field_delegate.h
Normal file
19
escher/include/escher/expression_layout_field_delegate.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef ESCHER_EXPRESSION_LAYOUT_FIELD_DELEGATE_H
|
||||
#define ESCHER_EXPRESSION_LAYOUT_FIELD_DELEGATE_H
|
||||
|
||||
#include <escher/toolbox.h>
|
||||
#include <ion/events.h>
|
||||
|
||||
class ExpressionLayoutField;
|
||||
|
||||
class ExpressionLayoutFieldDelegate {
|
||||
public:
|
||||
virtual bool expressionLayoutFieldShouldFinishEditing(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) = 0;
|
||||
virtual bool expressionLayoutFieldDidReceiveEvent(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) = 0;
|
||||
virtual bool expressionLayoutFieldDidFinishEditing(ExpressionLayoutField * expressionLayoutField, const char * text, Ion::Events::Event event) { return false; }
|
||||
virtual bool expressionLayoutFieldDidAbortEditing(ExpressionLayoutField * expressionLayoutField) { return false; }
|
||||
virtual void expressionLayoutFieldDidChangeSize(ExpressionLayoutField * expressionLayoutField) {}
|
||||
virtual Toolbox * toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -9,7 +9,7 @@ public:
|
||||
ExpressionTableCell(Layout layout = Layout::Horizontal);
|
||||
View * labelView() const override;
|
||||
void setHighlighted(bool highlight) override;
|
||||
void setExpression(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
|
||||
private:
|
||||
ExpressionView m_labelExpressionView;
|
||||
};
|
||||
|
||||
@@ -16,12 +16,14 @@ public:
|
||||
ExpressionView(float horizontalAlignment = 0.0f, float verticalAlignment = 0.5f,
|
||||
KDColor textColor = KDColorBlack, KDColor backgroundColor = KDColorWhite);
|
||||
Poincare::ExpressionLayout * expressionLayout() const;
|
||||
void setExpression(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
void setBackgroundColor(KDColor backgroundColor);
|
||||
void setTextColor(KDColor textColor);
|
||||
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
|
||||
|
||||
@@ -1,53 +1,64 @@
|
||||
#ifndef ESCHER_INPUT_VIEW_CONTROLLER_H
|
||||
#define ESCHER_INPUT_VIEW_CONTROLLER_H
|
||||
|
||||
#include <escher/expression_field.h>
|
||||
#include <escher/expression_layout_field_delegate.h>
|
||||
#include <escher/modal_view_controller.h>
|
||||
#include <escher/invocation.h>
|
||||
#include <escher/text_field.h>
|
||||
#include <escher/text_field_delegate.h>
|
||||
|
||||
class InputViewController : public ModalViewController, TextFieldDelegate {
|
||||
/* TODO Implement a split view. Because we use a modal view, the main view is
|
||||
* redrawn underneath the modal view, which is visible and ugly. */
|
||||
|
||||
class InputViewController : public ModalViewController, TextFieldDelegate, ExpressionLayoutFieldDelegate {
|
||||
public:
|
||||
InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate);
|
||||
InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate, ExpressionLayoutFieldDelegate * expressionLayoutFieldDelegate);
|
||||
void edit(Responder * caller, Ion::Events::Event event, void * context, const char * initialText, Invocation::Action successAction, Invocation::Action failureAction);
|
||||
const char * textBody();
|
||||
void abortEditionAndDismiss();
|
||||
|
||||
/* TextFieldDelegate */
|
||||
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
|
||||
void abortTextFieldEditionAndDismiss();
|
||||
bool textFieldShouldFinishEditing(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;
|
||||
bool textFieldDidAbortEditing(TextField * textField) override;
|
||||
Toolbox * toolboxForTextInput(TextInput * textInput) override;
|
||||
|
||||
/* ExpressionLayoutFieldDelegate */
|
||||
bool expressionLayoutFieldShouldFinishEditing(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
|
||||
bool expressionLayoutFieldDidReceiveEvent(ExpressionLayoutField * expressionLayoutField, Ion::Events::Event event) override;
|
||||
bool expressionLayoutFieldDidFinishEditing(ExpressionLayoutField * expressionLayoutField, const char * text, Ion::Events::Event event) override;
|
||||
bool expressionLayoutFieldDidAbortEditing(ExpressionLayoutField * expressionLayoutField) override;
|
||||
void expressionLayoutFieldDidChangeSize(ExpressionLayoutField * expressionLayoutField) override;
|
||||
Toolbox * toolboxForExpressionLayoutField(ExpressionLayoutField * expressionLayoutField) override;
|
||||
|
||||
private:
|
||||
class TextFieldController : public ViewController {
|
||||
class ExpressionFieldController : public ViewController {
|
||||
public:
|
||||
TextFieldController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate);
|
||||
ExpressionFieldController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ExpressionLayoutFieldDelegate * expressionLayoutFieldDelegate);
|
||||
~ExpressionFieldController();
|
||||
ExpressionFieldController(const ExpressionFieldController& other) = delete;
|
||||
ExpressionFieldController(ExpressionFieldController&& other) = delete;
|
||||
ExpressionFieldController& operator=(const ExpressionFieldController& other) = delete;
|
||||
ExpressionFieldController& operator=(ExpressionFieldController&& other) = delete;
|
||||
void didBecomeFirstResponder() override;
|
||||
View * view() override;
|
||||
TextField * textField();
|
||||
View * view() override { return &m_expressionField; }
|
||||
ExpressionField * expressionField() { return &m_expressionField; }
|
||||
private:
|
||||
class ContentView : public Responder, public View {
|
||||
public:
|
||||
ContentView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate);
|
||||
void didBecomeFirstResponder() override;
|
||||
TextField * textField();
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
private:
|
||||
View * subviewAtIndex(int index) override;
|
||||
int numberOfSubviews() const override;
|
||||
void layoutSubviews() override;
|
||||
constexpr static KDCoordinate k_inputHeight = 37;
|
||||
constexpr static KDCoordinate k_separatorThickness = 1;
|
||||
constexpr static KDCoordinate k_textMargin = 5;
|
||||
TextField m_textField;
|
||||
char m_textBody[TextField::maxBufferSize()];
|
||||
};
|
||||
ContentView m_view;
|
||||
static constexpr int k_bufferLength = TextField::maxBufferSize();
|
||||
Poincare::ExpressionLayout * m_layout;
|
||||
char m_textBuffer[k_bufferLength];
|
||||
ExpressionField m_expressionField;
|
||||
};
|
||||
TextFieldController m_textFieldController;
|
||||
bool inputViewDidFinishEditing();
|
||||
bool inputViewDidAbortEditing();
|
||||
ExpressionFieldController m_expressionFieldController;
|
||||
Invocation m_successAction;
|
||||
Invocation m_failureAction;
|
||||
TextFieldDelegate * m_textFieldDelegate;
|
||||
ExpressionLayoutFieldDelegate * m_expressionLayoutFieldDelegate;
|
||||
bool m_inputViewHeightIsMaximal;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,7 +9,7 @@ public:
|
||||
MessageTableCellWithChevronAndExpression(I18n::Message message = (I18n::Message)0, KDText::FontSize size = KDText::FontSize::Small);
|
||||
View * subAccessoryView() const override;
|
||||
void setHighlighted(bool highlight) override;
|
||||
void setExpression(Poincare::ExpressionLayout * expressionLayout);
|
||||
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
|
||||
private:
|
||||
ExpressionView m_subtitleView;
|
||||
};
|
||||
|
||||
@@ -26,6 +26,9 @@ public:
|
||||
constexpr static KDCoordinate StoreRowHeight = 50;
|
||||
constexpr static KDCoordinate ToolboxRowHeight = 40;
|
||||
constexpr static KDCoordinate StackTitleHeight = 20;
|
||||
constexpr static KDCoordinate FractionAndConjugateHorizontalOverflow = 2;
|
||||
constexpr static KDCoordinate FractionAndConjugateHorizontalMargin = 2;
|
||||
constexpr static KDCoordinate MinimalBracketAndParenthesisHeight = 18;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,10 +13,13 @@ public:
|
||||
void didBecomeFirstResponder() override;
|
||||
void displayModalViewController(ViewController * vc, float verticalAlignment, float horizontalAlignment,
|
||||
KDCoordinate topMargin = 0, KDCoordinate leftMargin = 0, KDCoordinate bottomMargin = 0, KDCoordinate rightMargin = 0);
|
||||
void reloadModalViewController();
|
||||
void dismissModalViewController();
|
||||
bool isDisplayingModal();
|
||||
void viewWillAppear() override;
|
||||
void viewDidDisappear() override;
|
||||
protected:
|
||||
void reloadView();
|
||||
private:
|
||||
class ContentView : public View {
|
||||
public:
|
||||
@@ -29,8 +32,9 @@ private:
|
||||
KDCoordinate topMargin, KDCoordinate leftMargin, KDCoordinate bottomMargin, KDCoordinate rightMargin);
|
||||
void dismissModalView();
|
||||
bool isDisplayingModal() const;
|
||||
void reload();
|
||||
private:
|
||||
KDRect frame() const;
|
||||
KDRect modalViewFrame() const;
|
||||
View * m_regularView;
|
||||
View * m_currentModalView;
|
||||
bool m_isDisplayingModal;
|
||||
|
||||
@@ -10,6 +10,7 @@ class Responder {
|
||||
public:
|
||||
Responder(Responder * parentResponder);
|
||||
virtual bool handleEvent(Ion::Events::Event event); // Default implementation does nothing
|
||||
virtual bool handleEventWithText(const char * text, bool indentation = false) { return false; }
|
||||
virtual void didBecomeFirstResponder();
|
||||
virtual void willResignFirstResponder();
|
||||
virtual void didEnterResponderChain(Responder * previousFirstResponder);
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
bool showsIndicators() const { return m_showsIndicators; }
|
||||
void setColorsBackground(bool c) { m_colorsBackground = c; }
|
||||
bool colorsBackground() const { return m_colorsBackground; }
|
||||
void setBackgroundColor(KDColor c) { m_backgroundColor = c; }
|
||||
virtual void setBackgroundColor(KDColor c) { m_backgroundColor = c; }
|
||||
KDColor backgroundColor() const { return m_backgroundColor; }
|
||||
|
||||
ScrollViewIndicator * verticalScrollIndicator() { return &m_verticalScrollIndicator; }
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#ifndef ESCHER_SCROLLABLE_VIEW_H
|
||||
#define ESCHER_SCROLLABLE_VIEW_H
|
||||
|
||||
#include <escher/scroll_view.h>
|
||||
#include <escher/palette.h>
|
||||
#include <escher/responder.h>
|
||||
#include <escher/scroll_view.h>
|
||||
|
||||
class ScrollableView : public Responder, public ScrollView {
|
||||
public:
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
class TextCursorView : public View {
|
||||
public:
|
||||
using View::View;
|
||||
KDRect frame() const { return m_frame; }
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
constexpr static KDCoordinate k_width = 1;
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
class TextField : public TextInput {
|
||||
public:
|
||||
TextField(Responder * parentResponder, char * textBuffer, char * draftTextBuffer, size_t textBufferSize,
|
||||
TextFieldDelegate * delegate = nullptr, bool hasTwoBuffers = true, KDText::FontSize size = KDText::FontSize::Large, float horizontalAlignment = 0.0f,
|
||||
float verticalAlignment = 0.5f, KDColor textColor = KDColorBlack, KDColor = KDColorWhite);
|
||||
TextFieldDelegate * delegate = nullptr, bool hasTwoBuffers = true, KDText::FontSize size = KDText::FontSize::Large,
|
||||
float horizontalAlignment = 0.0f, float verticalAlignment = 0.5f, KDColor textColor = KDColorBlack, KDColor backgroundColor = KDColorWhite);
|
||||
void setDelegate(TextFieldDelegate * delegate) { m_delegate = delegate; }
|
||||
void setDraftTextBuffer(char * draftTextBuffer);
|
||||
bool isEditing() const;
|
||||
|
||||
@@ -10,7 +10,7 @@ public:
|
||||
virtual bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) = 0;
|
||||
virtual bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) = 0;
|
||||
virtual bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) { return false; };
|
||||
virtual bool textFieldDidAbortEditing(TextField * textField, const char * text) {return false;};
|
||||
virtual bool textFieldDidAbortEditing(TextField * textField) {return false;};
|
||||
virtual bool textFieldDidHandleEvent(TextField * textField, bool returnValue, bool textHasChanged) { return returnValue; };
|
||||
};
|
||||
|
||||
|
||||
@@ -12,14 +12,12 @@ public:
|
||||
TextInput(Responder * parentResponder, View * contentView);
|
||||
Toolbox * toolbox() override;
|
||||
const char * text() const { return nonEditableContentView()->text(); }
|
||||
void setBackgroundColor(KDColor backgroundColor);
|
||||
KDColor backgroundColor() const { return nonEditableContentView()->backgroundColor(); }
|
||||
void setBackgroundColor(KDColor backgroundColor) override;
|
||||
void setTextColor(KDColor textColor);
|
||||
bool removeChar();
|
||||
size_t cursorLocation() const { return nonEditableContentView()->cursorLocation(); }
|
||||
bool setCursorLocation(int location);
|
||||
virtual void scrollToCursor();
|
||||
virtual bool handleEventWithText(const char * text, bool indenting = false) = 0;
|
||||
protected:
|
||||
class ContentView : public View {
|
||||
public:
|
||||
|
||||
@@ -8,12 +8,9 @@ namespace TextInputHelpers {
|
||||
int CursorIndexInCommand(const char * text);
|
||||
/* Returns the index of the cursor position in a Command, which is the smallest
|
||||
* index between :
|
||||
* - After the first open parenthesis/quote if the following element is
|
||||
* either a quote, a coma or a parenthesi
|
||||
* - The end of the text
|
||||
* - Special case: when the text preceding the parenthesis is 'random', the
|
||||
* cursor position is the end of the text. */
|
||||
constexpr static const char * k_random = "random";
|
||||
* - The first EmptyChar index (which is the position of the first argument)
|
||||
* - The first empty quote
|
||||
* - The end of the text */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
class Toolbox : public StackViewController, public ListViewDataSource, public SelectableTableViewDataSource {
|
||||
public:
|
||||
Toolbox(Responder * parentResponder, const char * title = 0);
|
||||
void setSender(Responder * sender);
|
||||
void setSender(Responder * sender) { m_sender = sender; }
|
||||
|
||||
// StackViewController
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
@@ -72,7 +72,7 @@ protected:
|
||||
bool handleEventForRow(Ion::Events::Event event, int selectedRow);
|
||||
bool selectSubMenu(ToolboxMessageTree * selectedMessageTree);
|
||||
bool returnToPreviousMenu();
|
||||
virtual Responder * sender();
|
||||
Responder * sender() { return m_sender; }
|
||||
virtual bool selectLeaf(ToolboxMessageTree * selectedMessageTree) = 0;
|
||||
virtual const ToolboxMessageTree * rootModel() = 0;
|
||||
virtual MessageTableCellWithMessage * leafCellAtIndex(int index) = 0;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define ESCHER_TOOLBOX_MESSAGE_TREE_H
|
||||
|
||||
#include <escher/message_tree.h>
|
||||
#include <poincare_layouts.h>
|
||||
|
||||
class ToolboxMessageTree : public MessageTree {
|
||||
public:
|
||||
@@ -12,9 +13,9 @@ public:
|
||||
m_insertedText(insertedText)
|
||||
{
|
||||
};
|
||||
const MessageTree * children(int index) const override;
|
||||
I18n::Message text() const;
|
||||
I18n::Message insertedText() const;
|
||||
const MessageTree * children(int index) const override { return &m_children[index]; }
|
||||
I18n::Message text() const { return m_text; }
|
||||
I18n::Message insertedText() const { return m_insertedText; }
|
||||
private:
|
||||
const ToolboxMessageTree * m_children;
|
||||
I18n::Message m_text;
|
||||
|
||||
@@ -19,8 +19,8 @@ void EvenOddExpressionCell::setEven(bool even) {
|
||||
m_expressionView.setBackgroundColor(backgroundColor());
|
||||
}
|
||||
|
||||
void EvenOddExpressionCell::setExpression(ExpressionLayout * expressionLayout) {
|
||||
m_expressionView.setExpression(expressionLayout);
|
||||
void EvenOddExpressionCell::setExpressionLayout(ExpressionLayout * expressionLayout) {
|
||||
m_expressionView.setExpressionLayout(expressionLayout);
|
||||
}
|
||||
|
||||
void EvenOddExpressionCell::setBackgroundColor(KDColor backgroundColor) {
|
||||
|
||||
131
escher/src/expression_field.cpp
Normal file
131
escher/src/expression_field.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
#include <escher/expression_field.h>
|
||||
#include <poincare/preferences.h>
|
||||
#include <assert.h>
|
||||
|
||||
ExpressionField::ExpressionField(Responder * parentResponder, char * textBuffer, int textBufferLength, Poincare::ExpressionLayout * layout, TextFieldDelegate * textFieldDelegate, ExpressionLayoutFieldDelegate * expressionLayoutFieldDelegate) :
|
||||
Responder(parentResponder),
|
||||
View(),
|
||||
m_textField(parentResponder, textBuffer, textBuffer, textBufferLength, textFieldDelegate, false, KDText::FontSize::Large, 0.0f, 0.5f, KDColorBlack, KDColorWhite),
|
||||
m_expressionLayoutField(parentResponder, layout, expressionLayoutFieldDelegate),
|
||||
m_textBuffer(textBuffer),
|
||||
m_textBufferLength(textBufferLength)
|
||||
{
|
||||
// Initialize text field
|
||||
m_textField.setMargins(0, k_horizontalMargin, 0, k_horizontalMargin);
|
||||
m_textField.setBackgroundColor(KDColorWhite);
|
||||
m_textField.setColorsBackground(true);
|
||||
// Initialize layout field
|
||||
m_expressionLayoutField.setMargins(k_verticalMargin, k_horizontalMargin, k_verticalMargin, k_horizontalMargin);
|
||||
m_expressionLayoutField.setBackgroundColor(KDColorWhite);
|
||||
m_expressionLayoutField.setColorsBackground(true);
|
||||
}
|
||||
|
||||
void ExpressionField::setEditing(bool isEditing, bool reinitDraftBuffer) {
|
||||
if (editionIsInTextField()) {
|
||||
m_textField.setEditing(isEditing, reinitDraftBuffer);
|
||||
} else {
|
||||
if (reinitDraftBuffer) {
|
||||
m_expressionLayoutField.clearLayout();
|
||||
}
|
||||
m_expressionLayoutField.setEditing(isEditing);
|
||||
}
|
||||
}
|
||||
|
||||
bool ExpressionField::isEditing() const {
|
||||
return editionIsInTextField() ? m_textField.isEditing() : m_expressionLayoutField.isEditing();
|
||||
}
|
||||
|
||||
const char * ExpressionField::text() {
|
||||
if (!editionIsInTextField()) {
|
||||
m_expressionLayoutField.writeTextInBuffer(m_textBuffer, m_textBufferLength);
|
||||
}
|
||||
return m_textBuffer;
|
||||
}
|
||||
|
||||
void ExpressionField::setText(const char * text) {
|
||||
if (editionIsInTextField()) {
|
||||
m_textField.setText(text);
|
||||
return;
|
||||
}
|
||||
m_expressionLayoutField.clearLayout();
|
||||
if (strlen(text) > 0) {
|
||||
m_expressionLayoutField.insertLayoutFromTextAtCursor(text);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionField::insertText(const char * text) {
|
||||
if (editionIsInTextField()) {
|
||||
m_textField.handleEventWithText(text);
|
||||
} else {
|
||||
m_expressionLayoutField.setEditing(true);
|
||||
m_expressionLayoutField.insertLayoutFromTextAtCursor(text);
|
||||
}
|
||||
}
|
||||
|
||||
View * ExpressionField::subviewAtIndex(int index) {
|
||||
assert(index == 0);
|
||||
if (editionIsInTextField()) {
|
||||
return &m_textField;
|
||||
}
|
||||
return &m_expressionLayoutField;
|
||||
}
|
||||
|
||||
void ExpressionField::layoutSubviews() {
|
||||
KDRect inputViewFrame(0, k_separatorThickness, bounds().width(), bounds().height() - k_separatorThickness);
|
||||
if (editionIsInTextField()) {
|
||||
m_textField.setFrame(inputViewFrame);
|
||||
m_expressionLayoutField.setFrame(KDRectZero);
|
||||
return;
|
||||
}
|
||||
m_expressionLayoutField.setFrame(inputViewFrame);
|
||||
m_textField.setFrame(KDRectZero);
|
||||
}
|
||||
|
||||
void ExpressionField::reload() {
|
||||
layoutSubviews();
|
||||
markRectAsDirty(bounds());
|
||||
}
|
||||
|
||||
void ExpressionField::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
// Draw the separator
|
||||
ctx->fillRect(KDRect(0, 0, bounds().width(), k_separatorThickness), Palette::GreyMiddle);
|
||||
}
|
||||
|
||||
bool ExpressionField::handleEvent(Ion::Events::Event event) {
|
||||
return editionIsInTextField() ? m_textField.handleEvent(event) : m_expressionLayoutField.handleEvent(event);
|
||||
}
|
||||
|
||||
KDSize ExpressionField::minimalSizeForOptimalDisplay() const {
|
||||
return KDSize(0, inputViewHeight());
|
||||
}
|
||||
|
||||
bool ExpressionField::editionIsInTextField() const {
|
||||
return Poincare::Preferences::sharedPreferences()->editionMode() == Poincare::Preferences::EditionMode::Edition1D;
|
||||
}
|
||||
|
||||
bool ExpressionField::isEmpty() const {
|
||||
return editionIsInTextField() ? (m_textField.draftTextLength() == 0) : !m_expressionLayoutField.hasText();
|
||||
}
|
||||
|
||||
bool ExpressionField::heightIsMaximal() const {
|
||||
return inputViewHeight() == k_separatorThickness + maximalHeight();
|
||||
}
|
||||
|
||||
bool ExpressionField::handleEventWithText(const char * text, bool indentation) {
|
||||
if (editionIsInTextField()) {
|
||||
return m_textField.handleEventWithText(text, indentation);
|
||||
} else {
|
||||
return m_expressionLayoutField.handleEventWithText(text, indentation);
|
||||
}
|
||||
}
|
||||
|
||||
KDCoordinate ExpressionField::inputViewHeight() const {
|
||||
return k_separatorThickness
|
||||
+ (editionIsInTextField() ? k_textFieldHeight :
|
||||
min(maximalHeight(),
|
||||
max(k_textFieldHeight, m_expressionLayoutField.minimalSizeForOptimalDisplay().height() + 2*k_verticalMargin )));
|
||||
}
|
||||
|
||||
KDCoordinate ExpressionField::maximalHeight() const {
|
||||
return 0.6*Ion::Display::Height;
|
||||
}
|
||||
334
escher/src/expression_layout_field.cpp
Normal file
334
escher/src/expression_layout_field.cpp
Normal file
@@ -0,0 +1,334 @@
|
||||
#include <escher/expression_layout_field.h>
|
||||
#include <apps/i18n.h>
|
||||
#include <escher/clipboard.h>
|
||||
#include <escher/text_field.h>
|
||||
#include <poincare/expression.h>
|
||||
#include <poincare/expression_layout_cursor.h>
|
||||
#include <poincare/src/layout/matrix_layout.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
ExpressionLayoutField::ExpressionLayoutField(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, ExpressionLayoutFieldDelegate * delegate) :
|
||||
ScrollableView(parentResponder, &m_contentView, this),
|
||||
m_contentView(expressionLayout),
|
||||
m_delegate(delegate)
|
||||
{
|
||||
}
|
||||
|
||||
bool ExpressionLayoutField::isEditing() const {
|
||||
return m_contentView.isEditing();
|
||||
}
|
||||
|
||||
void ExpressionLayoutField::setEditing(bool isEditing) {
|
||||
m_contentView.setEditing(isEditing);
|
||||
}
|
||||
|
||||
void ExpressionLayoutField::clearLayout() {
|
||||
m_contentView.clearLayout();
|
||||
}
|
||||
|
||||
void ExpressionLayoutField::scrollToCursor() {
|
||||
scrollToBaselinedRect(m_contentView.cursorRect(), m_contentView.cursor()->baseline());
|
||||
}
|
||||
|
||||
Toolbox * ExpressionLayoutField::toolbox() {
|
||||
if (m_delegate) {
|
||||
return m_delegate->toolboxForExpressionLayoutField(this);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ExpressionLayoutField::handleEvent(Ion::Events::Event event) {
|
||||
bool didHandleEvent = false;
|
||||
bool shouldRecomputeLayout = m_contentView.cursor()->showEmptyLayoutIfNeeded();
|
||||
bool moveEventChangedLayout = false;
|
||||
if (privateHandleMoveEvent(event, &moveEventChangedLayout)) {
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
shouldRecomputeLayout = shouldRecomputeLayout || moveEventChangedLayout;
|
||||
didHandleEvent = true;
|
||||
} else if (privateHandleEvent(event)) {
|
||||
shouldRecomputeLayout = true;
|
||||
didHandleEvent = true;
|
||||
}
|
||||
if (didHandleEvent) {
|
||||
shouldRecomputeLayout = m_contentView.cursor()->hideEmptyLayoutIfNeeded() || shouldRecomputeLayout;
|
||||
if (!shouldRecomputeLayout) {
|
||||
m_contentView.cursorPositionChanged();
|
||||
scrollToCursor();
|
||||
} else {
|
||||
reload();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
m_contentView.cursor()->hideEmptyLayoutIfNeeded();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ExpressionLayoutField::expressionLayoutFieldShouldFinishEditing(Ion::Events::Event event) {
|
||||
return m_delegate->expressionLayoutFieldShouldFinishEditing(this, event);
|
||||
}
|
||||
|
||||
KDSize ExpressionLayoutField::minimalSizeForOptimalDisplay() const {
|
||||
KDSize contentViewSize = m_contentView.minimalSizeForOptimalDisplay();
|
||||
return KDSize(contentViewSize.width(), contentViewSize.height());
|
||||
}
|
||||
|
||||
bool ExpressionLayoutField::privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout) {
|
||||
Poincare::ExpressionLayoutCursor result;
|
||||
if (event == Ion::Events::Left) {
|
||||
result = m_contentView.cursor()->cursorOnLeft(shouldRecomputeLayout);
|
||||
} else if (event == Ion::Events::Right) {
|
||||
result = m_contentView.cursor()->cursorOnRight(shouldRecomputeLayout);
|
||||
} else if (event == Ion::Events::Up) {
|
||||
result = m_contentView.cursor()->cursorAbove(shouldRecomputeLayout);
|
||||
} else if (event == Ion::Events::Down) {
|
||||
result = m_contentView.cursor()->cursorUnder(shouldRecomputeLayout);
|
||||
} else if (event == Ion::Events::ShiftLeft) {
|
||||
*shouldRecomputeLayout = true;
|
||||
if (m_contentView.cursor()->pointedExpressionLayout()->removeGreySquaresFromAllMatrixAncestors()) {
|
||||
*shouldRecomputeLayout = true;
|
||||
}
|
||||
result.setPointedExpressionLayout(m_contentView.expressionView()->expressionLayout());
|
||||
result.setPosition(Poincare::ExpressionLayoutCursor::Position::Left);
|
||||
} else if (event == Ion::Events::ShiftRight) {
|
||||
if (m_contentView.cursor()->pointedExpressionLayout()->removeGreySquaresFromAllMatrixAncestors()) {
|
||||
*shouldRecomputeLayout = true;
|
||||
}
|
||||
result.setPointedExpressionLayout(m_contentView.expressionView()->expressionLayout());
|
||||
result.setPosition(Poincare::ExpressionLayoutCursor::Position::Right);
|
||||
}
|
||||
if (result.isDefined()) {
|
||||
m_contentView.setCursor(result);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ExpressionLayoutField::privateHandleEvent(Ion::Events::Event event) {
|
||||
if (m_delegate && m_delegate->expressionLayoutFieldDidReceiveEvent(this, event)) {
|
||||
return true;
|
||||
}
|
||||
if (Responder::handleEvent(event)) {
|
||||
/* The only event Responder handles is 'Toolbox' displaying. In that case,
|
||||
* the ExpressionLayoutField is forced into editing mode. */
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (isEditing() && expressionLayoutFieldShouldFinishEditing(event)) {
|
||||
setEditing(false);
|
||||
int bufferSize = TextField::maxBufferSize();
|
||||
char buffer[bufferSize];
|
||||
m_contentView.expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize);
|
||||
if (m_delegate->expressionLayoutFieldDidFinishEditing(this, buffer, event)) {
|
||||
clearLayout();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if ((event == Ion::Events::OK || event == Ion::Events::EXE) && !isEditing()) {
|
||||
setEditing(true);
|
||||
m_contentView.cursor()->setPointedExpressionLayout(m_contentView.expressionView()->expressionLayout());
|
||||
m_contentView.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right);
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Back && isEditing()) {
|
||||
clearLayout();
|
||||
setEditing(false);
|
||||
m_delegate->expressionLayoutFieldDidAbortEditing(this);
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Division) {
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
m_contentView.cursor()->addFractionLayoutAndCollapseSiblings();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Exp) {
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
m_contentView.cursor()->addEmptyExponentialLayout();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Power) {
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
m_contentView.cursor()->addEmptyPowerLayout();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Sqrt) {
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
m_contentView.cursor()->addEmptySquareRootLayout();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Square) {
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
m_contentView.cursor()->addEmptySquarePowerLayout();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::EE) {
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
m_contentView.cursor()->addEmptyTenPowerLayout();
|
||||
return true;
|
||||
}
|
||||
if (event.hasText()) {
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
const char * textToInsert = event.text();
|
||||
if (textToInsert[1] == 0 && (textToInsert[0] == '[' || textToInsert[0] == ']')) {
|
||||
m_contentView.cursor()->addEmptyMatrixLayout();
|
||||
return true;
|
||||
}
|
||||
m_contentView.cursor()->insertText(textToInsert);
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Backspace) {
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
m_contentView.cursor()->performBackspace();
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Paste) {
|
||||
if (!isEditing()) {
|
||||
setEditing(true);
|
||||
}
|
||||
insertLayoutFromTextAtCursor(Clipboard::sharedClipboard()->storedText());
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Clear && isEditing()) {
|
||||
clearLayout();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ExpressionLayoutField::insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout) {
|
||||
if (layout == nullptr) {
|
||||
return;
|
||||
}
|
||||
m_contentView.cursor()->showEmptyLayoutIfNeeded();
|
||||
bool layoutWillBeMerged = layout->isHorizontal();
|
||||
Poincare::ExpressionLayout * lastMergedLayoutChild = layoutWillBeMerged ? layout->editableChild(layout->numberOfChildren()-1) : nullptr;
|
||||
m_contentView.cursor()->addLayoutAndMoveCursor(layout);
|
||||
if (pointedLayout != nullptr && (pointedLayout != layout || !layoutWillBeMerged)) {
|
||||
m_contentView.cursor()->setPointedExpressionLayout(pointedLayout);
|
||||
m_contentView.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right);
|
||||
} else if (!layoutWillBeMerged) {
|
||||
m_contentView.cursor()->setPointedExpressionLayout(layout->layoutToPointWhenInserting());
|
||||
m_contentView.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right);
|
||||
}
|
||||
m_contentView.cursor()->pointedExpressionLayout()->addGreySquaresToAllMatrixAncestors();
|
||||
m_contentView.cursor()->hideEmptyLayoutIfNeeded();
|
||||
reload();
|
||||
if (!layoutWillBeMerged) {
|
||||
scrollRightOfLayout(layout);
|
||||
} else {
|
||||
assert(lastMergedLayoutChild != nullptr);
|
||||
scrollRightOfLayout(lastMergedLayoutChild);
|
||||
}
|
||||
scrollToCursor();
|
||||
}
|
||||
|
||||
void ExpressionLayoutField::insertLayoutFromTextAtCursor(const char * text) {
|
||||
m_contentView.cursor()->showEmptyLayoutIfNeeded();
|
||||
Poincare::Expression * expression = Poincare::Expression::parse(text);
|
||||
if (expression != nullptr) {
|
||||
Poincare::ExpressionLayout * layout = expression->createLayout();
|
||||
delete expression;
|
||||
insertLayoutAtCursor(layout, layout);
|
||||
} else {
|
||||
m_contentView.cursor()->insertText(text);
|
||||
}
|
||||
m_contentView.cursor()->hideEmptyLayoutIfNeeded();
|
||||
reload();
|
||||
}
|
||||
|
||||
void ExpressionLayoutField::reload() {
|
||||
KDSize previousSize = minimalSizeForOptimalDisplay();
|
||||
m_contentView.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines();
|
||||
KDSize newSize = minimalSizeForOptimalDisplay();
|
||||
if (m_delegate && previousSize.height() != newSize.height()) {
|
||||
m_delegate->expressionLayoutFieldDidChangeSize(this);
|
||||
}
|
||||
m_contentView.cursorPositionChanged();
|
||||
scrollToCursor();
|
||||
markRectAsDirty(bounds());
|
||||
}
|
||||
|
||||
bool ExpressionLayoutField::hasText() const {
|
||||
return m_contentView.expressionView()->expressionLayout()->hasText();
|
||||
}
|
||||
|
||||
void ExpressionLayoutField::writeTextInBuffer(char * buffer, int bufferLength) {
|
||||
m_contentView.expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferLength);
|
||||
}
|
||||
|
||||
bool ExpressionLayoutField::handleEventWithText(const char * text, bool indentation) {
|
||||
Poincare::Expression * resultExpression = Poincare::Expression::parse(text);
|
||||
if (resultExpression == nullptr) {
|
||||
return false;
|
||||
}
|
||||
Poincare::ExpressionLayout * resultLayout = resultExpression->createLayout();
|
||||
delete resultExpression;
|
||||
// Find the pointed layout.
|
||||
Poincare::ExpressionLayout * pointedLayout = nullptr;
|
||||
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->isHorizontal()) {
|
||||
/* If the layout is horizontal, pick the first open parenthesis. For now,
|
||||
* all horizontal layouts in MathToolbox have parentheses. */
|
||||
for (int i = 0; i < resultLayout->numberOfChildren(); i++) {
|
||||
if (resultLayout->editableChild(i)->isLeftParenthesis()) {
|
||||
pointedLayout = resultLayout->editableChild(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Insert the layout. If pointedLayout is nullptr, the cursor will be on the
|
||||
* right of the inserted layout. */
|
||||
insertLayoutAtCursor(resultLayout, pointedLayout);
|
||||
return true;
|
||||
}
|
||||
|
||||
Poincare::ExpressionLayout * ExpressionLayoutField::expressionLayout() {
|
||||
return m_contentView.expressionView()->expressionLayout();
|
||||
}
|
||||
|
||||
char ExpressionLayoutField::XNTChar() {
|
||||
return m_contentView.cursor()->pointedExpressionLayout()->XNTChar();
|
||||
}
|
||||
|
||||
void ExpressionLayoutField::setBackgroundColor(KDColor c) {
|
||||
ScrollableView::setBackgroundColor(c);
|
||||
m_contentView.setBackgroundColor(c);
|
||||
}
|
||||
|
||||
void ExpressionLayoutField::scrollRightOfLayout(Poincare::ExpressionLayout * layout) {
|
||||
KDRect layoutRect(layout->absoluteOrigin().translatedBy(m_contentView.expressionView()->drawingOrigin()), layout->size());
|
||||
scrollToBaselinedRect(layoutRect, layout->baseline());
|
||||
}
|
||||
|
||||
void ExpressionLayoutField::scrollToBaselinedRect(KDRect rect, KDCoordinate baseline) {
|
||||
scrollToContentRect(rect, true);
|
||||
// Show the rect area around its baseline
|
||||
KDCoordinate underBaseline = rect.height() - baseline;
|
||||
KDCoordinate minAroundBaseline = min(baseline, underBaseline);
|
||||
minAroundBaseline = min(minAroundBaseline, bounds().height() / 2);
|
||||
KDRect balancedRect(rect.x(), rect.y() + baseline - minAroundBaseline, rect.width(), 2 * minAroundBaseline);
|
||||
scrollToContentRect(balancedRect, true);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user