Merge branch 'saisie-jolie' into master-merge-saisie-jolie

This commit is contained in:
Émilie Feral
2018-05-16 11:28:07 +02:00
243 changed files with 7672 additions and 1679 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View 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));
}
}

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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)
{
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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)
{
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 = "μ"

View File

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

View 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;
}
}

View 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

View 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);
}
}

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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] == '\'') {

View File

@@ -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 */
}
}

View File

@@ -7,6 +7,7 @@ ComplexNumber = "Komplexen Zahlen"
Probability = "Kombinatorik"
Arithmetic = "Arithmetisch"
Matrices = "Matrizen"
NewMatrix = "Neue Matrix"
Lists = "Listen"
HyperbolicTrigonometry = "Hyperbelfunktionen"
Fluctuation = "Konfidenzintervall"

View File

@@ -7,6 +7,7 @@ ComplexNumber = "Complex numbers"
Probability = "Combinatorics"
Arithmetic = "Arithmetic"
Matrices = "Matrix"
NewMatrix = "New matrix"
Lists = "List"
HyperbolicTrigonometry = "Hyperbolic trigonometry"
Fluctuation = "Prediction Interval"

View File

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

View File

@@ -7,6 +7,7 @@ ComplexNumber = "Nombres complexes"
Probability = "Denombrement"
Arithmetic = "Arithmetique"
Matrices = "Matrices"
NewMatrix = "Nouvelle matrice"
Lists = "Listes"
HyperbolicTrigonometry = "Trigonometrie hyperbolique"
Fluctuation = "Intervalle fluctuation"

View File

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

View File

@@ -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() {

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View 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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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;
}

View 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