[apps] Merge toolboxcontroller and node list controller

Change-Id: Ie273b6d7bca3a035e2420ddb6e66a4163d103748
This commit is contained in:
Émilie Feral
2017-02-15 17:49:01 +01:00
parent dfda0223cc
commit 5b73eed76a
14 changed files with 392 additions and 407 deletions

View File

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

View File

@@ -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() {

View File

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

273
apps/math_toolbox.cpp Normal file
View File

@@ -0,0 +1,273 @@
#include "math_toolbox.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
* 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;
}

77
apps/math_toolbox.h Normal file
View File

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

View File

@@ -1,119 +0,0 @@
#include "node_list_view_controller.h"
#include "toolbox_node.h"
#include <assert.h>
#include <string.h>
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;
}

View File

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

View File

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

View File

@@ -1,184 +0,0 @@
#include "toolbox_controller.h"
#include "toolbox_node.h"
#include <assert.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
* 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;
}

View File

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

View File

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

View File

@@ -53,6 +53,7 @@
#include <escher/table_view_cell.h>
#include <escher/table_view_data_source.h>
#include <escher/tiled_view.h>
#include <escher/toolbox.h>
#include <escher/view.h>
#include <escher/view_controller.h>
#include <escher/warning_controller.h>

View File

@@ -0,0 +1,17 @@
#ifndef ESCHER_TOOLBOX_H
#define ESCHER_TOOLBOX_H
#include <escher/stack_view_controller.h>
class Toolbox : public StackViewController {
public:
Toolbox(Responder * parentResponder, ViewController * rootViewController);
void setSender(Responder * sender);
protected:
virtual Responder * sender();
private:
Responder * m_sender;
};
#endif

15
escher/src/toolbox.cpp Normal file
View File

@@ -0,0 +1,15 @@
#include <escher/toolbox.h>
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;
}