Merge branch 'SaisieJolieRebase1201' into SaisieJolieMerge10Apr

Change-Id: I802dbb9f7c0eebf75a1b6cd21ddd194e89b53752
This commit is contained in:
Léa Saviot
2018-04-10 17:21:54 +02:00
212 changed files with 7429 additions and 1510 deletions

View File

@@ -6,13 +6,13 @@ app_objs += $(addprefix apps/calculation/,\
calculation.o\
calculation_store.o\
edit_expression_controller.o\
editable_expression_view.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),
EditableExpressionViewDelegateApp(container, snapshot, &m_editExpressionController),
m_historyController(&m_editExpressionController, snapshot->calculationStore()),
m_editExpressionController(&m_modalViewController, &m_historyController, snapshot->calculationStore())
{
@@ -85,6 +85,36 @@ bool App::textInputIsCorrect(const char * text) {
return true;
}
bool App::scrollableExpressionViewWithCursorDidReceiveEvent(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
if ((event == Ion::Events::Var || event == Ion::Events::XNT) && EditableExpressionViewDelegateApp::scrollableExpressionViewWithCursorDidReceiveEvent(scrollableExpressionViewWithCursor, event)) {
return true;
}
/* Here, we check that the expression entered by the user can be printed with
* less than k_printedExpressionLength characters. Otherwise, we prevent the
* user from adding this expression to the calculation store. */
if (scrollableExpressionViewWithCursor->isEditing() && scrollableExpressionViewWithCursor->scrollableExpressionViewWithCursorShouldFinishEditing(event)) {
int bufferLength = TextField::maxBufferSize();
char bufferForParsing[bufferLength];
Poincare::ExpressionLayout * expressionLayout = scrollableExpressionViewWithCursor->expressionViewWithCursor()->expressionView()->expressionLayout();
expressionLayout->writeTextInBuffer(bufferForParsing, bufferLength);
Expression * exp = Expression::parse(bufferForParsing);
if (exp == nullptr) {
scrollableExpressionViewWithCursor->app()->displayWarning(I18n::Message::SyntaxError);
return true;
}
char buffer[Calculation::k_printedExpressionSize];
int length = exp->writeTextInBuffer(buffer, sizeof(buffer));
delete exp;
/* if the buffer is totally full, it is VERY likely that writeTextInBuffer
* escaped before printing utterly the expression. */
if (length >= Calculation::k_printedExpressionSize-1) {
displayWarning(I18n::Message::SyntaxError);
return true;
}
}
return false;
}
const char * App::XNT() {
return "x";
}

View File

@@ -9,7 +9,7 @@
namespace Calculation {
class App : public Shared::TextFieldDelegateApp {
class App : public Shared::EditableExpressionViewDelegateApp {
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 scrollableExpressionViewWithCursorDidReceiveEvent(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
const char * XNT() override;
private:
App(Container * container, Snapshot * snapshot);

View File

@@ -1,49 +1,41 @@
#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, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) :
View(),
m_mainView(subview),
m_textField(parentResponder, m_textBody, TextField::maxBufferSize(), textFieldDelegate)
m_editableExpressionView(parentResponder, textFieldDelegate, scrollableExpressionViewWithCursorDelegate)
{
m_textBody[0] = 0;
}
int EditExpressionController::ContentView::numberOfSubviews() const {
return 2;
}
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_editableExpressionView;
}
void EditExpressionController::ContentView::layoutSubviews() {
KDRect mainViewFrame(0, 0, bounds().width(), bounds().height() - k_textFieldHeight-k_separatorThickness);
KDCoordinate inputViewFrameHeight = m_editableExpressionView.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_editableExpressionView.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) :
@@ -55,20 +47,18 @@ EditExpressionController::EditExpressionController(Responder * parentResponder,
}
const char * EditExpressionController::textBody() {
return ((ContentView *)view())->textField()->text();
return ((ContentView *)view())->editableExpressionView()->text();
}
void EditExpressionController::insertTextBody(const char * text) {
TextField * tf = ((ContentView *)view())->textField();
tf->setEditing(true, false);
tf->handleEventWithText(text);
((ContentView *)view())->editableExpressionView()->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())->editableExpressionView()->setEditing(false, false);
app()->setFirstResponder(m_historyController);
}
return true;
@@ -79,27 +69,90 @@ 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())->editableExpressionView()->setEditing(true, false);
app()->setFirstResponder(((ContentView *)view())->editableExpressionView());
}
bool EditExpressionController::textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) {
assert(textField == ((ContentView *)view())->editableExpressionView()->textField());
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) {
assert(textField == ((ContentView *)view())->editableExpressionView()->textField());
return inputViewDidFinishEditing(text, event);
}
bool EditExpressionController::textFieldDidAbortEditing(::TextField * textField) {
assert(textField == ((ContentView *)view())->editableExpressionView()->textField());
return inputViewDidAbortEditing(textField->text());
}
bool EditExpressionController::scrollableExpressionViewWithCursorDidReceiveEvent(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
assert(scrollableExpressionViewWithCursor == ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor());
if (scrollableExpressionViewWithCursor->isEditing() && scrollableExpressionViewWithCursor->scrollableExpressionViewWithCursorShouldFinishEditing(event) && !expressionLayout()->hasText() && m_calculationStore->numberOfCalculations() > 0) {
return inputViewDidReceiveEvent(event);
}
return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidReceiveEvent(scrollableExpressionViewWithCursor, event);
}
bool EditExpressionController::scrollableExpressionViewWithCursorDidFinishEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) {
assert(scrollableExpressionViewWithCursor == ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor());
return inputViewDidFinishEditing(text, event);
}
bool EditExpressionController::scrollableExpressionViewWithCursorDidAbortEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
assert(scrollableExpressionViewWithCursor == ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor());
return inputViewDidAbortEditing(nullptr);
}
void EditExpressionController::scrollableExpressionViewWithCursorDidChangeSize(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
assert(scrollableExpressionViewWithCursor == ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor());
reloadView();
}
TextFieldDelegateApp * EditExpressionController::textFieldDelegateApp() {
return (App *)app();
}
EditableExpressionViewDelegateApp * EditExpressionController::editableExpressionViewDelegateApp() {
return (App *)app();
}
View * EditExpressionController::loadView() {
return new ContentView(this, (TableView *)m_historyController->view(), this, this);
}
void EditExpressionController::unloadView(View * view) {
delete expressionLayout();
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());
@@ -110,27 +163,21 @@ bool EditExpressionController::textFieldDidFinishEditing(::TextField * textField
return true;
}
bool EditExpressionController::textFieldDidAbortEditing(::TextField * textField, const char * text) {
((ContentView *)view())->textField()->setEditing(true);
((ContentView *)view())->textField()->setText(text);
bool EditExpressionController::inputViewDidAbortEditing(const char * text) {
if (text != nullptr) {
((ContentView *)view())->editableExpressionView()->setEditing(true, true);
((ContentView *)view())->editableExpressionView()->setText(text);
}
return false;
}
TextFieldDelegateApp * EditExpressionController::textFieldDelegateApp() {
return (App *)app();
}
View * EditExpressionController::loadView() {
return new ContentView(this, (TableView *)m_historyController->view(), this);
}
void EditExpressionController::unloadView(View * view) {
delete view;
}
void EditExpressionController::viewDidDisappear() {
DynamicViewController::viewDidDisappear();
m_historyController->viewDidDisappear();
}
Poincare::ExpressionLayout * EditExpressionController::expressionLayout() {
return ((ContentView *)view())->editableExpressionView()->scrollableExpressionViewWithCursor()->expressionViewWithCursor()->expressionView()->expressionLayout();
}
}

View File

@@ -2,16 +2,17 @@
#define CALCULATION_EDIT_EXPRESSION_CONTROLLER_H
#include <escher.h>
#include "editable_expression_view.h"
#include "../shared/text_field_delegate.h"
#include "../shared/scrollable_expression_view_with_cursor_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::ScrollableExpressionViewWithCursorDelegate {
public:
EditExpressionController(Responder * parentResponder, HistoryController * historyController, CalculationStore * calculationStore);
void didBecomeFirstResponder() override;
@@ -19,31 +20,43 @@ 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;
/* ScrollableExpressionViewWithCursorDelegate */
bool scrollableExpressionViewWithCursorDidReceiveEvent(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
bool scrollableExpressionViewWithCursorDidFinishEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) override;
bool scrollableExpressionViewWithCursorDidAbortEditing(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
void scrollableExpressionViewWithCursorDidChangeSize(::ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) 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, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate);
void reload();
TableView * mainView() { return m_mainView; }
EditableExpressionView * editableExpressionView() { return &m_editableExpressionView; }
/* 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;
TableView * m_mainView;
TextField m_textField;
char m_textBody[TextField::maxBufferSize()];
EditableExpressionView m_editableExpressionView;
};
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;
char m_cacheBuffer[TextField::maxBufferSize()];
Shared::EditableExpressionViewDelegateApp * editableExpressionViewDelegateApp() override;
Poincare::ExpressionLayout * expressionLayout();
HistoryController * m_historyController;
CalculationStore * m_calculationStore;
};

View File

@@ -0,0 +1,31 @@
#include "editable_expression_view.h"
namespace Calculation {
EditableExpressionView::EditableExpressionView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) :
::EditableExpressionView(parentResponder, textFieldDelegate, scrollableExpressionViewWithCursorDelegate)
{
setEditing(true);
}
bool EditableExpressionView::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(::EditableExpressionView::handleEvent(event));
}
}

View File

@@ -0,0 +1,17 @@
#ifndef CALCULATION_EDITABLE_EXPRESSION_VIEW_H
#define CALCULATION_EDITABLE_EXPRESSION_VIEW_H
#include <escher.h>
namespace Calculation {
class EditableExpressionView : public ::EditableExpressionView {
public:
EditableExpressionView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate);
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,8 +10,8 @@ ScrollableExpressionView::ScrollableExpressionView(Responder * parentResponder)
{
}
void ScrollableExpressionView::setExpression(ExpressionLayout * expressionLayout) {
m_expressionView.setExpression(expressionLayout);
void ScrollableExpressionView::setExpressionLayout(ExpressionLayout * expressionLayout) {
m_expressionView.setExpressionLayout(expressionLayout);
layoutSubviews();
}

View File

@@ -8,7 +8,7 @@ namespace Calculation {
class ScrollableExpressionView : public ScrollableView, public ScrollViewDataSource {
public:
ScrollableExpressionView(Responder * parentResponder);
void setExpression(Poincare::ExpressionLayout * expressionLayout);
void setExpressionLayout(Poincare::ExpressionLayout * expressionLayout);
void setBackgroundColor(KDColor backgroundColor);
KDSize minimalSizeForOptimalDisplay() const override;
private:

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

@@ -277,7 +277,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

@@ -343,8 +343,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,8 +291,9 @@ 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);
int strippedEditedTextMaxLength = strlen(editedText)+1;
char strippedEditedText[strippedEditedTextMaxLength];
Shared::ToolboxHelpers::TextToInsertForCommandMessage(node->insertedText(), strippedEditedText, strippedEditedTextMaxLength);
TextInput * textInput = static_cast<TextInput *>(sender());
textInput->handleEventWithText(strippedEditedText, true);
app()->dismissModalViewController();

View File

@@ -113,8 +113,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

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

@@ -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,71 @@ 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())),
m_action(actionForTextInput)
{
}
TextField * MathToolbox::sender() {
return (TextField *)Toolbox::sender();
void MathToolbox::setSenderAndAction(Responder * sender, Action action) {
setSender(sender);
m_action = action;
}
void MathToolbox::actionForScrollableExpressionViewWithCursor(void * sender, const char * text, bool removeArguments) {
ScrollableExpressionViewWithCursor * expressionLayoutEditorSender = static_cast<ScrollableExpressionViewWithCursor *>(sender);
Expression * resultExpression = nullptr;
if (removeArguments) {
// Replace the arguments with Empty chars.
int textToInsertMaxLength = strlen(text);
char textToInsert[textToInsertMaxLength];
Shared::ToolboxHelpers::TextToParseIntoLayoutForCommandText(text, textToInsert, textToInsertMaxLength);
// Create the layout
resultExpression = Expression::parse(textToInsert);
} else {
resultExpression = Expression::parse(text);
}
if (resultExpression == nullptr) {
return;
}
ExpressionLayout * resultLayout = resultExpression->createLayout();
// Find the pointed layout.
ExpressionLayout * pointedLayout = nullptr;
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;
}
}
} else if (resultLayout->numberOfChildren() > 0) {
// Else, if the layout has children, pick the first one.
pointedLayout = resultLayout->editableChild(0);
}
// Insert the layout. If pointedLayout is nullptr, the cursor will be on the
// right of the inserted layout.
expressionLayoutEditorSender->insertLayoutAtCursor(resultLayout, pointedLayout);
}
void MathToolbox::actionForTextInput(void * sender, const char * text, bool removeArguments) {
TextInput * textInputSender = static_cast<TextInput *>(sender);
if (removeArguments) {
int maxTextToInsertLength = strlen(text);
char textToInsert[maxTextToInsertLength];
// Translate the message and remove the arguments.
Shared::ToolboxHelpers::TextToInsertForCommandText(text, textToInsert, maxTextToInsertLength);
textInputSender->handleEventWithText(textToInsert);
} else {
textInputSender->handleEventWithText(text);
}
}
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();
m_action(sender(), I18n::translate(messageTree->insertedText()), true);
app()->dismissModalViewController();
return true;
}

View File

@@ -7,15 +7,19 @@
class MathToolbox : public Toolbox {
public:
typedef void (*Action)(void * sender, const char * text, bool removeArguments);
MathToolbox();
void setSenderAndAction(Responder * sender, Action action);
static void actionForScrollableExpressionViewWithCursor(void * sender, const char * text, bool removeArguments = true);
static void actionForTextInput(void * sender, const char * text, bool removeArguments = true);
protected:
TextField * sender() override;
bool selectLeaf(ToolboxMessageTree * selectedMessageTree) override;
const ToolboxMessageTree * rootModel() override;
MessageTableCellWithMessage * leafCellAtIndex(int index) override;
MessageTableCellWithChevron* nodeCellAtIndex(int index) override;
int maxNumberOfDisplayedRows() override;
constexpr static int k_maxNumberOfDisplayedRows = 6; // = 240/40
Action m_action;
private:
MessageTableCellWithMessage m_leafCells[k_maxNumberOfDisplayedRows];
MessageTableCellWithChevron m_nodeCells[k_maxNumberOfDisplayedRows];

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,19 @@
#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/layout_engine.h>
#include "../../../poincare/src/layout/char_layout.h"
#include "../../../poincare/src/layout/condensed_sum_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;
@@ -45,8 +52,115 @@ double TermSumController::cursorNextStep(double x, int direction) {
return std::round(m_cursor->x()+delta);
}
<<<<<<< HEAD
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);
=======
/* Legend View */
TermSumController::LegendView::LegendView() :
m_sum(0.0f, 0.5f, KDColorBlack, Palette::GreyBright),
m_sumLayout(nullptr),
m_legend(KDText::FontSize::Small, I18n::Message::Default, 0.0f, 0.5f, KDColorBlack, Palette::GreyBright)
{
}
TermSumController::LegendView::~LegendView() {
if (m_sumLayout != nullptr) {
delete m_sumLayout;
m_sumLayout = nullptr;
}
}
void TermSumController::LegendView::drawRect(KDContext * ctx, KDRect rect) const {
ctx->fillRect(KDRect(0, bounds().height() - k_legendHeight, bounds().width(), k_legendHeight), Palette::GreyMiddle);
}
KDSize TermSumController::LegendView::minimalSizeForOptimalDisplay() const {
return KDSize(0, k_legendHeight);
}
void TermSumController::LegendView::setLegendMessage(I18n::Message message) {
m_legend.setMessage(message);
layoutSubviews();
}
void TermSumController::LegendView::setSumSubscript(float start) {
if (m_sumLayout) {
delete m_sumLayout;
m_sumLayout = nullptr;
}
const char sigma[] = {' ', Ion::Charset::CapitalSigma};
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
Complex<float>::convertFloatToText(start, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal);
m_sumLayout = new CondensedSumLayout(
LayoutEngine::createStringLayout(sigma, sizeof(sigma), KDText::FontSize::Large),
LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small),
nullptr,
false);
m_sum.setExpressionLayout(m_sumLayout);
m_sum.setAlignment(0.0f, 0.5f);
}
void TermSumController::LegendView::setSumSuperscript(float start, float end) {
if (m_sumLayout) {
delete m_sumLayout;
m_sumLayout = nullptr;
}
const char sigma[] = {' ', Ion::Charset::CapitalSigma};
char bufferStart[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
Complex<float>::convertFloatToText(start, bufferStart, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal);
char bufferEnd[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
Complex<float>::convertFloatToText(end, bufferEnd, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal);
m_sumLayout = new CondensedSumLayout(
LayoutEngine::createStringLayout(sigma, sizeof(sigma), KDText::FontSize::Large),
LayoutEngine::createStringLayout(bufferStart, strlen(bufferStart), KDText::FontSize::Small),
LayoutEngine::createStringLayout(bufferEnd, strlen(bufferEnd), KDText::FontSize::Small),
false);
m_sum.setExpressionLayout(m_sumLayout);
m_sum.setAlignment(0.0f, 0.5f);
}
void TermSumController::LegendView::setSumResult(const char * sequenceName, double result) {
char buffer[2+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
strlcpy(buffer, "= ", 3);
Complex<double>::convertFloatToText(result, buffer+2, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
m_sumLayout = new HorizontalLayout(
m_sumLayout,
new HorizontalLayout(
new CharLayout(sequenceName[0], KDText::FontSize::Small),
new VerticalOffsetLayout(new CharLayout('n', KDText::FontSize::Small), VerticalOffsetLayout::Type::Subscript, false),
false),
LayoutEngine::createStringLayout(buffer, strlen(buffer), KDText::FontSize::Small),
false);
m_sum.setExpressionLayout(m_sumLayout);
m_sum.setAlignment(0.5f, 0.5f);
}
int TermSumController::LegendView::numberOfSubviews() const {
return 2;
}
View * TermSumController::LegendView::subviewAtIndex(int index) {
assert(index >= 0 && index < 2);
if (index == 0) {
return &m_sum;
}
return &m_legend;
}
void TermSumController::LegendView::layoutSubviews() {
KDCoordinate width = bounds().width();
KDCoordinate heigth = bounds().height();
KDSize legendSize = m_legend.minimalSizeForOptimalDisplay();
if (legendSize.width() > 0) {
m_sum.setFrame(KDRect(0, 0, width-legendSize.width(), heigth));
m_legend.setFrame(KDRect(width-legendSize.width(), 0, legendSize.width(), heigth));
return;
}
m_sum.setFrame(bounds());
m_legend.setFrame(KDRectZero);
>>>>>>> SaisieJolieRebase1201
}
}

View File

@@ -24,13 +24,14 @@ 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);
setToolboxExtraCells();
m_sequenceToolbox.setSenderAndAction(textField, MathToolbox::actionForTextInput);
return &m_sequenceToolbox;
}
Toolbox * ListController::toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
setToolboxExtraCells();
m_sequenceToolbox.setSenderAndAction(scrollableExpressionViewWithCursor, MathToolbox::actionForScrollableExpressionViewWithCursor);
return &m_sequenceToolbox;
}
@@ -38,6 +39,10 @@ TextFieldDelegateApp * ListController::textFieldDelegateApp() {
return (App *)app();
}
EditableExpressionViewDelegateApp * ListController::editableExpressionViewDelegateApp() {
return (App *)app();
}
int ListController::numberOfRows() {
int numberOfRows = 0;
for (int i = 0; i < m_sequenceStore->numberOfFunctions(); i++) {
@@ -169,13 +174,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 +190,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;
@@ -304,4 +309,14 @@ void ListController::unloadView(View * view) {
Shared::ListController::unloadView(view);
}
void ListController::setToolboxExtraCells() {
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);
}
}

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/scrollable_expression_view_with_cursor_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::ScrollableExpressionViewWithCursorDelegate {
public:
ListController(Responder * parentResponder, SequenceStore * sequenceStore, ButtonRowController * header, ButtonRowController * footer);
const char * title() override;
@@ -22,9 +23,11 @@ public:
virtual KDCoordinate rowHeight(int j) override;
void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override;
Toolbox * toolboxForTextInput(TextInput * textInput) override;
Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
void selectPreviousNewSequenceCell();
private:
Shared::TextFieldDelegateApp * textFieldDelegateApp() override;
Shared::EditableExpressionViewDelegateApp * editableExpressionViewDelegateApp() override;
void editExpression(Sequence * sequence, int sequenceDefinitionIndex, Ion::Events::Event event);
ListParameterController * parameterController() override;
int maxNumberOfRows() override;
@@ -41,6 +44,7 @@ private:
void reinitExpression(Shared::Function * function) override;
View * loadView() override;
void unloadView(View * view) override;
void setToolboxExtraCells();
static constexpr KDCoordinate k_emptySubRowHeight = 30;
constexpr static int k_maxNumberOfRows = 3*MaxNumberOfSequences;
SequenceStore * m_sequenceStore;

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,12 +89,21 @@ 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]);
@@ -100,19 +111,29 @@ void SequenceToolbox::setExtraCells(const char * sequenceName, int recurrenceDep
}
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;
sender()->handleEventWithText(buffer);
int bufferSize = 10;
char buffer[bufferSize];
m_addedCellLayout[selectedRow]->writeTextInBuffer(buffer, bufferSize);
if (m_action == MathToolbox::actionForTextField) {
// DIRTY. The symbols are layouted using a Subscript VerticalOffsetLayout,
// which serializes into "_{}", but we want parentheses for text fields. We
// thus need to remove any underscores, and changes brackets into
// parentheses.
for (int i = 0; i < bufferSize; i++) {
if (buffer[i] == '{') {
buffer[i] = '(';
}
if (buffer[i] == '}') {
buffer[i] = ')';
}
if (buffer[i] == '_') {
memmove(&buffer[i], &buffer[i+1], bufferSize - (i+1) + 1);
bufferSize--;
i--;
}
}
}
m_action(sender(), buffer, false);
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;
@@ -124,9 +126,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::Large),
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;
@@ -245,12 +259,10 @@ 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);
}
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 +272,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 = "Editiermodus"
EditionLinear = "1D "
Edition2D = "2D "
ComplexFormat = "Komplex"
ExamMode = "Testmodus"
ActivateExamMode = "Start Testmodus"

View File

@@ -2,6 +2,9 @@ SettingsApp = "Settings"
SettingsAppCapital = "SETTINGS"
AngleUnit = "Angle measure"
DisplayMode = "Result format"
EditionMode = "Edition mode"
EditionLinear = "1D "
Edition2D = "2D "
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 = "Modo edicion"
EditionLinear = "1D "
Edition2D = "2D "
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 = "Mode d'edition"
EditionLinear = "1D "
Edition2D = "2D "
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 = "Modo de edicao"
EditionLinear = "1D "
Edition2D = "2D "
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) :
@@ -151,14 +155,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
@@ -169,36 +173,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());
@@ -213,6 +214,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>
@@ -22,13 +21,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);
@@ -73,7 +69,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;
@@ -258,6 +254,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);
}
@@ -270,6 +269,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

@@ -34,6 +34,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\
editable_expression_view_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\
scrollable_expression_view_with_cursor_delegate.o\
store_controller.o\
store_parameter_controller.o\
sum_graph_controller.o\

View File

@@ -0,0 +1,56 @@
#include "editable_expression_view_delegate_app.h"
#include "../i18n.h"
#include "../apps_container.h"
using namespace Poincare;
namespace Shared {
EditableExpressionViewDelegateApp::EditableExpressionViewDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController) :
TextFieldDelegateApp(container, snapshot, rootViewController),
ScrollableExpressionViewWithCursorDelegate()
{
}
bool EditableExpressionViewDelegateApp::scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
return event == Ion::Events::OK || event == Ion::Events::EXE;
}
bool EditableExpressionViewDelegateApp::scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
if (scrollableExpressionViewWithCursor->isEditing() && scrollableExpressionViewWithCursor->scrollableExpressionViewWithCursorShouldFinishEditing(event)) {
if (!scrollableExpressionViewWithCursor->expressionViewWithCursor()->expressionView()->expressionLayout()->hasText()) {
scrollableExpressionViewWithCursor->app()->displayWarning(I18n::Message::SyntaxError);
return true;
}
int bufferSize = 256;
char buffer[bufferSize];
scrollableExpressionViewWithCursor->expressionViewWithCursor()->expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize);
Expression * exp = Expression::parse(buffer);
if (exp != nullptr) {
delete exp;
}
if (exp == nullptr) {
scrollableExpressionViewWithCursor->app()->displayWarning(I18n::Message::SyntaxError);
return true;
}
}
if (event == Ion::Events::Var) {
if (!scrollableExpressionViewWithCursor->isEditing()) {
scrollableExpressionViewWithCursor->setEditing(true);
}
AppsContainer * appsContainer = (AppsContainer *)scrollableExpressionViewWithCursor->app()->container();
VariableBoxController * variableBoxController = appsContainer->variableBoxController();
variableBoxController->setScrollableExpressionViewWithCursorSender(scrollableExpressionViewWithCursor);
scrollableExpressionViewWithCursor->app()->displayModalViewController(variableBoxController, 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin);
return true;
}
return false;
}
Toolbox * EditableExpressionViewDelegateApp::toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
Toolbox * toolbox = container()->mathToolbox();
static_cast<MathToolbox *>(toolbox)->setSenderAndAction(scrollableExpressionViewWithCursor, MathToolbox::actionForScrollableExpressionViewWithCursor);
return toolbox;
}
}

View File

@@ -0,0 +1,21 @@
#ifndef SHARED_EDITABLE_EXPRESSION_VIEW_DELEGATE_APP_H
#define SHARED_EDITABLE_EXPRESSION_VIEW_DELEGATE_APP_H
#include "text_field_delegate_app.h"
#include <escher/scrollable_expression_view_with_cursor_delegate.h>
namespace Shared {
class EditableExpressionViewDelegateApp : public TextFieldDelegateApp, public ScrollableExpressionViewWithCursorDelegate {
public:
virtual ~EditableExpressionViewDelegateApp() = default;
bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
virtual bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
protected:
EditableExpressionViewDelegateApp(Container * container, Snapshot * snapshot, ViewController * rootViewController);
};
}
#endif

View File

@@ -53,7 +53,7 @@ void FunctionApp::Snapshot::reset() {
}
FunctionApp::FunctionApp(Container * container, Snapshot * snapshot, ViewController * rootViewController) :
TextFieldDelegateApp(container, snapshot, rootViewController)
EditableExpressionViewDelegateApp(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 "editable_expression_view_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 EditableExpressionViewDelegateApp {
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

@@ -0,0 +1,31 @@
#include "scrollable_expression_view_with_cursor_delegate.h"
using namespace Poincare;
namespace Shared {
bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorShouldFinishEditing(scrollableExpressionViewWithCursor, event);
}
bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidReceiveEvent(scrollableExpressionViewWithCursor, event);
}
bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) {
return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidFinishEditing(scrollableExpressionViewWithCursor, text, event);
}
bool ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidAbortEditing(scrollableExpressionViewWithCursor);
}
void ScrollableExpressionViewWithCursorDelegate::scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
return editableExpressionViewDelegateApp()->scrollableExpressionViewWithCursorDidChangeSize(scrollableExpressionViewWithCursor);
}
Toolbox * ScrollableExpressionViewWithCursorDelegate::toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
return editableExpressionViewDelegateApp()->toolboxForScrollableExpressionViewWithCursor(scrollableExpressionViewWithCursor);
}
}

View File

@@ -0,0 +1,23 @@
#ifndef SHARED_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_DELEGATE_H
#define SHARED_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_DELEGATE_H
#include <escher/scrollable_expression_view_with_cursor_delegate.h>
#include "editable_expression_view_delegate_app.h"
namespace Shared {
class ScrollableExpressionViewWithCursorDelegate : public ::ScrollableExpressionViewWithCursorDelegate {
public:
bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
bool scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) override;
bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
void scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
private:
virtual EditableExpressionViewDelegateApp * editableExpressionViewDelegateApp() = 0;
};
}
#endif

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->setTextFieldSender(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();
static_cast<MathToolbox *>(toolbox)->setSenderAndAction(textInput, MathToolbox::actionForTextInput);
return toolbox;
}
}

View File

@@ -1,36 +1,52 @@
#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) {
int CursorIndexInCommandText(const char * text) {
for (size_t i = 0; i < strlen(text); i++) {
if (text[i] == '(' || text[i] == '\'') {
return i + 1;
}
if (text[i] == ']') {
return i;
}
}
return strlen(text);
}
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) {
TextToInsertForCommandText(I18n::translate(message), buffer, bufferSize);
}
void TextToInsertForCommandText(const char * command, char * buffer) {
void TextToInsertForCommandText(const char * command, char * buffer, int bufferSize) {
int currentNewTextIndex = 0;
int numberOfOpenParentheses = 0;
int numberOfOpenBrackets = 0;
bool insideQuote = 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);
buffer[currentNewTextIndex++] = command[i];
}
if (command[i] == '(') {
numberOfOpenParentheses++;
}
if (command[i] == '[') {
numberOfOpenBrackets++;
}
if (command[i] == '\'') {
@@ -40,5 +56,24 @@ void TextToInsertForCommandText(const char * command, char * buffer) {
buffer[currentNewTextIndex] = 0;
}
void TextToParseIntoLayoutForCommandMessage(I18n::Message message, char * buffer, int bufferSize) {
TextToParseIntoLayoutForCommandText(I18n::translate(message), buffer, bufferSize);
}
void TextToParseIntoLayoutForCommandText(const char * command, char * buffer, int bufferSize) {
TextToInsertForCommandText(command, buffer, bufferSize);
size_t bufferLength = strlen(buffer);
for (size_t i = 0; i < bufferLength; i++) {
if (buffer[i] == '(' || buffer[i] == ',' || (i < bufferLength - 1 && buffer[i] == '[' && buffer[i+1] == ']')) {
// Shift the buffer to make room for the new char. Use memmove to avoid
// overwritting.
memmove(&buffer[i+2], &buffer[i+1], bufferLength - (i+1) + 1);
bufferLength++;
i++;
buffer[i] = Ion::Charset::Empty;
}
}
}
}
}

View File

@@ -6,17 +6,20 @@
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);
void TextToInsertForCommandText(const char * command, char * buffer, int bufferSize);
/* Removes the arguments from a command:
* - Removes text between parentheses, except commas */
* - Removes text between parentheses or brackets, except commas */
void TextToParseIntoLayoutForCommandMessage(I18n::Message message, char * buffer, int bufferSize);
void TextToParseIntoLayoutForCommandText(const char * command, char * buffer, int bufferSize);
/* Removes the arguments from a command and replaces them with empty chars. */
}
}

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),
@@ -18,14 +18,13 @@ VariableBoxController::ContentViewController::ContentViewController(Responder *
{
}
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);
@@ -65,7 +64,7 @@ bool VariableBoxController::ContentViewController::handleEvent(Ion::Events::Even
char label[3];
putLabelAtIndexInBuffer(selectedRow(), label);
const char * editedText = label;
m_textFieldCaller->handleEventWithText(editedText);
m_insertTextAction(m_sender, editedText);
#if MATRIX_VARIABLES
m_selectableTableView.deselectTable();
m_currentPage = Page::RootMenu;
@@ -198,21 +197,31 @@ 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;
}
void VariableBoxController::ContentViewController::setTextFieldSender(TextField * textField) {
m_sender = textField;
m_insertTextAction = &insertTextInTextInput;
}
void VariableBoxController::ContentViewController::setScrollableExpressionViewWithCursorSender(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
m_sender = scrollableExpressionViewWithCursor;
m_insertTextAction = &insertTextInScrollableExpressionViewWithCursor;
}
void VariableBoxController::ContentViewController::reloadData() {
m_selectableTableView.reloadData();
}
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) {
@@ -253,25 +262,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();
void VariableBoxController::ContentViewController::insertTextInTextInput(void * sender, const char * textToInsert) {
TextInput * textInput = static_cast<TextInput *>(sender);
textInput->handleEventWithText(textToInsert);
}
void VariableBoxController::ContentViewController::insertTextInScrollableExpressionViewWithCursor(void * sender, const char * textToInsert) {
ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor = static_cast<ScrollableExpressionViewWithCursor *>(sender);
if (!scrollableExpressionViewWithCursor->isEditing()) {
scrollableExpressionViewWithCursor->setEditing(true);
}
scrollableExpressionViewWithCursor->insertLayoutFromTextAtCursor(textToInsert);
}
VariableBoxController::VariableBoxController(GlobalContext * context) :
@@ -284,8 +302,12 @@ void VariableBoxController::didBecomeFirstResponder() {
app()->setFirstResponder(&m_contentViewController);
}
void VariableBoxController::setTextFieldCaller(TextField * textField) {
m_contentViewController.setTextFieldCaller(textField);
void VariableBoxController::setTextFieldSender(TextField * textField) {
m_contentViewController.setTextFieldSender(textField);
}
void VariableBoxController::setScrollableExpressionViewWithCursorSender(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
m_contentViewController.setScrollableExpressionViewWithCursorSender(scrollableExpressionViewWithCursor);
}
void VariableBoxController::viewWillAppear() {

View File

@@ -10,9 +10,11 @@
class VariableBoxController : public StackViewController {
public:
typedef void (*Action)(void * sender, const char * text);
VariableBoxController(Poincare::GlobalContext * context);
void didBecomeFirstResponder() override;
void setTextFieldCaller(TextField * textField);
void setTextFieldSender(TextField * textField);
void setScrollableExpressionViewWithCursorSender(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor);
void viewWillAppear() override;
void viewDidDisappear() override;
private:
@@ -31,7 +33,8 @@ private:
KDCoordinate cumulatedHeightFromIndex(int j) override;
int indexFromCumulatedHeight(KDCoordinate offsetY) override;
int typeAtLocation(int i, int j) override;
void setTextFieldCaller(TextField * textField);
void setTextFieldSender(TextField * textField);
void setScrollableExpressionViewWithCursorSender(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor);
void reloadData();
void resetPage();
void viewDidDisappear() override;
@@ -55,9 +58,11 @@ private:
void putLabelAtIndexInBuffer(int index, char * buffer);
I18n::Message nodeLabelAtIndex(int index);
const Poincare::Expression * expressionForIndex(int index);
static void insertTextInTextInput(void * sender, const char * textToInsert);
static void insertTextInScrollableExpressionViewWithCursor(void * sender, const char * textToInsert);
Poincare::GlobalContext * m_context;
TextField * m_textFieldCaller;
Responder * m_sender;
Action m_insertTextAction;
int m_firstSelectedRow;
int m_previousSelectedRow;
Page m_currentPage;

View File

@@ -91,7 +91,7 @@ void VariableBoxLeafCell::setExpression(const Expression * expression) {
if (expression) {
m_expressionLayout = expression->createLayout();
}
m_expressionView.setExpression(m_expressionLayout);
m_expressionView.setExpressionLayout(m_expressionLayout);
}
void VariableBoxLeafCell::drawRect(KDContext * ctx, KDRect rect) const {

View File

@@ -12,6 +12,7 @@ objs += $(addprefix escher/src/,\
dynamic_view_controller.o\
editable_text_cell.o\
ellipsis_view.o\
editable_expression_view.o\
even_odd_cell.o\
even_odd_cell_with_ellipsis.o\
even_odd_buffer_text_cell.o\
@@ -21,6 +22,7 @@ objs += $(addprefix escher/src/,\
expression_table_cell.o\
expression_table_cell_with_pointer.o\
expression_view.o\
expression_view_with_cursor.o\
highlight_cell.o\
gauge_view.o\
image_view.o\
@@ -48,6 +50,7 @@ objs += $(addprefix escher/src/,\
scroll_view_data_source.o\
scroll_view_indicator.o\
scrollable_view.o\
scrollable_expression_view_with_cursor.o\
selectable_table_view.o\
selectable_table_view_data_source.o\
selectable_table_view_delegate.o\
@@ -73,7 +76,6 @@ objs += $(addprefix escher/src/,\
tiled_view.o\
timer.o\
toolbox.o\
toolbox_message_tree.o\
view.o\
view_controller.o\
warning_controller.o\

View File

@@ -11,6 +11,7 @@
#include <escher/clipboard.h>
#include <escher/container.h>
#include <escher/dynamic_view_controller.h>
#include <escher/editable_expression_view.h>
#include <escher/editable_text_cell.h>
#include <escher/ellipsis_view.h>
#include <escher/even_odd_cell.h>
@@ -22,6 +23,7 @@
#include <escher/expression_table_cell.h>
#include <escher/expression_table_cell_with_pointer.h>
#include <escher/expression_view.h>
#include <escher/expression_view_with_cursor.h>
#include <escher/gauge_view.h>
#include <escher/highlight_cell.h>
#include <escher/image.h>
@@ -51,6 +53,8 @@
#include <escher/scroll_view_data_source.h>
#include <escher/scroll_view_indicator.h>
#include <escher/scrollable_view.h>
#include <escher/scrollable_expression_view_with_cursor.h>
#include <escher/scrollable_expression_view_with_cursor_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

@@ -0,0 +1,48 @@
#ifndef ESCHER_EDITABLE_EXPRESSION_VIEW_H
#define ESCHER_EDITABLE_EXPRESSION_VIEW_H
#include <escher/scrollable_expression_view_with_cursor.h>
#include <escher/scrollable_expression_view_with_cursor_delegate.h>
#include <escher/text_field.h>
#include <escher/text_field_delegate.h>
class EditableExpressionView : public Responder, public View {
public:
EditableExpressionView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate);
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();
TextField * textField() { return &m_textField; }
ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor() { return &m_scrollableExpressionViewWithCursor; }
bool editionIsInTextField() const;
bool isEmpty() const;
bool heightIsMaximal() const;
/* 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;
static constexpr int k_bufferLength = TextField::maxBufferSize();
private:
static constexpr KDCoordinate k_textFieldHeight = 37;
static constexpr KDCoordinate k_leftMargin = 5;
static constexpr KDCoordinate k_verticalExpressionViewMargin = 5;
constexpr static int k_separatorThickness = 1;
KDCoordinate inputViewHeight() const;
KDCoordinate maximalHeight() const;
TextField m_textField;
ScrollableExpressionViewWithCursor m_scrollableExpressionViewWithCursor;
char m_textBody[k_bufferLength];
};
#endif

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

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

@@ -0,0 +1,36 @@
#ifndef ESCHER_EXPRESSION_VIEW_WITH_CURSOR_H
#define ESCHER_EXPRESSION_VIEW_WITH_CURSOR_H
#include <escher/expression_view.h>
#include <escher/text_cursor_view.h>
#include <kandinsky/point.h>
#include <poincare/expression_layout.h>
#include <poincare/expression_layout_cursor.h>
class ExpressionViewWithCursor : public View {
public:
ExpressionViewWithCursor(Poincare::ExpressionLayout * expressionLayout);
bool isEditing() const { return m_isEditing; }
void setEditing(bool isEditing);
void cursorPositionChanged();
KDRect cursorRect();
Poincare::ExpressionLayoutCursor * cursor() { return &m_cursor; }
ExpressionView * expressionView() { return &m_expressionView; }
/* View */
KDSize minimalSizeForOptimalDisplay() const override;
private:
enum class Position {
Top,
Bottom
};
int numberOfSubviews() const override { return 2; }
View * subviewAtIndex(int index) override;
void layoutSubviews() override;
void layoutCursorSubview();
Poincare::ExpressionLayoutCursor m_cursor;
ExpressionView m_expressionView;
TextCursorView m_cursorView;
bool m_isEditing;
};
#endif

View File

@@ -1,53 +1,56 @@
#ifndef ESCHER_INPUT_VIEW_CONTROLLER_H
#define ESCHER_INPUT_VIEW_CONTROLLER_H
#include <escher/editable_expression_view.h>
#include <escher/scrollable_expression_view_with_cursor_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, ScrollableExpressionViewWithCursorDelegate {
public:
InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate);
InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate);
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;
/* ScrollableExpressionViewWithCursorDelegate */
bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) override;
bool scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) override;
bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
void scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) override;
private:
class TextFieldController : public ViewController {
class EditableExpressionViewController : public ViewController {
public:
TextFieldController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate);
EditableExpressionViewController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate);
void didBecomeFirstResponder() override;
View * view() override;
TextField * textField();
View * view() override { return &m_editableExpressionView; }
EditableExpressionView * editableExpressionView() { return &m_editableExpressionView; }
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;
EditableExpressionView m_editableExpressionView;
};
TextFieldController m_textFieldController;
bool inputViewDidFinishEditing();
bool inputViewDidAbortEditing();
EditableExpressionViewController m_editableExpressionViewController;
Invocation m_successAction;
Invocation m_failureAction;
TextFieldDelegate * m_textFieldDelegate;
ScrollableExpressionViewWithCursorDelegate * m_scrollableExpressionViewWithCursorDelegate;
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

@@ -17,6 +17,8 @@ public:
bool isDisplayingModal();
void viewWillAppear() override;
void viewDidDisappear() override;
protected:
void reloadView();
private:
class ContentView : public View {
public:
@@ -29,6 +31,7 @@ private:
KDCoordinate topMargin, KDCoordinate leftMargin, KDCoordinate bottomMargin, KDCoordinate rightMargin);
void dismissModalView();
bool isDisplayingModal() const;
void reload();
private:
KDRect frame() const;
View * m_regularView;

View File

@@ -0,0 +1,40 @@
#ifndef ESCHER_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_H
#define ESCHER_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_H
#include <escher/scrollable_view.h>
#include <escher/expression_view_with_cursor.h>
#include <escher/scrollable_expression_view_with_cursor_delegate.h>
#include <poincare/expression_layout_cursor.h>
class ScrollableExpressionViewWithCursor : public ScrollableView, public ScrollViewDataSource {
public:
ScrollableExpressionViewWithCursor(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, ScrollableExpressionViewWithCursorDelegate * delegate = nullptr);
void setDelegate(ScrollableExpressionViewWithCursorDelegate * delegate) { m_delegate = delegate; }
ExpressionViewWithCursor * expressionViewWithCursor() { return &m_expressionViewWithCursor; }
bool isEditing() const;
void setEditing(bool isEditing);
void clearLayout();
void scrollToCursor();
void reload();
/* Responder */
Toolbox * toolbox() override;
bool handleEvent(Ion::Events::Event event) override;
bool scrollableExpressionViewWithCursorShouldFinishEditing(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);
ExpressionViewWithCursor m_expressionViewWithCursor;
private:
ScrollableExpressionViewWithCursorDelegate * m_delegate;
};
#endif

View File

@@ -0,0 +1,19 @@
#ifndef ESCHER_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_DELEGATE_H
#define ESCHER_SCROLLABLE_EXPRESSION_VIEW_WITH_CURSOR_DELEGATE_H
#include <escher/toolbox.h>
#include <ion/events.h>
class ScrollableExpressionViewWithCursor;
class ScrollableExpressionViewWithCursorDelegate {
public:
virtual bool scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) = 0;
virtual bool scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) = 0;
virtual bool scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) { return false; }
virtual bool scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) { return false; }
virtual void scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {}
virtual Toolbox * toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) = 0;
};
#endif

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

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

@@ -41,6 +41,7 @@ public:
KDPoint pointFromPointInView(View * view, KDPoint point);
KDRect bounds() const;
KDRect frame() const;
View * subview(int index);
virtual KDSize minimalSizeForOptimalDisplay() const;

View File

@@ -0,0 +1,128 @@
#include <escher/editable_expression_view.h>
#include <poincare/preferences.h>
#include <assert.h>
EditableExpressionView::EditableExpressionView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) :
Responder(parentResponder),
View(),
m_textField(parentResponder, m_textBody, m_textBody, k_bufferLength, textFieldDelegate, false),
m_scrollableExpressionViewWithCursor(parentResponder, new Poincare::HorizontalLayout(), scrollableExpressionViewWithCursorDelegate)
{
m_textBody[0] = 0;
}
void EditableExpressionView::setEditing(bool isEditing, bool reinitDraftBuffer) {
if (editionIsInTextField()) {
m_textField.setEditing(isEditing, reinitDraftBuffer);
}
if (reinitDraftBuffer) {
m_scrollableExpressionViewWithCursor.clearLayout();
}
m_scrollableExpressionViewWithCursor.setEditing(isEditing);
}
bool EditableExpressionView::isEditing() const {
return editionIsInTextField() ? m_textField.isEditing() : m_scrollableExpressionViewWithCursor.isEditing();
}
const char * EditableExpressionView::text() {
if (!editionIsInTextField()) {
m_scrollableExpressionViewWithCursor.expressionViewWithCursor()->expressionView()->expressionLayout()->writeTextInBuffer(m_textBody, k_bufferLength);
}
return m_textBody;
}
void EditableExpressionView::setText(const char * text) {
if (editionIsInTextField()) {
m_textField.setText(text);
return;
}
m_scrollableExpressionViewWithCursor.clearLayout();
if (strlen(text) > 0) {
m_scrollableExpressionViewWithCursor.insertLayoutFromTextAtCursor(text);
}
}
void EditableExpressionView::insertText(const char * text) {
if (editionIsInTextField()) {
m_textField.handleEventWithText(text);
} else {
m_scrollableExpressionViewWithCursor.setEditing(true);
m_scrollableExpressionViewWithCursor.insertLayoutFromTextAtCursor(text);
}
}
View * EditableExpressionView::subviewAtIndex(int index) {
assert(index == 0);
if (editionIsInTextField()) {
return &m_textField;
}
return &m_scrollableExpressionViewWithCursor;
}
void EditableExpressionView::layoutSubviews() {
KDRect inputViewFrame(k_leftMargin, k_separatorThickness, bounds().width() - k_leftMargin, bounds().height() - k_separatorThickness);
if (editionIsInTextField()) {
m_textField.setFrame(inputViewFrame);
m_scrollableExpressionViewWithCursor.setFrame(KDRectZero);
return;
}
m_scrollableExpressionViewWithCursor.setFrame(inputViewFrame);
m_textField.setFrame(KDRectZero);
}
void EditableExpressionView::reload() {
layoutSubviews();
markRectAsDirty(bounds());
}
void EditableExpressionView::drawRect(KDContext * ctx, KDRect rect) const {
// Draw the separator
ctx->fillRect(KDRect(0, 0, bounds().width(), k_separatorThickness), Palette::GreyMiddle);
// Color the left margin
ctx->fillRect(KDRect(0, k_separatorThickness, k_leftMargin, bounds().height() - k_separatorThickness), m_textField.backgroundColor());
if (!editionIsInTextField()) {
// Color the upper margin
ctx->fillRect(KDRect(0, k_separatorThickness, bounds().width(), k_verticalExpressionViewMargin), m_textField.backgroundColor());
}
}
bool EditableExpressionView::handleEvent(Ion::Events::Event event) {
return editionIsInTextField() ? m_textField.handleEvent(event) : m_scrollableExpressionViewWithCursor.handleEvent(event);
}
KDSize EditableExpressionView::minimalSizeForOptimalDisplay() const {
return KDSize(0, inputViewHeight());
}
bool EditableExpressionView::editionIsInTextField() const {
return Poincare::Preferences::sharedPreferences()->editionMode() == Poincare::Preferences::EditionMode::Edition1D;
}
bool EditableExpressionView::isEmpty() const {
if (editionIsInTextField()) {
return m_textField.draftTextLength() == 0;
}
Poincare::ExpressionLayout * layout = const_cast<ScrollableExpressionViewWithCursor *>(&m_scrollableExpressionViewWithCursor)->expressionViewWithCursor()->expressionView()->expressionLayout();
return !layout->hasText();
}
bool EditableExpressionView::heightIsMaximal() const {
return inputViewHeight() == k_separatorThickness + k_verticalExpressionViewMargin + maximalHeight();
}
KDCoordinate EditableExpressionView::inputViewHeight() const {
if (editionIsInTextField()) {
return k_separatorThickness + k_textFieldHeight;
}
return k_separatorThickness
+ k_verticalExpressionViewMargin
+ min(maximalHeight(),
max(k_textFieldHeight,
m_scrollableExpressionViewWithCursor.minimalSizeForOptimalDisplay().height()
+ k_verticalExpressionViewMargin));
}
KDCoordinate EditableExpressionView::maximalHeight() const {
return 0.6*Ion::Display::Height;
}

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

@@ -18,7 +18,7 @@ void ExpressionTableCell::setHighlighted(bool highlight) {
m_labelExpressionView.setBackgroundColor(backgroundColor);
}
void ExpressionTableCell::setExpression(Poincare::ExpressionLayout * expressionLayout) {
m_labelExpressionView.setExpression(expressionLayout);
void ExpressionTableCell::setExpressionLayout(Poincare::ExpressionLayout * expressionLayout) {
m_labelExpressionView.setExpressionLayout(expressionLayout);
layoutSubviews();
}

View File

@@ -15,7 +15,7 @@ ExpressionLayout * ExpressionView::expressionLayout() const {
return m_expressionLayout;
}
void ExpressionView::setExpression(ExpressionLayout * expressionLayout) {
void ExpressionView::setExpressionLayout(ExpressionLayout * expressionLayout) {
m_expressionLayout = expressionLayout;
markRectAsDirty(bounds());
}
@@ -47,13 +47,18 @@ KDSize ExpressionView::minimalSizeForOptimalDisplay() const {
return m_expressionLayout->size();
}
KDPoint ExpressionView::drawingOrigin() const {
KDSize expressionSize = m_expressionLayout->size();
return KDPoint(m_horizontalAlignment*(m_frame.width() - expressionSize.width()), 0.5f*(m_frame.height() - expressionSize.height()));
}
KDPoint ExpressionView::absoluteDrawingOrigin() const {
return drawingOrigin().translatedBy(m_frame.topLeft());
}
void ExpressionView::drawRect(KDContext * ctx, KDRect rect) const {
ctx->fillRect(rect, m_backgroundColor);
if (m_expressionLayout != nullptr) {
//Position the origin of expression
KDSize expressionSize = m_expressionLayout->size();
KDPoint origin(m_horizontalAlignment*(m_frame.width() - expressionSize.width()),
0.5f*(m_frame.height() - expressionSize.height()));
m_expressionLayout->draw(ctx, origin, m_textColor, m_backgroundColor);
m_expressionLayout->draw(ctx, drawingOrigin(), m_textColor, m_backgroundColor);
}
}

View File

@@ -0,0 +1,64 @@
#include <escher/expression_view_with_cursor.h>
#include <kandinsky/rect.h>
#include <assert.h>
using namespace Poincare;
ExpressionViewWithCursor::ExpressionViewWithCursor(ExpressionLayout * expressionLayout) :
m_cursor(),
m_expressionView(),
m_cursorView(),
m_isEditing(false)
{
m_cursor.setPointedExpressionLayout(expressionLayout);
m_cursor.setPosition(ExpressionLayoutCursor::Position::Right);
m_expressionView.setExpressionLayout(expressionLayout);
}
void ExpressionViewWithCursor::setEditing(bool isEditing) {
m_isEditing = isEditing;
markRectAsDirty(bounds());
layoutSubviews();
}
void ExpressionViewWithCursor::cursorPositionChanged() {
layoutCursorSubview();
}
KDRect ExpressionViewWithCursor::cursorRect() {
return m_cursorView.frame();
}
KDSize ExpressionViewWithCursor::minimalSizeForOptimalDisplay() const {
KDSize expressionViewSize = m_expressionView.minimalSizeForOptimalDisplay();
KDSize cursorSize = isEditing() ? m_cursorView.minimalSizeForOptimalDisplay() : KDSizeZero;
KDCoordinate resultWidth = expressionViewSize.width() + cursorSize.width();
KDCoordinate resultHeight = expressionViewSize.height() + cursorSize.height()/2;
return KDSize(resultWidth, resultHeight);
}
View * ExpressionViewWithCursor::subviewAtIndex(int index) {
assert(index >= 0 && index < 2);
View * m_views[] = {&m_expressionView, &m_cursorView};
return m_views[index];
}
void ExpressionViewWithCursor::layoutSubviews() {
m_expressionView.setFrame(bounds());
layoutCursorSubview();
}
void ExpressionViewWithCursor::layoutCursorSubview() {
if (!m_isEditing) {
m_cursorView.setFrame(KDRectZero);
return;
}
KDPoint expressionViewOrigin = m_expressionView.absoluteDrawingOrigin();
KDPoint cursoredExpressionViewOrigin = m_cursor.pointedExpressionLayout()->absoluteOrigin();
KDCoordinate cursorX = expressionViewOrigin.x() + cursoredExpressionViewOrigin.x();
if (m_cursor.position() == ExpressionLayoutCursor::Position::Right) {
cursorX += m_cursor.pointedExpressionLayout()->size().width();
}
KDPoint cursorTopLeftPosition(cursorX, expressionViewOrigin.y() + cursoredExpressionViewOrigin.y() + m_cursor.pointedExpressionLayout()->baseline()-m_cursor.cursorHeight()/2);
m_cursorView.setFrame(KDRect(cursorTopLeftPosition, 1, m_cursor.cursorHeight()));
}

View File

@@ -1,88 +1,46 @@
#include <escher/input_view_controller.h>
#include <escher/app.h>
#include <escher/palette.h>
#include <poincare/src/layout/horizontal_layout.h>
#include <assert.h>
InputViewController::TextFieldController::ContentView::ContentView(Responder * parentResponder, TextFieldDelegate * textFieldDelegate) :
Responder(parentResponder),
View(),
m_textField(this, m_textBody, m_textBody, TextField::maxBufferSize(), textFieldDelegate, false)
{
m_textBody[0] = 0;
}
void InputViewController::TextFieldController::ContentView::didBecomeFirstResponder() {
app()->setFirstResponder(&m_textField);
}
TextField * InputViewController::TextFieldController::ContentView::textField() {
return &m_textField;
}
void InputViewController::TextFieldController::ContentView::drawRect(KDContext * ctx, KDRect rect) const {
ctx->fillRect(KDRect(0, 0, bounds().width(), k_separatorThickness), Palette::GreyMiddle);
ctx->fillRect(KDRect(0, k_separatorThickness, k_textMargin, bounds().height()-k_separatorThickness), m_textField.backgroundColor());
}
KDSize InputViewController::TextFieldController::ContentView::minimalSizeForOptimalDisplay() const {
return KDSize(0, k_inputHeight);
}
int InputViewController::TextFieldController::ContentView::numberOfSubviews() const {
return 1;
}
View * InputViewController::TextFieldController::ContentView::subviewAtIndex(int index) {
return &m_textField;
}
void InputViewController::TextFieldController::ContentView::layoutSubviews() {
m_textField.setFrame(KDRect(k_textMargin, k_separatorThickness, bounds().width()-k_textMargin, bounds().height()));
}
InputViewController::TextFieldController::TextFieldController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate) :
InputViewController::EditableExpressionViewController::EditableExpressionViewController(Responder * parentResponder, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) :
ViewController(parentResponder),
m_view(this, textFieldDelegate)
m_editableExpressionView(this, textFieldDelegate, scrollableExpressionViewWithCursorDelegate)
{
}
View * InputViewController::TextFieldController::view() {
return &m_view;
void InputViewController::EditableExpressionViewController::didBecomeFirstResponder() {
app()->setFirstResponder(&m_editableExpressionView);
}
void InputViewController::TextFieldController::didBecomeFirstResponder() {
app()->setFirstResponder(&m_view);
}
TextField * InputViewController::TextFieldController::textField() {
return m_view.textField();
}
InputViewController::InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate) :
InputViewController::InputViewController(Responder * parentResponder, ViewController * child, TextFieldDelegate * textFieldDelegate, ScrollableExpressionViewWithCursorDelegate * scrollableExpressionViewWithCursorDelegate) :
ModalViewController(parentResponder, child),
m_textFieldController(this, this),
m_editableExpressionViewController(this, this, this),
m_successAction(Invocation(nullptr, nullptr)),
m_failureAction(Invocation(nullptr, nullptr)),
m_textFieldDelegate(textFieldDelegate)
m_textFieldDelegate(textFieldDelegate),
m_scrollableExpressionViewWithCursorDelegate(scrollableExpressionViewWithCursorDelegate),
m_inputViewHeightIsMaximal(false)
{
}
const char * InputViewController::textBody() {
return m_textFieldController.textField()->text();
return m_editableExpressionViewController.editableExpressionView()->text();
}
void InputViewController::edit(Responder * caller, Ion::Events::Event event, void * context, const char * initialText, Invocation::Action successAction, Invocation::Action failureAction) {
m_successAction = Invocation(successAction, context);
m_failureAction = Invocation(failureAction, context);
displayModalViewController(&m_textFieldController, 1.0f, 1.0f);
m_textFieldController.textField()->handleEvent(event);
displayModalViewController(&m_editableExpressionViewController, 1.0f, 1.0f);
m_editableExpressionViewController.editableExpressionView()->handleEvent(event);
if (initialText != nullptr) {
m_textFieldController.textField()->handleEventWithText(initialText);
m_editableExpressionViewController.editableExpressionView()->setText(initialText);
}
}
void InputViewController::abortTextFieldEditionAndDismiss() {
m_textFieldController.textField()->setEditing(false);
void InputViewController::abortEditionAndDismiss() {
m_editableExpressionViewController.editableExpressionView()->setEditing(false);
dismissModalViewController();
}
@@ -91,15 +49,11 @@ bool InputViewController::textFieldShouldFinishEditing(TextField * textField, Io
}
bool InputViewController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) {
m_successAction.perform(this);
dismissModalViewController();
return true;
return inputViewDidFinishEditing();
}
bool InputViewController::textFieldDidAbortEditing(TextField * textField, const char * text) {
m_failureAction.perform(this);
dismissModalViewController();
return true;
bool InputViewController::textFieldDidAbortEditing(TextField * textField) {
return inputViewDidAbortEditing();
}
bool InputViewController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
@@ -109,3 +63,45 @@ bool InputViewController::textFieldDidReceiveEvent(TextField * textField, Ion::E
Toolbox * InputViewController::toolboxForTextInput(TextInput * input) {
return m_textFieldDelegate->toolboxForTextInput(input);
}
bool InputViewController::scrollableExpressionViewWithCursorShouldFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
return event == Ion::Events::OK || event == Ion::Events::EXE;
}
bool InputViewController::scrollableExpressionViewWithCursorDidReceiveEvent(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, Ion::Events::Event event) {
return m_scrollableExpressionViewWithCursorDelegate->scrollableExpressionViewWithCursorDidReceiveEvent(scrollableExpressionViewWithCursor, event);
}
bool InputViewController::scrollableExpressionViewWithCursorDidFinishEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor, const char * text, Ion::Events::Event event) {
return inputViewDidFinishEditing();
}
bool InputViewController::scrollableExpressionViewWithCursorDidAbortEditing(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
return inputViewDidAbortEditing();
}
void InputViewController::scrollableExpressionViewWithCursorDidChangeSize(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
// Reload the view only if the EditableExpressionView height actually changes,
// i.e. not if the height is already maximal and stays maximal.
bool newInputViewHeightIsMaximal = m_editableExpressionViewController.editableExpressionView()->heightIsMaximal();
if (!m_inputViewHeightIsMaximal || !newInputViewHeightIsMaximal) {
m_inputViewHeightIsMaximal = newInputViewHeightIsMaximal;
reloadView();
}
}
Toolbox * InputViewController::toolboxForScrollableExpressionViewWithCursor(ScrollableExpressionViewWithCursor * scrollableExpressionViewWithCursor) {
return m_scrollableExpressionViewWithCursorDelegate->toolboxForScrollableExpressionViewWithCursor(scrollableExpressionViewWithCursor);
}
bool InputViewController::inputViewDidFinishEditing() {
m_successAction.perform(this);
dismissModalViewController();
return true;
}
bool InputViewController::inputViewDidAbortEditing() {
m_failureAction.perform(this);
dismissModalViewController();
return true;
}

View File

@@ -17,8 +17,8 @@ void MessageTableCellWithChevronAndExpression::setHighlighted(bool highlight) {
m_subtitleView.setBackgroundColor(backgroundColor);
}
void MessageTableCellWithChevronAndExpression::setExpression(Poincare::ExpressionLayout * expressionLayout) {
m_subtitleView.setExpression(expressionLayout);
void MessageTableCellWithChevronAndExpression::setExpressionLayout(Poincare::ExpressionLayout * expressionLayout) {
m_subtitleView.setExpressionLayout(expressionLayout);
reloadCell();
layoutSubviews();
}

View File

@@ -95,6 +95,11 @@ bool ModalViewController::ContentView::isDisplayingModal() const {
return m_isDisplayingModal;
}
void ModalViewController::ContentView::reload() {
markRectAsDirty(frame());
layoutSubviews();
}
ModalViewController::ModalViewController(Responder * parentResponder, ViewController * child) :
ViewController(parentResponder),
m_contentView(),
@@ -162,3 +167,7 @@ void ModalViewController::viewDidDisappear() {
}
m_regularViewController->viewDidDisappear();
}
void ModalViewController::reloadView() {
m_contentView.reload();
}

View File

@@ -0,0 +1,238 @@
#include <escher/scrollable_expression_view_with_cursor.h>
#include <escher/clipboard.h>
#include <escher/text_field.h>
#include <poincare/src/layout/matrix_layout.h>
#include <assert.h>
ScrollableExpressionViewWithCursor::ScrollableExpressionViewWithCursor(Responder * parentResponder, Poincare::ExpressionLayout * expressionLayout, ScrollableExpressionViewWithCursorDelegate * delegate) :
ScrollableView(parentResponder, &m_expressionViewWithCursor, this),
m_expressionViewWithCursor(expressionLayout),
m_delegate(delegate)
{
}
bool ScrollableExpressionViewWithCursor::isEditing() const {
return m_expressionViewWithCursor.isEditing();
}
void ScrollableExpressionViewWithCursor::setEditing(bool isEditing) {
m_expressionViewWithCursor.setEditing(isEditing);
}
void ScrollableExpressionViewWithCursor::clearLayout() {
delete m_expressionViewWithCursor.expressionView()->expressionLayout();
Poincare::ExpressionLayout * newLayout = new Poincare::HorizontalLayout();
m_expressionViewWithCursor.expressionView()->setExpressionLayout(newLayout);
m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(newLayout);
}
void ScrollableExpressionViewWithCursor::scrollToCursor() {
scrollToContentRect(m_expressionViewWithCursor.cursorRect(), true);
}
Toolbox * ScrollableExpressionViewWithCursor::toolbox() {
if (m_delegate) {
return m_delegate->toolboxForScrollableExpressionViewWithCursor(this);
}
return nullptr;
}
bool ScrollableExpressionViewWithCursor::handleEvent(Ion::Events::Event event) {
KDSize previousSize = minimalSizeForOptimalDisplay();
bool shouldRecomputeLayout = false;
if (privateHandleMoveEvent(event, &shouldRecomputeLayout)) {
if (!shouldRecomputeLayout) {
m_expressionViewWithCursor.cursorPositionChanged();
scrollToCursor();
return true;
}
reload();
KDSize newSize = minimalSizeForOptimalDisplay();
if (m_delegate && previousSize.height() != newSize.height()) {
m_delegate->scrollableExpressionViewWithCursorDidChangeSize(this);
reload();
}
return true;
}
if (privateHandleEvent(event)) {
reload();
KDSize newSize = minimalSizeForOptimalDisplay();
if (m_delegate && previousSize.height() != newSize.height()) {
m_delegate->scrollableExpressionViewWithCursorDidChangeSize(this);
reload();
}
return true;
}
return false;
}
bool ScrollableExpressionViewWithCursor::scrollableExpressionViewWithCursorShouldFinishEditing(Ion::Events::Event event) {
return m_delegate->scrollableExpressionViewWithCursorShouldFinishEditing(this, event);
}
KDSize ScrollableExpressionViewWithCursor::minimalSizeForOptimalDisplay() const {
return m_expressionViewWithCursor.minimalSizeForOptimalDisplay();
}
bool ScrollableExpressionViewWithCursor::privateHandleMoveEvent(Ion::Events::Event event, bool * shouldRecomputeLayout) {
if (event == Ion::Events::Left) {
return m_expressionViewWithCursor.cursor()->moveLeft(shouldRecomputeLayout);
}
if (event == Ion::Events::Right) {
return m_expressionViewWithCursor.cursor()->moveRight(shouldRecomputeLayout);
}
if (event == Ion::Events::Up) {
return m_expressionViewWithCursor.cursor()->moveUp(shouldRecomputeLayout);
}
if (event == Ion::Events::Down) {
return m_expressionViewWithCursor.cursor()->moveDown(shouldRecomputeLayout);
}
if (event == Ion::Events::ShiftLeft) {
m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout());
m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Left);
return true;
}
if (event == Ion::Events::ShiftRight) {
m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout());
m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right);
return true;
}
return false;
}
bool ScrollableExpressionViewWithCursor::privateHandleEvent(Ion::Events::Event event) {
if (m_delegate && m_delegate->scrollableExpressionViewWithCursorDidReceiveEvent(this, event)) {
return true;
}
if (Responder::handleEvent(event)) {
/* The only event Responder handles is 'Toolbox' displaying. In that case,
* the ScrollableExpressionViewWithCursor is forced into editing mode. */
if (!isEditing()) {
setEditing(true);
}
return true;
}
if (isEditing() && scrollableExpressionViewWithCursorShouldFinishEditing(event)) {
setEditing(false);
int bufferSize = TextField::maxBufferSize();
char buffer[bufferSize];
m_expressionViewWithCursor.expressionView()->expressionLayout()->writeTextInBuffer(buffer, bufferSize);
if (m_delegate->scrollableExpressionViewWithCursorDidFinishEditing(this, buffer, event)) {
delete m_expressionViewWithCursor.expressionView()->expressionLayout();
Poincare::ExpressionLayout * newLayout = new Poincare::HorizontalLayout();
m_expressionViewWithCursor.expressionView()->setExpressionLayout(newLayout);
m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(newLayout);
}
return true;
}
if ((event == Ion::Events::OK || event == Ion::Events::EXE) && !isEditing()) {
setEditing(true);
m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(m_expressionViewWithCursor.expressionView()->expressionLayout());
m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right);
return true;
}
if (event == Ion::Events::Back && isEditing()) {
setEditing(false);
m_delegate->scrollableExpressionViewWithCursorDidAbortEditing(this);
return true;
}
if (event == Ion::Events::Division) {
m_expressionViewWithCursor.cursor()->addFractionLayoutAndCollapseBrothers();
return true;
}
if (event == Ion::Events::XNT) {
m_expressionViewWithCursor.cursor()->addXNTCharLayout();
return true;
}
if (event == Ion::Events::Exp) {
m_expressionViewWithCursor.cursor()->addEmptyExponentialLayout();
return true;
}
if (event == Ion::Events::Power) {
m_expressionViewWithCursor.cursor()->addEmptyPowerLayout();
return true;
}
if (event == Ion::Events::Sqrt) {
m_expressionViewWithCursor.cursor()->addEmptySquareRootLayout();
return true;
}
if (event == Ion::Events::Square) {
m_expressionViewWithCursor.cursor()->addEmptySquarePowerLayout();
return true;
}
if (event.hasText()) {
const char * textToInsert = event.text();
if (textToInsert[1] == 0) {
if (textToInsert[0] == Ion::Charset::MultiplicationSign) {
const char middleDotString[] = {Ion::Charset::MiddleDot, 0};
m_expressionViewWithCursor.cursor()->insertText(middleDotString);
return true;
}
if (textToInsert[0] == '[' || textToInsert[0] == ']') {
m_expressionViewWithCursor.cursor()->addEmptyMatrixLayout();
return true;
}
}
m_expressionViewWithCursor.cursor()->insertText(textToInsert);
return true;
}
if (event == Ion::Events::Backspace) {
m_expressionViewWithCursor.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 ScrollableExpressionViewWithCursor::insertLayoutAtCursor(Poincare::ExpressionLayout * layout, Poincare::ExpressionLayout * pointedLayout) {
if (layout == nullptr) {
return;
}
KDSize previousSize = minimalSizeForOptimalDisplay();
if (layout->isMatrix() && pointedLayout && pointedLayout->hasAncestor(layout)) {
static_cast<Poincare::MatrixLayout *>(layout)->addGreySquares();
}
if (pointedLayout != nullptr) {
m_expressionViewWithCursor.cursor()->addLayout(layout);
m_expressionViewWithCursor.cursor()->setPointedExpressionLayout(pointedLayout);
m_expressionViewWithCursor.cursor()->setPosition(Poincare::ExpressionLayoutCursor::Position::Right);
} else {
m_expressionViewWithCursor.cursor()->addLayoutAndMoveCursor(layout);
}
reload();
KDSize newSize = minimalSizeForOptimalDisplay();
if (m_delegate && previousSize.height() != newSize.height()) {
m_delegate->scrollableExpressionViewWithCursorDidChangeSize(this);
}
}
void ScrollableExpressionViewWithCursor::insertLayoutFromTextAtCursor(const char * text) {
Poincare::Expression * expression = Poincare::Expression::parse(text);
if (expression != nullptr) {
Poincare::ExpressionLayout * layout = expression->createLayout();
delete expression;
insertLayoutAtCursor(layout, nullptr);
reload();
return;
}
m_expressionViewWithCursor.cursor()->insertText(text);
reload();
}
void ScrollableExpressionViewWithCursor::reload() {
m_expressionViewWithCursor.expressionView()->expressionLayout()->invalidAllSizesPositionsAndBaselines();
m_expressionViewWithCursor.cursorPositionChanged();
layoutSubviews();
scrollToCursor();
markRectAsDirty(bounds());
}

View File

@@ -249,7 +249,7 @@ bool TextField::privateHandleEvent(Ion::Events::Event event) {
if (event == Ion::Events::Back && isEditing()) {
setEditing(false);
reloadScroll();
m_delegate->textFieldDidAbortEditing(this, text());
m_delegate->textFieldDidAbortEditing(this);
return true;
}
if (event == Ion::Events::Clear && isEditing()) {

View File

@@ -1,13 +0,0 @@
#include <escher/toolbox_message_tree.h>
I18n::Message ToolboxMessageTree::text() const {
return m_text;
}
I18n::Message ToolboxMessageTree::insertedText() const {
return m_insertedText;
}
const MessageTree * ToolboxMessageTree::children(int index) const {
return &m_children[index];
}

View File

@@ -158,6 +158,10 @@ KDRect View::bounds() const {
return m_frame.movedTo(KDPointZero);
}
KDRect View::frame() const {
return KDRect(m_frame);
}
KDPoint View::absoluteOrigin() const {
if (m_superview == nullptr) {
assert(this == (View *)window());

View File

@@ -24,7 +24,8 @@ enum Charset : char {
GreaterEqual = (char)146,
MultiplicationSign = (char)147,
MiddleDot = (char)148,
AlmostEqual = (char)149
AlmostEqual = (char)149,
Empty = (char)150 // This char is used to be parsed into EmptyExpression.
};
}

View File

@@ -17,6 +17,7 @@ public:
bool operator !=(const KDPoint &other) const {
return !(operator ==(other));
}
uint16_t squareDistanceTo(KDPoint other) const;
private:
KDCoordinate m_x;
KDCoordinate m_y;

View File

@@ -45,6 +45,8 @@ public:
KDCoordinate left() const { return m_x; }
KDPoint topLeft() const { return KDPoint(left(), top()); }
KDPoint topRight() const { return KDPoint(right(), top()); }
KDPoint bottomLeft() const { return KDPoint(left(), bottom()); }
KDPoint bottomRight() const { return KDPoint(right(), bottom()); }
bool operator ==(const KDRect &other) const {
@@ -61,6 +63,8 @@ public:
KDRect intersectedWith(const KDRect & other) const;
KDRect unionedWith(const KDRect & other) const; // Returns the smallest rectangle containing r1 and r2
bool contains(KDPoint p) const;
bool isAbove(KDPoint p) const;
bool isUnder(KDPoint p) const;
bool isEmpty() const;
private:

View File

@@ -7,3 +7,7 @@ KDPoint KDPoint::translatedBy(KDPoint other) const {
KDPoint KDPoint::opposite() const {
return KDPoint(-m_x, -m_y);
}
uint16_t KDPoint::squareDistanceTo(KDPoint other) const {
return (m_x-other.x()) * (m_x-other.x()) + (m_y-other.y()) * (m_y-other.y());
}

Some files were not shown because too many files have changed in this diff Show More