[apps] make a parent class node navigation controller to navigate in a

tree model

Change-Id: Ib5671c688237435c6da3b1f1e5cd715671e75cd9
This commit is contained in:
Émilie Feral
2016-11-09 14:50:13 +01:00
parent 2561f6fd3c
commit e1dbfbe51c
5 changed files with 191 additions and 164 deletions

View File

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

View File

@@ -0,0 +1,136 @@
#include "node_navigation_controller.h"
#include <assert.h>
#include <string.h>
/* 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;
}

View File

@@ -0,0 +1,47 @@
#ifndef APPS_NODE_NAVIGATION_CONTROLLER_H
#define APPS_NODE_NAVIGATION_CONTROLLER_H
#include <escher.h>
#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

View File

@@ -1,6 +1,4 @@
#include "tool_box_controller.h"
#include <assert.h>
#include <string.h>
/* 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;
}

View File

@@ -2,44 +2,14 @@
#define APPS_TOOL_BOX_CONTROLLER_H
#include <escher.h>
#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