diff --git a/apps/Makefile b/apps/Makefile index 7fefeb149..efba9b037 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -11,6 +11,7 @@ app_objs += $(addprefix apps/,\ main.o\ node.o\ node_list_view_controller.o\ + node_navigation_controller.o\ tool_box_controller.o\ ) diff --git a/apps/node_navigation_controller.cpp b/apps/node_navigation_controller.cpp new file mode 100644 index 000000000..3b94492be --- /dev/null +++ b/apps/node_navigation_controller.cpp @@ -0,0 +1,136 @@ +#include "node_navigation_controller.h" +#include +#include + +/* State */ + +NodeNavigationController::Stack::State::State(int selectedRow, KDCoordinate verticalScroll) : + m_selectedRow(selectedRow), + m_verticalScroll(verticalScroll) +{ +} + +int NodeNavigationController::Stack::State::selectedRow() { + return m_selectedRow; +} + +KDCoordinate NodeNavigationController::Stack::State::verticalScroll() { + return m_verticalScroll; +} + +bool NodeNavigationController::Stack::State::isNull(){ + if (m_selectedRow == -1) { + return true; + } + return false; +} + +/* Stack */ + +void NodeNavigationController::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); +} + +NodeNavigationController::Stack::State * NodeNavigationController::Stack::stateAtIndex(int index) { + return &m_statesStack[index]; +} + +int NodeNavigationController::Stack::depth() { + int depth = 0; + for (int i = 0; i < k_maxModelTreeDepth; i++) { + depth += (!m_statesStack[i].isNull()); + } + return depth; +} + +void NodeNavigationController::Stack::pop() { + int stackDepth = depth(); + if (stackDepth == 0) { + return; + } + m_statesStack[stackDepth-1] = State(); +} + +void NodeNavigationController::Stack::resetStack() { + for (int i = 0; i < k_maxModelTreeDepth; i++) { + m_statesStack[i] = State(); + } +} + +/* NodeNavigationController */ + +NodeNavigationController::NodeNavigationController() : + StackViewController(nullptr, &m_listViewController, true), + m_listViewController(NodeListViewController(this)) +{ +} + +const char * NodeNavigationController::title() const { + return "NodeNavigationController"; +} + +bool NodeNavigationController::handleEvent(Ion::Events::Event event) { + switch (event) { + case Ion::Events::Event::ESC: + return returnToPreviousMenu(); + case Ion::Events::Event::ENTER: + { + int selectedRow = m_listViewController.selectedRow(); + Node * selectedNode = (Node *)m_listViewController.nodeModel()->children(selectedRow); + if (selectedNode->numberOfChildren() == 0) { + return selectLeaf(selectedNode); + } + return selectSubMenu(selectedNode); + } + default: + return false; + } +} + +bool NodeNavigationController::returnToPreviousMenu() { + m_listViewController.deselectTable(); + int depth = m_stack.depth(); + if (depth == 0) { + app()->dismissModalViewController(); + return true; + } + int index = 0; + Node * parentNode = nodeModel(); + 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 NodeNavigationController::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; +} + +void NodeNavigationController::didBecomeFirstResponder() { + m_stack.resetStack(); + m_listViewController.setNodeModel(nodeModel()); + m_listViewController.setFirstSelectedRow(0); + app()->setFirstResponder(&m_listViewController); +} + +void NodeNavigationController::setTextFieldCaller(TextField * textField) { + m_textFieldCaller = textField; +} diff --git a/apps/node_navigation_controller.h b/apps/node_navigation_controller.h new file mode 100644 index 000000000..7769fb4b9 --- /dev/null +++ b/apps/node_navigation_controller.h @@ -0,0 +1,47 @@ +#ifndef APPS_NODE_NAVIGATION_CONTROLLER_H +#define APPS_NODE_NAVIGATION_CONTROLLER_H + +#include +#include "node.h" +#include "node_list_view_controller.h" + +class NodeNavigationController : public StackViewController { +public: + NodeNavigationController(); + const char * title() const override; + bool handleEvent(Ion::Events::Event event) override; + void didBecomeFirstResponder() override; + void setTextFieldCaller(TextField * textField); +protected: + TextField * m_textFieldCaller; +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]; + }; + virtual Node * nodeModel() = 0; + virtual bool selectLeaf(Node * selectedNode) = 0; + bool selectSubMenu(Node * selectedNode); + bool returnToPreviousMenu(); + NodeListViewController m_listViewController; + Stack m_stack; +}; + +#endif diff --git a/apps/tool_box_controller.cpp b/apps/tool_box_controller.cpp index 61f2c9ce8..d7ad6e0a4 100644 --- a/apps/tool_box_controller.cpp +++ b/apps/tool_box_controller.cpp @@ -1,6 +1,4 @@ #include "tool_box_controller.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 @@ -23,129 +21,15 @@ const Node menu[11] = {Node("|x|", "abs()"), Node("root(x)", "root(,)"), Node("l Node("Approximation", nullptr, approximationChildren, 4), Node("Trigonometrie", nullptr, trigonometryChildren, 6)}; const Node toolBoxModel = Node("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), - m_listViewController(NodeListViewController(this)) -{ -} - const char * ToolBoxController::title() const { return "ToolBoxController"; } -bool ToolBoxController::handleEvent(Ion::Events::Event event) { - switch (event) { - case Ion::Events::Event::ESC: - return returnToPreviousMenu(); - case Ion::Events::Event::ENTER: - { - int selectedRow = m_listViewController.selectedRow(); - Node * selectedNode = (Node *)m_listViewController.nodeModel()->children(selectedRow); - if (selectedNode->numberOfChildren() == 0) { - return editMathFunction(selectedNode); - } - return selectSubMenu(selectedNode); - } - default: - return false; - } +Node * ToolBoxController::nodeModel() { + return (Node *)&toolBoxModel; } -bool ToolBoxController::returnToPreviousMenu() { - m_listViewController.deselectTable(); - int depth = m_stack.depth(); - if (depth == 0) { - app()->dismissModalViewController(); - return true; - } - int index = 0; - Node * parentNode = (Node *)&toolBoxModel; - 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; -} - -bool ToolBoxController::editMathFunction(Node * selectedNode){ +bool ToolBoxController::selectLeaf(Node * selectedNode){ const char * editedText = selectedNode->text(); m_textFieldCaller->appendText(editedText); int cursorPosition = 0; @@ -160,14 +44,3 @@ bool ToolBoxController::editMathFunction(Node * selectedNode){ app()->dismissModalViewController(); return true; } - -void ToolBoxController::didBecomeFirstResponder() { - m_stack.resetStack(); - m_listViewController.setNodeModel((Node *)&toolBoxModel); - m_listViewController.setFirstSelectedRow(0); - app()->setFirstResponder(&m_listViewController); -} - -void ToolBoxController::setTextFieldCaller(TextField * textField) { - m_textFieldCaller = textField; -} diff --git a/apps/tool_box_controller.h b/apps/tool_box_controller.h index 8677b46d4..c61fdba16 100644 --- a/apps/tool_box_controller.h +++ b/apps/tool_box_controller.h @@ -2,44 +2,14 @@ #define APPS_TOOL_BOX_CONTROLLER_H #include -#include "node.h" -#include "node_list_view_controller.h" +#include "node_navigation_controller.h" -class ToolBoxController : public StackViewController { +class ToolBoxController : public NodeNavigationController { public: - ToolBoxController(); const char * title() const override; - bool handleEvent(Ion::Events::Event event) override; - void didBecomeFirstResponder() 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]; - }; - bool editMathFunction(Node * selectedNode); - bool selectSubMenu(Node * selectedNode); - bool returnToPreviousMenu(); - NodeListViewController m_listViewController; - TextField * m_textFieldCaller; - Stack m_stack; + Node * nodeModel() override; + bool selectLeaf(Node * selectedNode) override; }; #endif