diff --git a/apps/Makefile b/apps/Makefile index cbf4bccad..922ebc4cb 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -16,10 +16,9 @@ app_objs += $(addprefix apps/,\ constant.o\ global_preferences.o\ main.o\ + math_toolbox.o\ node.o\ - node_list_view_controller.o\ title_bar_view.o\ - toolbox_controller.o\ toolbox_leaf_cell.o\ toolbox_node.o\ variable_box_controller.o\ diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp index 8f8f0eaf4..5d32e05bc 100644 --- a/apps/apps_container.cpp +++ b/apps/apps_container.cpp @@ -48,8 +48,8 @@ Context * AppsContainer::globalContext() { return &m_globalContext; } -ToolboxController * AppsContainer::toolboxController() { - return &m_toolboxController; +MathToolbox * AppsContainer::mathToolbox() { + return &m_mathToolbox; } VariableBoxController * AppsContainer::variableBoxController() { diff --git a/apps/apps_container.h b/apps/apps_container.h index 3c9761c81..b97cdf8fd 100644 --- a/apps/apps_container.h +++ b/apps/apps_container.h @@ -10,7 +10,7 @@ #include "settings/app.h" #include "statistics/app.h" #include "apps_window.h" -#include "toolbox_controller.h" +#include "math_toolbox.h" #include "variable_box_controller.h" #define USE_PIC_VIEW_APP 0 @@ -25,7 +25,7 @@ public: int numberOfApps(); App * appAtIndex(int index); Poincare::Context * globalContext(); - ToolboxController * toolboxController(); + MathToolbox * mathToolbox(); VariableBoxController * variableBoxController(); bool handleEvent(Ion::Events::Event event) override; void switchTo(App * app) override; @@ -46,7 +46,7 @@ private: PicViewApp m_picViewApp; #endif Poincare::GlobalContext m_globalContext; - ToolboxController m_toolboxController; + MathToolbox m_mathToolbox; VariableBoxController m_variableBoxController; }; diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp new file mode 100644 index 000000000..011799a74 --- /dev/null +++ b/apps/math_toolbox.cpp @@ -0,0 +1,273 @@ +#include "math_toolbox.h" +#include +#include + +/* TODO: find a shorter way to initiate 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 nullptr. */ + +const ToolboxNode calculChildren[4] = {ToolboxNode("diff(,)", "Nombre derive"), ToolboxNode("int(,,)", "Integrale"), ToolboxNode("sum(,,)", "Somme"), ToolboxNode("product(,,)", "Produit")}; +const ToolboxNode complexChildren[5] = {ToolboxNode("abs()", "Module"), ToolboxNode("arg()", "Argument"), ToolboxNode("re()", "Partie reelle"), ToolboxNode("im()", "Partie imaginaire"), ToolboxNode("conj()", "Conjugue")}; +const ToolboxNode probabilityChildren[4] = {ToolboxNode("binomial()", "Combinaison"), ToolboxNode("permute(,)", "Arrangement"), ToolboxNode("random(,)", "Nombre aleatoire"), ToolboxNode("gamma()", "Fonction gamma")}; +const ToolboxNode arithmeticChildren[4] = {ToolboxNode("gcd()", "PGCD"), ToolboxNode("lcm()", "PPCM"), ToolboxNode("rem()", "Reste division euclidienne"), ToolboxNode("quo()","Quotien division euclidienne")}; +const ToolboxNode matricesChildren[5] = {ToolboxNode("inverse()", "Inverse"), ToolboxNode("det()", "Determinant"), ToolboxNode("transpose()", "Transposee"), ToolboxNode("trace()", "Trace"), ToolboxNode("dim()", "Taille")}; +const ToolboxNode listesChildren[5] = {ToolboxNode("sort<()", "Tri croissant"), ToolboxNode("sort>()", "Tri decroissant"), ToolboxNode("max()", "Maximum"), ToolboxNode("min()", "Minimum"), ToolboxNode("dim()", "Taille")}; +const ToolboxNode approximationChildren[4] = {ToolboxNode("floor()", "Partie entiere"), ToolboxNode("frac()", "Partie fractionnaire"), ToolboxNode("ceil()", "Plafond"), ToolboxNode("round(,)", "Arrondi")}; +const ToolboxNode trigonometryChildren[6] = {ToolboxNode("cosh()", "cosh"), ToolboxNode("sinh()", "sinh"), ToolboxNode("tanh()", "tanh"), ToolboxNode("acosh()", "acosh"), ToolboxNode("asinh()", "asinh"), ToolboxNode("atanh()", "atanh")}; + +const ToolboxNode menu[11] = {ToolboxNode("abs()", "Valeur absolue"), ToolboxNode("root(,)", "Racine k-ieme"), ToolboxNode("log(,)", "Logarithme base a"), + ToolboxNode("Calcul", nullptr, calculChildren, 4), ToolboxNode("Nombre complexe", nullptr, complexChildren, 5), + ToolboxNode("Probabilite", nullptr, probabilityChildren, 4), ToolboxNode("Arithmetique", nullptr, arithmeticChildren, 4), + ToolboxNode("Matrice", nullptr, matricesChildren, 5), ToolboxNode("Liste", nullptr, listesChildren, 5), + ToolboxNode("Approximation", nullptr, approximationChildren, 4), ToolboxNode("Trigonometrie", nullptr, trigonometryChildren, 6)}; +const ToolboxNode toolboxModel = ToolboxNode("Toolbox", nullptr, menu, 11); + +/* State */ + +MathToolbox::Stack::State::State(int selectedRow, KDCoordinate verticalScroll) : + m_selectedRow(selectedRow), + m_verticalScroll(verticalScroll) +{ +} + +int MathToolbox::Stack::State::selectedRow() { + return m_selectedRow; +} + +KDCoordinate MathToolbox::Stack::State::verticalScroll() { + return m_verticalScroll; +} + +bool MathToolbox::Stack::State::isNull(){ + if (m_selectedRow == -1) { + return true; + } + return false; +} + +/* Stack */ + +void MathToolbox::Stack::push(int selectedRow, KDCoordinate verticalScroll) { + int i = 0; + while (!m_statesStack[i].isNull() && i < k_maxModelTreeDepth) { + i++; + } + assert(m_statesStack[i].isNull()); + m_statesStack[i] = State(selectedRow, verticalScroll); +} + +MathToolbox::Stack::State * MathToolbox::Stack::stateAtIndex(int index) { + return &m_statesStack[index]; +} + +int MathToolbox::Stack::depth() { + int depth = 0; + for (int i = 0; i < k_maxModelTreeDepth; i++) { + depth += (!m_statesStack[i].isNull()); + } + return depth; +} + +void MathToolbox::Stack::pop() { + int stackDepth = depth(); + if (stackDepth == 0) { + return; + } + m_statesStack[stackDepth-1] = State(); +} + +void MathToolbox::Stack::resetStack() { + for (int i = 0; i < k_maxModelTreeDepth; i++) { + m_statesStack[i] = State(); + } +} + +/* List Controller */ + +MathToolbox::ListController::ListController(Responder * parentResponder, SelectableTableView * tableView) : + ViewController(parentResponder), + m_selectableTableView(tableView), + m_firstSelectedRow(0) +{ +} + +View * MathToolbox::ListController::view() { + return m_selectableTableView; +} + +const char * MathToolbox::ListController::title() const { + return toolboxModel.label(); +} + +void MathToolbox::ListController::didBecomeFirstResponder() { + m_selectableTableView->reloadData(); + m_selectableTableView->selectCellAtLocation(0, m_firstSelectedRow); + app()->setFirstResponder(m_selectableTableView); +} + +void MathToolbox::ListController::setFirstSelectedRow(int firstSelectedRow) { + m_firstSelectedRow = firstSelectedRow; +} + +/* MathToolbox */ + +MathToolbox::MathToolbox() : + Toolbox(nullptr, &m_listController), + m_selectableTableView(SelectableTableView(&m_listController, this, 0, 0, 0, 0, nullptr, false)), + m_listController(this, &m_selectableTableView), + m_nodeModel(nullptr) +{ +} + +void MathToolbox::didBecomeFirstResponder() { + m_nodeModel = (ToolboxNode *)rootModel(); + StackViewController::didBecomeFirstResponder(); + m_stack.resetStack(); + m_listController.setFirstSelectedRow(0); + app()->setFirstResponder(&m_listController); +} + +bool MathToolbox::handleEvent(Ion::Events::Event event) { + if (event == Ion::Events::Back) { + return returnToPreviousMenu(); + } + if (event == Ion::Events::OK) { + int selectedRow = m_selectableTableView.selectedRow(); + ToolboxNode * selectedNode = (ToolboxNode *)m_nodeModel->children(selectedRow); + if (selectedNode->numberOfChildren() == 0) { + return selectLeaf(selectedNode); + } + return selectSubMenu(selectedNode); + } + return false; +} + +int MathToolbox::numberOfRows() { + return m_nodeModel->numberOfChildren(); +} + +TableViewCell * MathToolbox::reusableCell(int index, int type) { + assert(type < 2); + assert(index >= 0); + assert(index < k_maxNumberOfDisplayedRows); + if (type == 0) { + return &m_leafCells[index]; + } + return &m_nodeCells[index]; +} + +int MathToolbox::reusableCellCount(int type) { + assert(type < 2); + return k_maxNumberOfDisplayedRows; +} + +void MathToolbox::willDisplayCellForIndex(TableViewCell * cell, int index) { + ToolboxNode * node = (ToolboxNode *)m_nodeModel->children(index); + if (node->numberOfChildren() == 0) { + ToolboxLeafCell * myCell = (ToolboxLeafCell *)cell; + myCell->setLabel(node->label()); + myCell->setSubtitle(node->text()); + return; + } + MenuListCell * myCell = (MenuListCell *)cell; + myCell->setText(node->label()); +} + +KDCoordinate MathToolbox::rowHeight(int j) { + if (typeAtLocation(0, j) == 0) { + return k_leafRowHeight; + } + return k_nodeRowHeight; +} + +KDCoordinate MathToolbox::cumulatedHeightFromIndex(int j) { + int result = 0; + for (int k = 0; k < j; k++) { + result += rowHeight(k); + } + return result; +} + +int MathToolbox::indexFromCumulatedHeight(KDCoordinate offsetY) { + int result = 0; + int j = 0; + while (result < offsetY && j < numberOfRows()) { + result += rowHeight(j++); + } + return (result < offsetY || offsetY == 0) ? j : j - 1; +} + +int MathToolbox::typeAtLocation(int i, int j) { + Node * node = (Node *)m_nodeModel->children(j); + if (node->numberOfChildren() == 0) { + return 0; + } + return 1; +} + +void MathToolbox::viewWillDisappear() { + m_selectableTableView.deselectTable(); +} + +TextField * MathToolbox::sender() { + return (TextField *)Toolbox::sender(); +} + +const ToolboxNode * MathToolbox::rootModel() { + return &toolboxModel; +} + +bool MathToolbox::selectLeaf(ToolboxNode * selectedNode){ + m_selectableTableView.deselectTable(); + ToolboxNode * node = selectedNode; + const char * editedText = node->label(); + if (!sender()->isEditing()) { + sender()->setEditing(true); + } + sender()->insertTextAtLocation(editedText, sender()->cursorLocation()); + int cursorDelta = 0; + int editedTextLength = strlen(editedText); + for (int i = 0; i < editedTextLength; i++) { + if (editedText[i] == '(') { + cursorDelta = i + 1; + break; + } + } + sender()->setCursorLocation(sender()->cursorLocation()+cursorDelta); + app()->dismissModalViewController(); + return true; +} + +bool MathToolbox::returnToPreviousMenu() { + m_selectableTableView.deselectTable(); + int depth = m_stack.depth(); + if (depth == 0) { + app()->dismissModalViewController(); + return true; + } + int index = 0; + ToolboxNode * parentNode = (ToolboxNode *)rootModel(); + Stack::State * previousState = m_stack.stateAtIndex(index++);; + while (depth-- > 1) { + parentNode = (ToolboxNode *)parentNode->children(previousState->selectedRow()); + previousState = m_stack.stateAtIndex(index++); + } + m_selectableTableView.deselectTable(); + m_nodeModel = parentNode; + m_listController.setFirstSelectedRow(previousState->selectedRow()); + KDPoint scroll = m_selectableTableView.contentOffset(); + m_selectableTableView.setContentOffset(KDPoint(scroll.x(), previousState->verticalScroll())); + m_stack.pop(); + app()->setFirstResponder(&m_listController); + return true; +} + +bool MathToolbox::selectSubMenu(ToolboxNode * selectedNode) { + m_stack.push(m_selectableTableView.selectedRow(), m_selectableTableView.contentOffset().y()); + m_selectableTableView.deselectTable(); + m_nodeModel = selectedNode; + m_listController.setFirstSelectedRow(0); + app()->setFirstResponder(&m_listController); + return true; +} diff --git a/apps/math_toolbox.h b/apps/math_toolbox.h new file mode 100644 index 000000000..968f9e931 --- /dev/null +++ b/apps/math_toolbox.h @@ -0,0 +1,77 @@ +#ifndef APPS_MATH_TOOLBOX_H +#define APPS_MATH_TOOLBOX_H + +#include +#include "toolbox_node.h" +#include "toolbox_leaf_cell.h" + +/* m_nodeModel points at the node of the tree (describing the whole model) + * where we are located. It enables to know which rows are leaves and which are + * subtrees. */ + +class MathToolbox : public Toolbox, public ListViewDataSource { +public: + MathToolbox(); + void didBecomeFirstResponder() override; + bool handleEvent(Ion::Events::Event event) override; + + int numberOfRows() override; + TableViewCell * reusableCell(int index, int type) override; + int reusableCellCount(int type) override; + void willDisplayCellForIndex(TableViewCell * cell, int index) override; + KDCoordinate rowHeight(int j) override; + KDCoordinate cumulatedHeightFromIndex(int j) override; + int indexFromCumulatedHeight(KDCoordinate offsetY) override; + int typeAtLocation(int i, int j) override; + + void viewWillDisappear() override; +private: + class Stack { + public: + class State { + public: + State(int selectedRow = -1, KDCoordinate verticalScroll = 0); + bool isNull(); + int selectedRow(); + KDCoordinate verticalScroll(); + private: + int m_selectedRow; + KDCoordinate m_verticalScroll; + }; + void push(int selectedRow, KDCoordinate verticalScroll); + void pop(); + State * stateAtIndex(int index); + int depth(); + void resetStack(); + private: + constexpr static int k_maxModelTreeDepth = 2; + State m_statesStack[k_maxModelTreeDepth]; + }; + class ListController : public ViewController { + public: + ListController(Responder * parentResponder, SelectableTableView * tableView); + const char * title() const override; + View * view() override; + void didBecomeFirstResponder() override; + void setFirstSelectedRow(int firstSelectedRow); + private: + SelectableTableView * m_selectableTableView; + int m_firstSelectedRow; + }; + 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); + bool returnToPreviousMenu(); + Stack m_stack; + ToolboxLeafCell m_leafCells[k_maxNumberOfDisplayedRows]; + ChevronMenuListCell m_nodeCells[k_maxNumberOfDisplayedRows]; + SelectableTableView m_selectableTableView; + ListController m_listController; + ToolboxNode * m_nodeModel; +}; + +#endif diff --git a/apps/node_list_view_controller.cpp b/apps/node_list_view_controller.cpp deleted file mode 100644 index df4f3d9b3..000000000 --- a/apps/node_list_view_controller.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "node_list_view_controller.h" -#include "toolbox_node.h" -#include -#include - -NodeListViewController::NodeListViewController(Responder * parentResponder) : - ViewController(parentResponder), - m_selectableTableView(SelectableTableView(this, this, 0, 0, 0, 0, nullptr, false)), - m_nodeModel(nullptr), - m_firstSelectedRow(0) -{ -} - -View * NodeListViewController::view() { - return &m_selectableTableView; -} - -const char * NodeListViewController::title() const { - return m_nodeModel->label(); -} - -Node * NodeListViewController::nodeModel() { - return m_nodeModel; -} - -void NodeListViewController::setNodeModel(Node * nodeModel) { - m_nodeModel = nodeModel; - m_selectableTableView.reloadData(); -} - -void NodeListViewController::setFirstSelectedRow(int firstSelectedRow) { - m_firstSelectedRow = firstSelectedRow; -} - -int NodeListViewController::selectedRow() { - return m_selectableTableView.selectedRow(); -} - -void NodeListViewController::setVerticalScroll(KDCoordinate verticalScroll) { - KDPoint scroll = m_selectableTableView.contentOffset(); - m_selectableTableView.setContentOffset(KDPoint(scroll.x(), verticalScroll)); -} - -KDCoordinate NodeListViewController::verticalScroll() { - return m_selectableTableView.contentOffset().y(); -} - -void NodeListViewController::deselectTable() { - m_selectableTableView.deselectTable(); -} - -void NodeListViewController::didBecomeFirstResponder() { - m_selectableTableView.reloadData(); - m_selectableTableView.selectCellAtLocation(0, m_firstSelectedRow); - app()->setFirstResponder(&m_selectableTableView); -} - -int NodeListViewController::numberOfRows() { - return m_nodeModel->numberOfChildren(); -} - -TableViewCell * NodeListViewController::reusableCell(int index, int type) { - assert(type < 2); - assert(index >= 0); - assert(index < k_maxNumberOfDisplayedRows); - if (type == 0) { - return &m_leafCells[index]; - } - return &m_nodeCells[index]; -} - -int NodeListViewController::reusableCellCount(int type) { - assert(type < 2); - return k_maxNumberOfDisplayedRows; -} - -void NodeListViewController::willDisplayCellForIndex(TableViewCell * cell, int index) { - ToolboxNode * node = (ToolboxNode *)m_nodeModel->children(index); - if (node->numberOfChildren() == 0) { - ToolboxLeafCell * myCell = (ToolboxLeafCell *)cell; - myCell->setLabel(node->label()); - myCell->setSubtitle(node->text()); - return; - } - MenuListCell * myCell = (MenuListCell *)cell; - myCell->setText(node->label()); -} - -KDCoordinate NodeListViewController::rowHeight(int j) { - if (typeAtLocation(0, j) == 0) { - return k_leafRowHeight; - } - return k_nodeRowHeight; -} - -KDCoordinate NodeListViewController::cumulatedHeightFromIndex(int j) { - int result = 0; - for (int k = 0; k < j; k++) { - result += rowHeight(k); - } - return result; -} - -int NodeListViewController::indexFromCumulatedHeight(KDCoordinate offsetY) { - int result = 0; - int j = 0; - while (result < offsetY && j < numberOfRows()) { - result += rowHeight(j++); - } - return (result < offsetY || offsetY == 0) ? j : j - 1; -} - -int NodeListViewController::typeAtLocation(int i, int j) { - Node * node = (Node *)m_nodeModel->children(j); - if (node->numberOfChildren() == 0) { - return 0; - } - return 1; -} diff --git a/apps/node_list_view_controller.h b/apps/node_list_view_controller.h deleted file mode 100644 index 4b7f0eca6..000000000 --- a/apps/node_list_view_controller.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef APPS_NODE_LIST_VIEW_CONTROLLER_H -#define APPS_NODE_LIST_VIEW_CONTROLLER_H - -#include -#include "node.h" -#include "toolbox_leaf_cell.h" - -/* m_nodeModel points at the node of the tree (describing the whole model) - * where we are located. It enables to know which rows are leaves and which are - * subtrees. */ - -class NodeNavigationController; - -class NodeListViewController : public ViewController, public ListViewDataSource { -public: - NodeListViewController(Responder * parentResponder); - View * view() override; - const char * title() const override; - void didBecomeFirstResponder() override; - - int numberOfRows() override; - TableViewCell * reusableCell(int index, int type) override; - int reusableCellCount(int type) override; - void willDisplayCellForIndex(TableViewCell * cell, int index) override; - KDCoordinate rowHeight(int j) override; - KDCoordinate cumulatedHeightFromIndex(int j) override; - int indexFromCumulatedHeight(KDCoordinate offsetY) override; - int typeAtLocation(int i, int j) override; - - void setNodeModel(Node * nodeModel); - Node * nodeModel(); - void setFirstSelectedRow(int firstSelectedRow); - int selectedRow(); - void setVerticalScroll(KDCoordinate verticalScroll); - KDCoordinate verticalScroll(); - void deselectTable(); -private: - constexpr static KDCoordinate k_nodeRowHeight = 40; - constexpr static KDCoordinate k_leafRowHeight = 40; - constexpr static int k_maxNumberOfDisplayedRows = 6; //240/40 - ToolboxLeafCell m_leafCells[k_maxNumberOfDisplayedRows]; - ChevronMenuListCell m_nodeCells[k_maxNumberOfDisplayedRows]; - SelectableTableView m_selectableTableView; - Node * m_nodeModel; - int m_firstSelectedRow; -}; - -#endif diff --git a/apps/shared/expression_text_field_delegate.cpp b/apps/shared/expression_text_field_delegate.cpp index 640b8af32..3961b7884 100644 --- a/apps/shared/expression_text_field_delegate.cpp +++ b/apps/shared/expression_text_field_delegate.cpp @@ -51,8 +51,8 @@ bool ExpressionTextFieldDelegate::textFieldDidReceiveEvent(TextField * textField } if (event == Ion::Events::Toolbox) { AppsContainer * appsContainer = (AppsContainer *)textField->app()->container(); - ToolboxController * toolboxController = appsContainer->toolboxController(); - toolboxController->setTextFieldCaller(textField); + MathToolbox * toolboxController = appsContainer->mathToolbox(); + toolboxController->setSender(textField); textField->app()->displayModalViewController(toolboxController, 0.f, 0.f, 50, 50, 0, 50); return true; } diff --git a/apps/toolbox_controller.cpp b/apps/toolbox_controller.cpp deleted file mode 100644 index b77edfb2f..000000000 --- a/apps/toolbox_controller.cpp +++ /dev/null @@ -1,184 +0,0 @@ -#include "toolbox_controller.h" -#include "toolbox_node.h" -#include - -/* TODO: find a shorter way to initiate 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 nullptr. */ - -const ToolboxNode calculChildren[4] = {ToolboxNode("diff(,)", "Nombre derive"), ToolboxNode("int(,,)", "Integrale"), ToolboxNode("sum(,,)", "Somme"), ToolboxNode("product(,,)", "Produit")}; -const ToolboxNode complexChildren[5] = {ToolboxNode("abs()", "Module"), ToolboxNode("arg()", "Argument"), ToolboxNode("re()", "Partie reelle"), ToolboxNode("im()", "Partie imaginaire"), ToolboxNode("conj()", "Conjugue")}; -const ToolboxNode probabilityChildren[4] = {ToolboxNode("binomial()", "Combinaison"), ToolboxNode("permute(,)", "Arrangement"), ToolboxNode("random(,)", "Nombre aleatoire"), ToolboxNode("gamma()", "Fonction gamma")}; -const ToolboxNode arithmeticChildren[4] = {ToolboxNode("gcd()", "PGCD"), ToolboxNode("lcm()", "PPCM"), ToolboxNode("rem()", "Reste division euclidienne"), ToolboxNode("quo()","Quotien division euclidienne")}; -const ToolboxNode matricesChildren[5] = {ToolboxNode("inverse()", "Inverse"), ToolboxNode("det()", "Determinant"), ToolboxNode("transpose()", "Transposee"), ToolboxNode("trace()", "Trace"), ToolboxNode("dim()", "Taille")}; -const ToolboxNode listesChildren[5] = {ToolboxNode("sort<()", "Tri croissant"), ToolboxNode("sort>()", "Tri decroissant"), ToolboxNode("max()", "Maximum"), ToolboxNode("min()", "Minimum"), ToolboxNode("dim()", "Taille")}; -const ToolboxNode approximationChildren[4] = {ToolboxNode("floor()", "Partie entiere"), ToolboxNode("frac()", "Partie fractionnaire"), ToolboxNode("ceil()", "Plafond"), ToolboxNode("round(,)", "Arrondi")}; -const ToolboxNode trigonometryChildren[6] = {ToolboxNode("cosh()", "cosh"), ToolboxNode("sinh()", "sinh"), ToolboxNode("tanh()", "tanh"), ToolboxNode("acosh()", "acosh"), ToolboxNode("asinh()", "asinh"), ToolboxNode("atanh()", "atanh")}; - -const ToolboxNode menu[11] = {ToolboxNode("abs()", "Valeur absolue"), ToolboxNode("root(,)", "Racine k-ieme"), ToolboxNode("log(,)", "Logarithme base a"), - ToolboxNode("Calcul", nullptr, calculChildren, 4), ToolboxNode("Nombre complexe", nullptr, complexChildren, 5), - ToolboxNode("Probabilite", nullptr, probabilityChildren, 4), ToolboxNode("Arithmetique", nullptr, arithmeticChildren, 4), - ToolboxNode("Matrice", nullptr, matricesChildren, 5), ToolboxNode("Liste", nullptr, listesChildren, 5), - ToolboxNode("Approximation", nullptr, approximationChildren, 4), ToolboxNode("Trigonometrie", nullptr, trigonometryChildren, 6)}; -const ToolboxNode toolboxModel = ToolboxNode("Toolbox", nullptr, menu, 11); - -/* State */ - -ToolboxController::Stack::State::State(int selectedRow, KDCoordinate verticalScroll) : - m_selectedRow(selectedRow), - m_verticalScroll(verticalScroll) -{ -} - -int ToolboxController::Stack::State::selectedRow() { - return m_selectedRow; -} - -KDCoordinate ToolboxController::Stack::State::verticalScroll() { - return m_verticalScroll; -} - -bool ToolboxController::Stack::State::isNull(){ - if (m_selectedRow == -1) { - return true; - } - return false; -} - -/* Stack */ - -void ToolboxController::Stack::push(int selectedRow, KDCoordinate verticalScroll) { - int i = 0; - while (!m_statesStack[i].isNull() && i < k_maxModelTreeDepth) { - i++; - } - assert(m_statesStack[i].isNull()); - m_statesStack[i] = State(selectedRow, verticalScroll); -} - -ToolboxController::Stack::State * ToolboxController::Stack::stateAtIndex(int index) { - return &m_statesStack[index]; -} - -int ToolboxController::Stack::depth() { - int depth = 0; - for (int i = 0; i < k_maxModelTreeDepth; i++) { - depth += (!m_statesStack[i].isNull()); - } - return depth; -} - -void ToolboxController::Stack::pop() { - int stackDepth = depth(); - if (stackDepth == 0) { - return; - } - m_statesStack[stackDepth-1] = State(); -} - -void ToolboxController::Stack::resetStack() { - for (int i = 0; i < k_maxModelTreeDepth; i++) { - m_statesStack[i] = State(); - } -} - -/* ToolboxController */ - -ToolboxController::ToolboxController() : - StackViewController(nullptr, &m_listViewController, true, KDColorWhite, Palette::PurpleBright, Palette::PurpleDark), - m_listViewController(NodeListViewController(this)) -{ -} - -const char * ToolboxController::title() const { - return "ToolboxController"; -} - -bool ToolboxController::handleEvent(Ion::Events::Event event) { - if (event == Ion::Events::Back) { - return returnToPreviousMenu(); - } - if (event == Ion::Events::OK) { - int selectedRow = m_listViewController.selectedRow(); - Node * selectedNode = (Node *)m_listViewController.nodeModel()->children(selectedRow); - if (selectedNode->numberOfChildren() == 0) { - return selectLeaf(selectedNode); - } - return selectSubMenu(selectedNode); - } - return false; -} - -void ToolboxController::didBecomeFirstResponder() { - m_listViewController.setNodeModel(rootModel()); - StackViewController::didBecomeFirstResponder(); - m_stack.resetStack(); - m_listViewController.setFirstSelectedRow(0); - app()->setFirstResponder(&m_listViewController); -} - -void ToolboxController::viewWillDisappear() { - m_listViewController.deselectTable(); -} - -void ToolboxController::setTextFieldCaller(TextField * textField) { - m_textFieldCaller = textField; -} - -Node * ToolboxController::rootModel() { - return (Node *)&toolboxModel; -} - -bool ToolboxController::selectLeaf(Node * selectedNode){ - m_listViewController.deselectTable(); - ToolboxNode * node = (ToolboxNode *)selectedNode; - const char * editedText = node->label(); - if (!m_textFieldCaller->isEditing()) { - m_textFieldCaller->setEditing(true); - } - m_textFieldCaller->insertTextAtLocation(editedText, m_textFieldCaller->cursorLocation()); - int cursorDelta = 0; - int editedTextLength = strlen(editedText); - for (int i = 0; i < editedTextLength; i++) { - if (editedText[i] == '(') { - cursorDelta = i + 1; - break; - } - } - m_textFieldCaller->setCursorLocation(m_textFieldCaller->cursorLocation()+cursorDelta); - app()->dismissModalViewController(); - return true; -} - -bool ToolboxController::returnToPreviousMenu() { - m_listViewController.deselectTable(); - int depth = m_stack.depth(); - if (depth == 0) { - app()->dismissModalViewController(); - return true; - } - int index = 0; - Node * parentNode = rootModel(); - Stack::State * previousState = m_stack.stateAtIndex(index++);; - while (depth-- > 1) { - parentNode = (Node *)parentNode->children(previousState->selectedRow()); - previousState = m_stack.stateAtIndex(index++); - } - m_listViewController.deselectTable(); - m_listViewController.setNodeModel(parentNode); - m_listViewController.setFirstSelectedRow(previousState->selectedRow()); - m_listViewController.setVerticalScroll(previousState->verticalScroll()); - m_stack.pop(); - app()->setFirstResponder(&m_listViewController); - return true; -} - -bool ToolboxController::selectSubMenu(Node * selectedNode) { - m_stack.push(m_listViewController.selectedRow(), m_listViewController.verticalScroll()); - m_listViewController.deselectTable(); - m_listViewController.setNodeModel(selectedNode); - m_listViewController.setFirstSelectedRow(0); - app()->setFirstResponder(&m_listViewController); - return true; -} diff --git a/apps/toolbox_controller.h b/apps/toolbox_controller.h deleted file mode 100644 index 19c1a2d87..000000000 --- a/apps/toolbox_controller.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef APPS_TOOLBOX_CONTROLLER_H -#define APPS_TOOLBOX_CONTROLLER_H - -#include -#include "node.h" -#include "node_list_view_controller.h" - -class ToolboxController : public StackViewController { -public: - ToolboxController(); - const char * title() const override; - bool handleEvent(Ion::Events::Event event) override; - void didBecomeFirstResponder() override; - void viewWillDisappear() override; - void setTextFieldCaller(TextField * textField); -private: - class Stack { - public: - class State { - public: - State(int selectedRow = -1, KDCoordinate verticalScroll = 0); - bool isNull(); - int selectedRow(); - KDCoordinate verticalScroll(); - private: - int m_selectedRow; - KDCoordinate m_verticalScroll; - }; - void push(int selectedRow, KDCoordinate verticalScroll); - void pop(); - State * stateAtIndex(int index); - int depth(); - void resetStack(); - private: - constexpr static int k_maxModelTreeDepth = 2; - State m_statesStack[k_maxModelTreeDepth]; - }; - TextField * m_textFieldCaller; - NodeListViewController m_listViewController; - Node * rootModel(); - bool selectLeaf(Node * selectedNode); - bool selectSubMenu(Node * selectedNode); - bool returnToPreviousMenu(); - Stack m_stack; -}; - -#endif diff --git a/escher/Makefile b/escher/Makefile index 0a1555388..338484ac8 100644 --- a/escher/Makefile +++ b/escher/Makefile @@ -52,6 +52,7 @@ objs += $(addprefix escher/src/,\ text_menu_list_cell.o\ text_view.o\ tiled_view.o\ + toolbox.o\ view.o\ view_controller.o\ warning_controller.o\ diff --git a/escher/include/escher.h b/escher/include/escher.h index efae858c8..2f57c92ad 100644 --- a/escher/include/escher.h +++ b/escher/include/escher.h @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include diff --git a/escher/include/escher/toolbox.h b/escher/include/escher/toolbox.h new file mode 100644 index 000000000..00d7bb29b --- /dev/null +++ b/escher/include/escher/toolbox.h @@ -0,0 +1,17 @@ +#ifndef ESCHER_TOOLBOX_H +#define ESCHER_TOOLBOX_H + +#include + +class Toolbox : public StackViewController { +public: + Toolbox(Responder * parentResponder, ViewController * rootViewController); + void setSender(Responder * sender); +protected: + virtual Responder * sender(); +private: + Responder * m_sender; +}; + + +#endif diff --git a/escher/src/toolbox.cpp b/escher/src/toolbox.cpp new file mode 100644 index 000000000..a8a5c919c --- /dev/null +++ b/escher/src/toolbox.cpp @@ -0,0 +1,15 @@ +#include + +Toolbox::Toolbox(Responder * parentResponder, ViewController * rootViewController) : + StackViewController(parentResponder, rootViewController, true, KDColorWhite, Palette::PurpleBright, Palette::PurpleDark), + m_sender(nullptr) +{ +} + +void Toolbox::setSender(Responder * sender) { + m_sender = sender; +} + +Responder * Toolbox::sender() { + return m_sender; +}