diff --git a/apps/graph/list/function_expression_cell.cpp b/apps/graph/list/function_expression_cell.cpp index 4c9994d44..8e8e6a06c 100644 --- a/apps/graph/list/function_expression_cell.cpp +++ b/apps/graph/list/function_expression_cell.cpp @@ -1,20 +1,21 @@ #include "function_expression_cell.h" #include +using namespace Poincare; + namespace Graph { FunctionExpressionCell::FunctionExpressionCell() : EvenOddCell(), - m_function(nullptr), m_expressionView(ExpressionView()) { } -void FunctionExpressionCell::setFunction(CartesianFunction * f) { - m_function = f; - m_expressionView.setExpression(m_function->layout()); - bool active = m_function->isActive(); - KDColor textColor = active ? KDColorBlack : Palette::GreyDark; +void FunctionExpressionCell::setExpression(ExpressionLayout * expressionLayout) { + m_expressionView.setExpression(expressionLayout); +} + +void FunctionExpressionCell::setTextColor(KDColor textColor) { m_expressionView.setTextColor(textColor); } @@ -28,10 +29,6 @@ void FunctionExpressionCell::setHighlighted(bool highlight) { m_expressionView.setBackgroundColor(backgroundColor()); } -CartesianFunction * FunctionExpressionCell::function() { - return m_function; -} - int FunctionExpressionCell::numberOfSubviews() const { return 1; } diff --git a/apps/graph/list/function_expression_cell.h b/apps/graph/list/function_expression_cell.h index 5bf0f090b..2a7101270 100644 --- a/apps/graph/list/function_expression_cell.h +++ b/apps/graph/list/function_expression_cell.h @@ -2,15 +2,14 @@ #define GRAPH_FUNCTION_EXPRESSION_CELL_H #include -#include "../cartesian_function.h" namespace Graph { class FunctionExpressionCell : public EvenOddCell { public: FunctionExpressionCell(); - virtual void setFunction(CartesianFunction * f); - CartesianFunction * function(); + void setExpression(Poincare::ExpressionLayout * expressionLayout); + void setTextColor(KDColor color); void setEven(bool even) override; void setHighlighted(bool highlight) override; int numberOfSubviews() const override; @@ -19,7 +18,6 @@ public: void drawRect(KDContext * ctx, KDRect rect) const override; private: constexpr static KDCoordinate k_separatorThickness = 1; - CartesianFunction * m_function; ExpressionView m_expressionView; }; diff --git a/apps/graph/list/list_controller.cpp b/apps/graph/list/list_controller.cpp index cecd51dee..90a807fa6 100644 --- a/apps/graph/list/list_controller.cpp +++ b/apps/graph/list/list_controller.cpp @@ -30,8 +30,8 @@ bool ListController::handleEvent(Ion::Events::Event event) { || m_selectableTableView.selectedRow() == numberOfRows() - 1) { return false; } - FunctionExpressionCell * functionCell = (FunctionExpressionCell *)(m_selectableTableView.cellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow())); - editExpression(functionCell, event); + Shared::Function * function = m_functionStore->functionAtIndex(m_selectableTableView.selectedRow()); + editExpression(function, event); return true; } @@ -54,8 +54,8 @@ bool ListController::handleEnter() { m_selectableTableView.reloadData(); return true; } - FunctionExpressionCell * functionCell = (FunctionExpressionCell *)(m_selectableTableView.cellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow())); - editExpression(functionCell, Ion::Events::OK); + Shared::Function * function = m_functionStore->functionAtIndex(m_selectableTableView.selectedRow()); + editExpression(function, Ion::Events::OK); return true; } default: @@ -65,23 +65,21 @@ bool ListController::handleEnter() { } } -void ListController::editExpression(FunctionExpressionCell * functionCell, Ion::Events::Event event) { +void ListController::editExpression(Function * function, Ion::Events::Event event) { char * initialText = nullptr; char initialTextContent[255]; if (event == Ion::Events::OK) { - strlcpy(initialTextContent, functionCell->function()->text(), sizeof(initialTextContent)); + strlcpy(initialTextContent, function->text(), sizeof(initialTextContent)); initialText = initialTextContent; } App * myApp = (App *)app(); InputViewController * inputController = myApp->inputViewController(); - inputController->edit(this, event, functionCell, initialText, + inputController->edit(this, event, function, initialText, [](void * context, void * sender){ - FunctionExpressionCell * myCell = (FunctionExpressionCell *) context; - Shared::Function * myFunction = myCell->function(); + Shared::Function * myFunction = (Shared::Function *)context; InputViewController * myInputViewController = (InputViewController *)sender; const char * textBody = myInputViewController->textBody(); myFunction->setContent(textBody); - myCell->reloadCell(); }, [](void * context, void * sender){ }); @@ -122,7 +120,12 @@ void ListController::willDisplayTitleCellAtIndex(TableViewCell * cell, int j) { void ListController::willDisplayExpressionCellAtIndex(TableViewCell * cell, int j) { FunctionExpressionCell * myCell = (FunctionExpressionCell *)cell; - myCell->setFunction(((CartesianFunctionStore *)m_functionStore)->functionAtIndex(j)); + Function * f = m_functionStore->functionAtIndex(j); + myCell->setExpression(f->layout()); + bool active = f->isActive(); + KDColor textColor = active ? KDColorBlack : Palette::GreyDark; + myCell->setTextColor(textColor); } + } diff --git a/apps/graph/list/list_controller.h b/apps/graph/list/list_controller.h index 0e0189298..53b10b3a8 100644 --- a/apps/graph/list/list_controller.h +++ b/apps/graph/list/list_controller.h @@ -18,7 +18,7 @@ public: bool handleEvent(Ion::Events::Event event) override; private: bool handleEnter(); - void editExpression(FunctionExpressionCell * functionCell, Ion::Events::Event event); + void editExpression(Shared::Function * function, Ion::Events::Event event); Shared::ListParameterController * parameterController() override; int maxNumberOfRows() override; TableViewCell * titleCells(int index) override; diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 011799a74..71c37b6ba 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -122,6 +122,7 @@ MathToolbox::MathToolbox() : void MathToolbox::didBecomeFirstResponder() { m_nodeModel = (ToolboxNode *)rootModel(); + m_selectableTableView.reloadData(); StackViewController::didBecomeFirstResponder(); m_stack.resetStack(); m_listController.setFirstSelectedRow(0); @@ -158,7 +159,6 @@ TableViewCell * MathToolbox::reusableCell(int index, int type) { } int MathToolbox::reusableCellCount(int type) { - assert(type < 2); return k_maxNumberOfDisplayedRows; } @@ -210,6 +210,10 @@ void MathToolbox::viewWillDisappear() { m_selectableTableView.deselectTable(); } +int MathToolbox::stackDepth() { + return m_stack.depth(); +} + TextField * MathToolbox::sender() { return (TextField *)Toolbox::sender(); } diff --git a/apps/math_toolbox.h b/apps/math_toolbox.h index 968f9e931..be270f376 100644 --- a/apps/math_toolbox.h +++ b/apps/math_toolbox.h @@ -25,6 +25,11 @@ public: int typeAtLocation(int i, int j) override; void viewWillDisappear() override; +protected: + int stackDepth(); + TextField * sender() override; + SelectableTableView m_selectableTableView; + constexpr static int k_maxNumberOfDisplayedRows = 6; //240/40 private: class Stack { public: @@ -60,8 +65,6 @@ private: }; constexpr static KDCoordinate k_nodeRowHeight = 40; constexpr static KDCoordinate k_leafRowHeight = 40; - constexpr static int k_maxNumberOfDisplayedRows = 6; //240/40 - TextField * sender() override; const ToolboxNode * rootModel(); bool selectLeaf(ToolboxNode * selectedNode); bool selectSubMenu(ToolboxNode * selectedNode); @@ -69,7 +72,6 @@ private: Stack m_stack; ToolboxLeafCell m_leafCells[k_maxNumberOfDisplayedRows]; ChevronMenuListCell m_nodeCells[k_maxNumberOfDisplayedRows]; - SelectableTableView m_selectableTableView; ListController m_listController; ToolboxNode * m_nodeModel; }; diff --git a/apps/sequence/Makefile b/apps/sequence/Makefile index 87b76514a..77fb0b83f 100644 --- a/apps/sequence/Makefile +++ b/apps/sequence/Makefile @@ -10,6 +10,7 @@ app_objs += $(addprefix apps/sequence/,\ values/values_controller.o\ sequence.o\ sequence_store.o\ + sequence_toolbox.o\ ) app_images += apps/sequence/sequence_icon.png diff --git a/apps/sequence/app.cpp b/apps/sequence/app.cpp index aa4c7f945..9cb4fbf81 100644 --- a/apps/sequence/app.cpp +++ b/apps/sequence/app.cpp @@ -7,6 +7,7 @@ namespace Sequence { App::App(Container * container, Context * context) : TextFieldDelegateApp(container, &m_inputViewController, "Suites", "SUITES", ImageStore::SequenceIcon), + m_sequenceToolbox(SequenceToolbox()), m_sequenceStore(SequenceStore()), m_nContext(VariableContext('n', context)), m_listController(&m_listHeader, &m_sequenceStore, &m_listHeader), @@ -37,4 +38,12 @@ const char * App::XNT() { return "n"; } +SequenceToolbox * App::sequenceToolbox() { + return &m_sequenceToolbox; +} + +SequenceStore * App::sequenceStore() { + return &m_sequenceStore; +} + } diff --git a/apps/sequence/app.h b/apps/sequence/app.h index df4b07b5c..6b12a837a 100644 --- a/apps/sequence/app.h +++ b/apps/sequence/app.h @@ -4,6 +4,7 @@ #include #include #include "sequence_store.h" +#include "sequence_toolbox.h" #include "list/list_controller.h" #include "values/values_controller.h" #include "../shared/text_field_delegate_app.h" @@ -16,7 +17,10 @@ public: InputViewController * inputViewController(); Poincare::Context * localContext() override; const char * XNT() override; + SequenceToolbox * sequenceToolbox(); + SequenceStore * sequenceStore(); private: + SequenceToolbox m_sequenceToolbox; SequenceStore m_sequenceStore; Poincare::VariableContext m_nContext; ListController m_listController; diff --git a/apps/sequence/list/list_controller.cpp b/apps/sequence/list/list_controller.cpp index 9738ed4ef..b2c2d11a1 100644 --- a/apps/sequence/list/list_controller.cpp +++ b/apps/sequence/list/list_controller.cpp @@ -67,11 +67,11 @@ bool ListController::handleEvent(Ion::Events::Event event) { void ListController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY) { if (m_functionStore->numberOfFunctions() == m_functionStore->maxNumberOfFunctions() || t->selectedRow() < numberOfRows() - 1) { - SequenceCell * myCell = (SequenceCell *)t->cellAtLocation(t->selectedColumn(), t->selectedRow()); - app()->setFirstResponder(myCell); if (t->selectedRow() == -1) { return; } + SequenceCell * myCell = (SequenceCell *)t->cellAtLocation(t->selectedColumn(), t->selectedRow()); + app()->setFirstResponder(myCell); if (t->selectedRow() == previousSelectedCellY) { SequenceCell * otherCell = (SequenceCell *)t->cellAtLocation(previousSelectedCellX, previousSelectedCellY); myCell->selectSubCell(otherCell->selectedSubCell()); diff --git a/apps/sequence/list/sequence_expression_cell.cpp b/apps/sequence/list/sequence_expression_cell.cpp index e0f370df9..89f0aa0fd 100644 --- a/apps/sequence/list/sequence_expression_cell.cpp +++ b/apps/sequence/list/sequence_expression_cell.cpp @@ -66,6 +66,32 @@ bool SequenceExpressionCell::handleEvent(Ion::Events::Event event) { return false; } +Toolbox * SequenceExpressionCell::toolboxForTextField(TextField * textField) { + SequenceToolbox * toolbox = ((App *)app())->sequenceToolbox(); + SequenceStore * sequenceStore = ((App *)app())->sequenceStore(); + int numberOfToolboxAddedCells = 0; + char * toolboxCellNames[6]; + char * toolboxCellSubscript[6]; + int recurrenceDepth = 0; + if (m_selectedSubCell == 0) { + recurrenceDepth = m_numberOfSubCells-1; + } + for (int k = 0; k < sequenceStore->numberOfFunctions(); k++) { + Sequence * s = sequenceStore->functionAtIndex(k); + for (int j = 0; j < recurrenceDepth; j++) { + toolboxCellNames[numberOfToolboxAddedCells] = (char *)s->name(); + toolboxCellSubscript[numberOfToolboxAddedCells] = (char *)(j == 0? "n" : "n+1"); + numberOfToolboxAddedCells++; + } + } + toolbox->addCells(numberOfToolboxAddedCells, toolboxCellNames, toolboxCellSubscript); + return toolbox; +} + +TextFieldDelegateApp * SequenceExpressionCell::textFieldDelegateApp() { + return (App *)app(); +} + EvenOddCell * SequenceExpressionCell::viewAtIndex(int index) { if (index == 0) { return &m_expressionView; @@ -92,6 +118,7 @@ void SequenceExpressionCell::editExpression(Ion::Events::Event event) { } App * myApp = (App *)app(); InputViewController * inputController = myApp->inputViewController(); + inputController->setTextFieldDelegate(this); if (m_selectedSubCell == 0) { inputController->edit(this, event, this, initialText, [](void * context, void * sender){ diff --git a/apps/sequence/list/sequence_expression_cell.h b/apps/sequence/list/sequence_expression_cell.h index e66eccc82..9132d4ab8 100644 --- a/apps/sequence/list/sequence_expression_cell.h +++ b/apps/sequence/list/sequence_expression_cell.h @@ -3,18 +3,21 @@ #include "../sequence.h" #include "sequence_cell.h" +#include "../../shared/text_field_delegate.h" #include namespace Sequence { -class SequenceExpressionCell : public SequenceCell { +class SequenceExpressionCell : public SequenceCell, public Shared::TextFieldDelegate { public: SequenceExpressionCell(Responder * parentResponder); void setSequence(Sequence * sequence) override; Sequence * sequence(); void drawRect(KDContext * ctx, KDRect rect) const override; bool handleEvent(Ion::Events::Event event) override; + Toolbox * toolboxForTextField(TextField * textField) override; private: + Shared::TextFieldDelegateApp * textFieldDelegateApp() override; EvenOddCell * viewAtIndex(int index) override; void editExpression(Ion::Events::Event event); EvenOddExpressionCell m_expressionView; diff --git a/apps/sequence/sequence_toolbox.cpp b/apps/sequence/sequence_toolbox.cpp new file mode 100644 index 000000000..03c0013d5 --- /dev/null +++ b/apps/sequence/sequence_toolbox.cpp @@ -0,0 +1,93 @@ +#include "sequence_toolbox.h" +#include "../../poincare/src/layout/baseline_relative_layout.h" +#include "../../poincare/src/layout/string_layout.h" +#include + +using namespace Poincare; + +namespace Sequence { + +SequenceToolbox::SequenceToolbox() : + MathToolbox(), + m_numberOfAddedCells(0) +{ +} + +bool SequenceToolbox::handleEvent(Ion::Events::Event event) { + if (event == Ion::Events::OK && stackDepth() == 0) { + int selectedRow = m_selectableTableView.selectedRow(); + if (selectedRow < m_numberOfAddedCells) { + return selectAddedCell(selectedRow); + } + } + return MathToolbox::handleEvent(event); +} + +int SequenceToolbox::numberOfRows() { + if (stackDepth() == 0) { + return MathToolbox::numberOfRows()+m_numberOfAddedCells; + } + return MathToolbox::numberOfRows(); +} + +TableViewCell * SequenceToolbox::reusableCell(int index, int type) { + assert(type < 3); + assert(index >= 0); + assert(index < k_maxNumberOfDisplayedRows); + if (type == 2) { + return &m_addedCells[index]; + } + return MathToolbox::reusableCell(index, type); +} + +void SequenceToolbox::willDisplayCellForIndex(TableViewCell * cell, int index) { + if (typeAtLocation(0, index) == 2) { + ExpressionMenuListCell * myCell = (ExpressionMenuListCell *)cell; + myCell->setExpression(m_addedCellLayout[index]); + return; + } else { + MathToolbox::willDisplayCellForIndex(cell, index); + } +} + +KDCoordinate SequenceToolbox::rowHeight(int j) { + if (typeAtLocation(0, j) == 2) { + return k_addedRowHeight; + } + return MathToolbox::rowHeight(j); +} + +int SequenceToolbox::typeAtLocation(int i, int j) { + if (stackDepth() == 0 && j < m_numberOfAddedCells) { + return 2; + } + return MathToolbox::typeAtLocation(i,j); +} + +void SequenceToolbox::addCells(int numberOfAddedCells, char ** cellNames, char ** cellSubscript) { + m_numberOfAddedCells = numberOfAddedCells; + for (int i = 0; i < numberOfAddedCells; i++) { + m_addedCellLayout[i] = new BaselineRelativeLayout(new StringLayout(cellNames[i], 1, KDText::FontSize::Large), new StringLayout(cellSubscript[i], strlen(cellSubscript[i]), KDText::FontSize::Small), BaselineRelativeLayout::Type::Subscript); + } +} + +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()->insertTextAtLocation(buffer, sender()->cursorLocation()); + sender()->setCursorLocation(sender()->cursorLocation()+currentChar); + app()->dismissModalViewController(); + return true; +} + +} diff --git a/apps/sequence/sequence_toolbox.h b/apps/sequence/sequence_toolbox.h new file mode 100644 index 000000000..c26675496 --- /dev/null +++ b/apps/sequence/sequence_toolbox.h @@ -0,0 +1,28 @@ +#ifndef SEQUENCE_SEQUENCE_TOOLBOX_H +#define SEQUENCE_SEQUENCE_TOOLBOX_H + +#include "../math_toolbox.h" + +namespace Sequence { + +class SequenceToolbox : public MathToolbox { +public: + SequenceToolbox(); + bool handleEvent(Ion::Events::Event event) override; + int numberOfRows() override; + TableViewCell * reusableCell(int index, int type) override; + void willDisplayCellForIndex(TableViewCell * cell, int index) override; + KDCoordinate rowHeight(int j) override; + int typeAtLocation(int i, int j) override; + void addCells(int numberOfAddedCells, char ** cellNames, char ** cellSubscripts); +private: + bool selectAddedCell(int selectedRow); + constexpr static KDCoordinate k_addedRowHeight = 20; + ExpressionMenuListCell m_addedCells[k_maxNumberOfDisplayedRows]; + Poincare::ExpressionLayout * m_addedCellLayout[k_maxNumberOfDisplayedRows]; + int m_numberOfAddedCells; +}; + +} + +#endif diff --git a/escher/include/escher/input_view_controller.h b/escher/include/escher/input_view_controller.h index 7bbde626c..6bb0e9fc1 100644 --- a/escher/include/escher/input_view_controller.h +++ b/escher/include/escher/input_view_controller.h @@ -12,6 +12,7 @@ public: const char * title() const override; void edit(Responder * caller, Ion::Events::Event event, void * context, const char * initialText, Invocation::Action successAction, Invocation::Action failureAction); const char * textBody(); + void setTextFieldDelegate(TextFieldDelegate * textFieldDelegate); bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override; bool textFieldDidFinishEditing(TextField * textField, const char * text) override; bool textFieldDidAbortEditing(TextField * textField, const char * text) override; diff --git a/escher/src/input_view_controller.cpp b/escher/src/input_view_controller.cpp index cc3425ac7..3483da950 100644 --- a/escher/src/input_view_controller.cpp +++ b/escher/src/input_view_controller.cpp @@ -49,6 +49,10 @@ void InputViewController::edit(Responder * caller, Ion::Events::Event event, voi } } +void InputViewController::setTextFieldDelegate(TextFieldDelegate * textFieldDelegate) { + m_textFieldDelegate = textFieldDelegate; +} + bool InputViewController::textFieldDidFinishEditing(TextField * textField, const char * text) { m_successAction.perform(this); dismissModalViewController(); diff --git a/poincare/src/layout/baseline_relative_layout.cpp b/poincare/src/layout/baseline_relative_layout.cpp index dfd2fc992..9ff635a15 100644 --- a/poincare/src/layout/baseline_relative_layout.cpp +++ b/poincare/src/layout/baseline_relative_layout.cpp @@ -21,6 +21,14 @@ BaselineRelativeLayout::~BaselineRelativeLayout() { delete m_indiceLayout; } +ExpressionLayout * BaselineRelativeLayout::baseLayout() { + return m_baseLayout; +} + +ExpressionLayout * BaselineRelativeLayout::indiceLayout() { + return m_indiceLayout; +} + void BaselineRelativeLayout::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) { // There is nothing to draw for a subscript/superscript, only the position of the children matters } diff --git a/poincare/src/layout/baseline_relative_layout.h b/poincare/src/layout/baseline_relative_layout.h index 2e19a293d..2382d5c50 100644 --- a/poincare/src/layout/baseline_relative_layout.h +++ b/poincare/src/layout/baseline_relative_layout.h @@ -14,6 +14,8 @@ class BaselineRelativeLayout : public ExpressionLayout { }; BaselineRelativeLayout(ExpressionLayout * baseLayout, ExpressionLayout * indiceLayout, Type type); ~BaselineRelativeLayout(); + ExpressionLayout * baseLayout(); + ExpressionLayout * indiceLayout(); protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override; diff --git a/poincare/src/layout/string_layout.cpp b/poincare/src/layout/string_layout.cpp index 88ee73ff1..4df0ce63d 100644 --- a/poincare/src/layout/string_layout.cpp +++ b/poincare/src/layout/string_layout.cpp @@ -19,6 +19,10 @@ StringLayout::~StringLayout() { free(m_string); } +char * StringLayout::text() { + return m_string; +} + ExpressionLayout * StringLayout::child(uint16_t index) { return nullptr; } diff --git a/poincare/src/layout/string_layout.h b/poincare/src/layout/string_layout.h index ed94f4a25..3a286ee81 100644 --- a/poincare/src/layout/string_layout.h +++ b/poincare/src/layout/string_layout.h @@ -13,6 +13,7 @@ class StringLayout : public ExpressionLayout { // sure about compatibility. StringLayout(const char * string, size_t length, KDText::FontSize fontSize = KDText::FontSize::Large); ~StringLayout(); + char * text(); protected: void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override; KDSize computeSize() override;