[escher/apps] Factorization of Toolbox.

MathToolbox methods moved to its parent, Toolbox (in escher).
Node and ToolboxNode classes renamed MessageTree and ToolboxMessageTree.
They are now in escher/, not in apps/.

Change-Id: Ibb26b0e9016094cef79506a1e9fc6dfb492d7103
This commit is contained in:
Léa Saviot
2017-10-31 15:18:09 +01:00
committed by Romain Goyet
parent fc603df886
commit 68e237702b
24 changed files with 510 additions and 485 deletions

View File

@@ -36,11 +36,9 @@ app_objs += $(addprefix apps/,\
lock_view.o\
main.o\
math_toolbox.o\
node.o\
shift_alpha_lock_view.o\
suspend_timer.o\
title_bar_view.o\
toolbox_node.o\
usb_timer.o\
variable_box_controller.o\
variable_box_leaf_cell.o\

View File

@@ -7,270 +7,69 @@
* and the text which would be edited by clicking on the row. When the node is a
* subtree, the edited text is set at I18n::Message::Default. */
const ToolboxNode calculChildren[4] = {ToolboxNode(I18n::Message::DiffCommandWithArg, I18n::Message::DerivateNumber, I18n::Message::DiffCommand), ToolboxNode(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommand), ToolboxNode(I18n::Message::SumCommandWithArg, I18n::Message::Sum, I18n::Message::SumCommand), ToolboxNode(I18n::Message::ProductCommandWithArg, I18n::Message::Product, I18n::Message::ProductCommand)};
const ToolboxNode complexChildren[5] = {ToolboxNode(I18n::Message::AbsCommandWithArg, I18n::Message::ComplexAbsoluteValue, I18n::Message::AbsCommand), ToolboxNode(I18n::Message::ArgCommandWithArg, I18n::Message::Agument, I18n::Message::ArgCommand), ToolboxNode(I18n::Message::ReCommandWithArg, I18n::Message::RealPart, I18n::Message::ReCommand), ToolboxNode(I18n::Message::ImCommandWithArg, I18n::Message::ImaginaryPart, I18n::Message::ImCommand), ToolboxNode(I18n::Message::ConjCommandWithArg, I18n::Message::Conjugate, I18n::Message::ConjCommand)};
const ToolboxNode probabilityChildren[2] = {ToolboxNode(I18n::Message::BinomialCommandWithArg, I18n::Message::Combination, I18n::Message::BinomialCommand), ToolboxNode(I18n::Message::PermuteCommandWithArg, I18n::Message::Permutation, I18n::Message::PermuteCommand)};
const ToolboxNode arithmeticChildren[4] = {ToolboxNode(I18n::Message::GcdCommandWithArg, I18n::Message::GreatCommonDivisor, I18n::Message::GcdCommand),ToolboxNode(I18n::Message::LcmCommandWithArg, I18n::Message::LeastCommonMultiple, I18n::Message::LcmCommand), ToolboxNode(I18n::Message::RemCommandWithArg, I18n::Message::Remainder, I18n::Message::RemCommand), ToolboxNode(I18n::Message::QuoCommandWithArg, I18n::Message::Quotient, I18n::Message::QuoCommand)};
const ToolboxMessageTree calculChildren[4] = {ToolboxMessageTree(I18n::Message::DiffCommandWithArg, I18n::Message::DerivateNumber, I18n::Message::DiffCommand), ToolboxMessageTree(I18n::Message::IntCommandWithArg, I18n::Message::Integral, I18n::Message::IntCommand), ToolboxMessageTree(I18n::Message::SumCommandWithArg, I18n::Message::Sum, I18n::Message::SumCommand), ToolboxMessageTree(I18n::Message::ProductCommandWithArg, I18n::Message::Product, I18n::Message::ProductCommand)};
const ToolboxMessageTree complexChildren[5] = {ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::ComplexAbsoluteValue, I18n::Message::AbsCommand), ToolboxMessageTree(I18n::Message::ArgCommandWithArg, I18n::Message::Agument, I18n::Message::ArgCommand), ToolboxMessageTree(I18n::Message::ReCommandWithArg, I18n::Message::RealPart, I18n::Message::ReCommand), ToolboxMessageTree(I18n::Message::ImCommandWithArg, I18n::Message::ImaginaryPart, I18n::Message::ImCommand), ToolboxMessageTree(I18n::Message::ConjCommandWithArg, I18n::Message::Conjugate, I18n::Message::ConjCommand)};
const ToolboxMessageTree probabilityChildren[2] = {ToolboxMessageTree(I18n::Message::BinomialCommandWithArg, I18n::Message::Combination, I18n::Message::BinomialCommand), ToolboxMessageTree(I18n::Message::PermuteCommandWithArg, I18n::Message::Permutation, I18n::Message::PermuteCommand)};
const ToolboxMessageTree arithmeticChildren[4] = {ToolboxMessageTree(I18n::Message::GcdCommandWithArg, I18n::Message::GreatCommonDivisor, I18n::Message::GcdCommand),ToolboxMessageTree(I18n::Message::LcmCommandWithArg, I18n::Message::LeastCommonMultiple, I18n::Message::LcmCommand), ToolboxMessageTree(I18n::Message::RemCommandWithArg, I18n::Message::Remainder, I18n::Message::RemCommand), ToolboxMessageTree(I18n::Message::QuoCommandWithArg, I18n::Message::Quotient, I18n::Message::QuoCommand)};
#if MATRICES_ARE_DEFINED
const ToolboxNode matricesChildren[5] = {ToolboxNode(I18n::Message::InverseCommandWithArg, I18n::Message::Inverse, I18n::Message::InverseCommand), ToolboxNode(I18n::Message::DeterminantCommandWithArg, I18n::Message::Determinant, I18n::Message::DeterminantCommand), ToolboxNode(I18n::Message::TransposeCommandWithArg, I18n::Message::Transpose, I18n::Message::TransposeCommand), ToolboxNode(I18n::Message::TraceCommandWithArg, I18n::Message::Trace, I18n::Message::TraceCommand), ToolboxNode(I18n::Message::DimensionCommandWithArg, I18n::Message::Dimension, I18n::Message::DimensionCommand)};
const ToolboxMessageTree matricesChildren[5] = {ToolboxMessageTree(I18n::Message::InverseCommandWithArg, I18n::Message::Inverse, I18n::Message::InverseCommand), ToolboxMessageTree(I18n::Message::DeterminantCommandWithArg, I18n::Message::Determinant, I18n::Message::DeterminantCommand), ToolboxMessageTree(I18n::Message::TransposeCommandWithArg, I18n::Message::Transpose, I18n::Message::TransposeCommand), ToolboxMessageTree(I18n::Message::TraceCommandWithArg, I18n::Message::Trace, I18n::Message::TraceCommand), ToolboxMessageTree(I18n::Message::DimensionCommandWithArg, I18n::Message::Dimension, I18n::Message::DimensionCommand)};
#endif
#if LIST_ARE_DEFINED
const ToolboxNode listesChildren[5] = {ToolboxNode(I18n::Message::SortCommandWithArg, I18n::Message::Sort, I18n::Message::SortCommand), ToolboxNode(I18n::Message::InvSortCommandWithArg, I18n::Message::InvSort, I18n::Message::InvSortCommand), ToolboxNode(I18n::Message::MaxCommandWithArg, I18n::Message::Maximum, I18n::Message::MaxCommand), ToolboxNode(I18n::Message::MinCommandWithArg, I18n::Message::Minimum, I18n::Message::MinCommand), ToolboxNode(I18n::Message::DimensionCommandWithArg, I18n::Message::Dimension, I18n::Message::DimensionCommand)};
const ToolboxMessageTree listesChildren[5] = {ToolboxMessageTree(I18n::Message::SortCommandWithArg, I18n::Message::Sort, I18n::Message::SortCommand), ToolboxMessageTree(I18n::Message::InvSortCommandWithArg, I18n::Message::InvSort, I18n::Message::InvSortCommand), ToolboxMessageTree(I18n::Message::MaxCommandWithArg, I18n::Message::Maximum, I18n::Message::MaxCommand), ToolboxMessageTree(I18n::Message::MinCommandWithArg, I18n::Message::Minimum, I18n::Message::MinCommand), ToolboxMessageTree(I18n::Message::DimensionCommandWithArg, I18n::Message::Dimension, I18n::Message::DimensionCommand)};
#endif
const ToolboxNode approximationChildren[4] = {ToolboxNode(I18n::Message::FloorCommandWithArg, I18n::Message::Floor, I18n::Message::FloorCommand), ToolboxNode(I18n::Message::FracCommandWithArg, I18n::Message::FracPart, I18n::Message::FracCommand), ToolboxNode(I18n::Message::CeilCommandWithArg, I18n::Message::Ceiling, I18n::Message::CeilCommand), ToolboxNode(I18n::Message::RoundCommandWithArg, I18n::Message::Rounding, I18n::Message::RoundCommand)};
const ToolboxNode trigonometryChildren[6] = {ToolboxNode(I18n::Message::CoshCommandWithArg, I18n::Message::HyperbolicCosine, I18n::Message::CoshCommand), ToolboxNode(I18n::Message::SinhCommandWithArg, I18n::Message::HyperbolicSine, I18n::Message::SinhCommand), ToolboxNode(I18n::Message::TanhCommandWithArg, I18n::Message::HyperbolicTangent, I18n::Message::TanhCommand), ToolboxNode(I18n::Message::AcoshCommandWithArg, I18n::Message::InverseHyperbolicCosine, I18n::Message::AcoshCommand), ToolboxNode(I18n::Message::AsinhCommandWithArg, I18n::Message::InverseHyperbolicSine, I18n::Message::AsinhCommand), ToolboxNode(I18n::Message::AtanhCommandWithArg, I18n::Message::InverseHyperbolicTangent, I18n::Message::AtanhCommand)};
const ToolboxNode predictionChildren[3] = {ToolboxNode(I18n::Message::Prediction95CommandWithArg, I18n::Message::Prediction95, I18n::Message::Prediction95Command), ToolboxNode(I18n::Message::PredictionCommandWithArg, I18n::Message::Prediction, I18n::Message::PredictionCommand), ToolboxNode(I18n::Message::ConfidenceCommandWithArg, I18n::Message::Confidence, I18n::Message::ConfidenceCommand)};
const ToolboxMessageTree approximationChildren[4] = {ToolboxMessageTree(I18n::Message::FloorCommandWithArg, I18n::Message::Floor, I18n::Message::FloorCommand), ToolboxMessageTree(I18n::Message::FracCommandWithArg, I18n::Message::FracPart, I18n::Message::FracCommand), ToolboxMessageTree(I18n::Message::CeilCommandWithArg, I18n::Message::Ceiling, I18n::Message::CeilCommand), ToolboxMessageTree(I18n::Message::RoundCommandWithArg, I18n::Message::Rounding, I18n::Message::RoundCommand)};
const ToolboxMessageTree trigonometryChildren[6] = {ToolboxMessageTree(I18n::Message::CoshCommandWithArg, I18n::Message::HyperbolicCosine, I18n::Message::CoshCommand), ToolboxMessageTree(I18n::Message::SinhCommandWithArg, I18n::Message::HyperbolicSine, I18n::Message::SinhCommand), ToolboxMessageTree(I18n::Message::TanhCommandWithArg, I18n::Message::HyperbolicTangent, I18n::Message::TanhCommand), ToolboxMessageTree(I18n::Message::AcoshCommandWithArg, I18n::Message::InverseHyperbolicCosine, I18n::Message::AcoshCommand), ToolboxMessageTree(I18n::Message::AsinhCommandWithArg, I18n::Message::InverseHyperbolicSine, I18n::Message::AsinhCommand), ToolboxMessageTree(I18n::Message::AtanhCommandWithArg, I18n::Message::InverseHyperbolicTangent, I18n::Message::AtanhCommand)};
const ToolboxMessageTree predictionChildren[3] = {ToolboxMessageTree(I18n::Message::Prediction95CommandWithArg, I18n::Message::Prediction95, I18n::Message::Prediction95Command), ToolboxMessageTree(I18n::Message::PredictionCommandWithArg, I18n::Message::Prediction, I18n::Message::PredictionCommand), ToolboxMessageTree(I18n::Message::ConfidenceCommandWithArg, I18n::Message::Confidence, I18n::Message::ConfidenceCommand)};
#if LIST_ARE_DEFINED
const ToolboxNode menu[12] = {ToolboxNode(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommand),
const ToolboxMessageTree menu[12] = {ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommand),
#elif MATRICES_ARE_DEFINED
const ToolboxNode menu[11] = {ToolboxNode(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommand),
const ToolboxMessageTree menu[11] = {ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommand),
#else
const ToolboxNode menu[10] = {ToolboxNode(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommand),
const ToolboxMessageTree menu[10] = {ToolboxMessageTree(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue, I18n::Message::AbsCommand),
#endif
ToolboxNode(I18n::Message::RootCommandWithArg, I18n::Message::NthRoot, I18n::Message::RootCommand),
ToolboxNode(I18n::Message::LogCommandWithArg, I18n::Message::BasedLogarithm, I18n::Message::LogCommand),
ToolboxNode(I18n::Message::Calculation, I18n::Message::Default, I18n::Message::Default, calculChildren, 4),
ToolboxNode(I18n::Message::ComplexNumber, I18n::Message::Default, I18n::Message::Default, complexChildren, 5),
ToolboxNode(I18n::Message::Probability, I18n::Message::Default, I18n::Message::Default, probabilityChildren, 2),
ToolboxNode(I18n::Message::Arithmetic, I18n::Message::Default, I18n::Message::Default, arithmeticChildren, 4),
ToolboxMessageTree(I18n::Message::RootCommandWithArg, I18n::Message::NthRoot, I18n::Message::RootCommand),
ToolboxMessageTree(I18n::Message::LogCommandWithArg, I18n::Message::BasedLogarithm, I18n::Message::LogCommand),
ToolboxMessageTree(I18n::Message::Calculation, I18n::Message::Default, I18n::Message::Default, calculChildren, 4),
ToolboxMessageTree(I18n::Message::ComplexNumber, I18n::Message::Default, I18n::Message::Default, complexChildren, 5),
ToolboxMessageTree(I18n::Message::Probability, I18n::Message::Default, I18n::Message::Default, probabilityChildren, 2),
ToolboxMessageTree(I18n::Message::Arithmetic, I18n::Message::Default, I18n::Message::Default, arithmeticChildren, 4),
#if MATRICES_ARE_DEFINED
ToolboxNode(I18n::Message::Matrices, I18n::Message::Default, I18n::Message::Default, matricesChildren, 5),
ToolboxMessageTree(I18n::Message::Matrices, I18n::Message::Default, I18n::Message::Default, matricesChildren, 5),
#endif
#if LIST_ARE_DEFINED
ToolboxNode(I18n::Message::Lists, I18n::Message::Default, I18n::Message::Default, listesChildren, 5),
ToolboxMessageTree(I18n::Message::Lists, I18n::Message::Default, I18n::Message::Default, listesChildren, 5),
#endif
ToolboxNode(I18n::Message::Approximation, I18n::Message::Default, I18n::Message::Default, approximationChildren, 4),
ToolboxNode(I18n::Message::HyperbolicTrigonometry, I18n::Message::Default, I18n::Message::Default, trigonometryChildren, 6),
ToolboxNode(I18n::Message::Fluctuation, I18n::Message::Default, I18n::Message::Default, predictionChildren, 3)};
ToolboxMessageTree(I18n::Message::Approximation, I18n::Message::Default, I18n::Message::Default, approximationChildren, 4),
ToolboxMessageTree(I18n::Message::HyperbolicTrigonometry, I18n::Message::Default, I18n::Message::Default, trigonometryChildren, 6),
ToolboxMessageTree(I18n::Message::Fluctuation, I18n::Message::Default, I18n::Message::Default, predictionChildren, 3)};
#if LIST_ARE_DEFINED
const ToolboxNode toolboxModel = ToolboxNode(I18n::Message::Toolbox, I18n::Message::Default, I18n::Message::Default, menu, 12);
const ToolboxMessageTree toolboxModel = ToolboxMessageTree(I18n::Message::Toolbox, I18n::Message::Default, I18n::Message::Default, menu, 12);
#elif MATRICES_ARE_DEFINED
const ToolboxNode toolboxModel = ToolboxNode(I18n::Message::Toolbox, I18n::Message::Default, I18n::Message::Default, menu, 11);
const ToolboxMessageTree toolboxModel = ToolboxMessageTree(I18n::Message::Toolbox, I18n::Message::Default, I18n::Message::Default, menu, 11);
#else
const ToolboxNode toolboxModel = ToolboxNode(I18n::Message::Toolbox, I18n::Message::Default, I18n::Message::Default, menu, 10);
const ToolboxMessageTree toolboxModel = ToolboxMessageTree(I18n::Message::Toolbox, I18n::Message::Default, I18n::Message::Default, menu, 10);
#endif
/* State */
MathToolbox::Stack::State::State(int selectedRow, KDCoordinate verticalScroll) :
m_selectedRow(selectedRow),
m_verticalScroll(verticalScroll)
MathToolbox::MathToolbox() : Toolbox(nullptr, I18n::translate(rootModel()->label()))
{
}
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() {
return I18n::translate(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(&m_listController, this, 0, 1, 0, 0, 0, 0, this, nullptr, false),
m_listController(this, &m_selectableTableView),
m_nodeModel(nullptr)
{
}
void MathToolbox::didBecomeFirstResponder() {
app()->setFirstResponder(&m_listController);
}
bool MathToolbox::handleEvent(Ion::Events::Event event) {
return handleEventForRow(event, selectedRow());
}
int MathToolbox::numberOfRows() {
if (m_nodeModel == nullptr) {
m_nodeModel = (ToolboxNode *)rootModel();
}
return m_nodeModel->numberOfChildren();
}
HighlightCell * 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) {
return k_maxNumberOfDisplayedRows;
}
void MathToolbox::willDisplayCellForIndex(HighlightCell * cell, int index) {
ToolboxNode * node = (ToolboxNode *)m_nodeModel->children(index);
if (node->numberOfChildren() == 0) {
MessageTableCellWithMessage * myCell = (MessageTableCellWithMessage *)cell;
myCell->setMessage(node->label());
myCell->setAccessoryMessage(node->text());
myCell->setAccessoryTextColor(Palette::GreyDark);
return;
}
MessageTableCell * myCell = (MessageTableCell *)cell;
myCell->setMessage(node->label());
}
KDCoordinate MathToolbox::rowHeight(int j) {
if (typeAtLocation(0, j) == 0) {
if (typeAtLocation(0, j) == Toolbox::LeafCellType) {
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::viewWillAppear() {
Toolbox::viewWillAppear();
m_nodeModel = (ToolboxNode *)rootModel();
m_selectableTableView.reloadData();
m_stack.resetStack();
m_listController.setFirstSelectedRow(0);
}
void MathToolbox::viewDidDisappear() {
Toolbox::viewDidDisappear();
m_selectableTableView.deselectTable();
}
int MathToolbox::stackDepth() {
return m_stack.depth();
}
TextField * MathToolbox::sender() {
return (TextField *)Toolbox::sender();
}
bool MathToolbox::handleEventForRow(Ion::Events::Event event, int selectedRow) {
int depth = m_stack.depth();
if (event == Ion::Events::Back && depth == 0) {
m_selectableTableView.deselectTable();
app()->dismissModalViewController();
return true;
}
if ((event == Ion::Events::Back || event == Ion::Events::Left) && depth > 0) {
return returnToPreviousMenu();
}
ToolboxNode * selectedNode = (ToolboxNode *)m_nodeModel->children(selectedRow);
if ((event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) && selectedNode->numberOfChildren() > 0) {
return selectSubMenu(selectedNode);
}
if ((event == Ion::Events::OK || event == Ion::Events::EXE) && selectedNode->numberOfChildren() == 0) {
return selectLeaf(selectedNode);
}
return false;
}
const ToolboxNode * MathToolbox::rootModel() {
return &toolboxModel;
}
bool MathToolbox::selectLeaf(ToolboxNode * selectedNode){
bool MathToolbox::selectLeaf(ToolboxMessageTree * selectedMessageTree) {
m_selectableTableView.deselectTable();
ToolboxNode * node = selectedNode;
const char * editedText = I18n::translate(node->insertedText());
ToolboxMessageTree * messageTree = selectedMessageTree;
const char * editedText = I18n::translate(messageTree->insertedText());
if (!sender()->isEditing()) {
sender()->setEditing(true);
}
@@ -288,31 +87,20 @@ bool MathToolbox::selectLeaf(ToolboxNode * selectedNode){
return true;
}
bool MathToolbox::returnToPreviousMenu() {
m_selectableTableView.deselectTable();
int depth = m_stack.depth();
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;
const ToolboxMessageTree * MathToolbox::rootModel() {
return &toolboxModel;
}
bool MathToolbox::selectSubMenu(ToolboxNode * selectedNode) {
m_stack.push(selectedRow(), m_selectableTableView.contentOffset().y());
m_selectableTableView.deselectTable();
m_nodeModel = selectedNode;
m_listController.setFirstSelectedRow(0);
app()->setFirstResponder(&m_listController);
return true;
MessageTableCellWithMessage * MathToolbox::leafCellAtIndex(int index) {
assert(index > 0 && index < k_maxNumberOfDisplayedRows);
return &m_leafCells[index];
}
MessageTableCellWithChevron* MathToolbox::nodeCellAtIndex(int index) {
assert(index > 0 && index < k_maxNumberOfDisplayedRows);
return &m_nodeCells[index];
}
int MathToolbox::maxNumberOfDisplayedRows() {
return k_maxNumberOfDisplayedRows;
}

View File

@@ -3,79 +3,25 @@
#define MATRICES_ARE_DEFINED 1
#include <escher.h>
#include "toolbox_node.h"
#include <apps/i18n.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 SelectableTableViewDataSource {
class MathToolbox : public Toolbox {
public:
MathToolbox();
void didBecomeFirstResponder() override;
bool handleEvent(Ion::Events::Event event) override;
int numberOfRows() override;
HighlightCell * reusableCell(int index, int type) override;
int reusableCellCount(int type) override;
void willDisplayCellForIndex(HighlightCell * 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 viewWillAppear() override;
void viewDidDisappear() override;
protected:
int stackDepth();
KDCoordinate rowHeight(int j) override;
TextField * sender() override;
bool handleEventForRow(Ion::Events::Event event, int selectedRow);
SelectableTableView m_selectableTableView;
constexpr static int k_maxNumberOfDisplayedRows = 6; //240/40
bool selectLeaf(ToolboxMessageTree * selectedMessageTree) override;
const ToolboxMessageTree * rootModel() override;
MessageTableCellWithMessage * leafCellAtIndex(int index) override;
MessageTableCellWithChevron* nodeCellAtIndex(int index) override;
int maxNumberOfDisplayedRows() override;
constexpr static int k_maxNumberOfDisplayedRows = 6; // = 240/40
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() 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;
const ToolboxNode * rootModel();
bool selectLeaf(ToolboxNode * selectedNode);
bool selectSubMenu(ToolboxNode * selectedNode);
bool returnToPreviousMenu();
Stack m_stack;
MessageTableCellWithMessage m_leafCells[k_maxNumberOfDisplayedRows];
MessageTableCellWithChevron m_nodeCells[k_maxNumberOfDisplayedRows];
ListController m_listController;
ToolboxNode * m_nodeModel;
};
#endif

View File

@@ -1,13 +0,0 @@
#include "node.h"
int Node::numberOfChildren() const {
return m_numberOfChildren;
}
I18n::Message Node::label() const {
return m_label;
}
bool Node::isNull() const {
return (m_label == I18n::Message::Default);
}

View File

@@ -1,23 +0,0 @@
#ifndef APPS_NODE_H
#define APPS_NODE_H
#include "i18n.h"
class Node {
public:
constexpr Node(I18n::Message label = I18n::Message::Default, int numberOfChildren = 0) :
m_label(label),
m_numberOfChildren(numberOfChildren)
{
};
virtual const Node * children(int index) const = 0;
I18n::Message label() const;
int numberOfChildren() const;
bool isNull() const;
protected:
I18n::Message m_label;
int m_numberOfChildren;
};
#endif

View File

@@ -5,7 +5,7 @@ app_objs += $(addprefix apps/settings/,\
app.o\
language_controller.o\
main_controller.o\
settings_node.o\
settings_message_tree.o\
sub_controller.o\
)

View File

@@ -10,27 +10,27 @@ using namespace Poincare;
namespace Settings {
const SettingsNode angleChildren[2] = {SettingsNode(I18n::Message::Degres), SettingsNode(I18n::Message::Radian)};
const SettingsNode FloatDisplayModeChildren[2] = {SettingsNode(I18n::Message::Auto), SettingsNode(I18n::Message::Scientific)};
const SettingsNode complexFormatChildren[2] = {SettingsNode(I18n::Message::Default), SettingsNode(I18n::Message::Default)};
const SettingsNode examChildren[1] = {SettingsNode(I18n::Message::ActivateExamMode)};
const SettingsNode aboutChildren[3] = {SettingsNode(I18n::Message::SoftwareVersion), SettingsNode(I18n::Message::SerialNumber), SettingsNode(I18n::Message::FccId)};
const SettingsMessageTree angleChildren[2] = {SettingsMessageTree(I18n::Message::Degres), SettingsMessageTree(I18n::Message::Radian)};
const SettingsMessageTree FloatDisplayModeChildren[2] = {SettingsMessageTree(I18n::Message::Auto), SettingsMessageTree(I18n::Message::Scientific)};
const SettingsMessageTree complexFormatChildren[2] = {SettingsMessageTree(I18n::Message::Default), SettingsMessageTree(I18n::Message::Default)};
const SettingsMessageTree examChildren[1] = {SettingsMessageTree(I18n::Message::ActivateExamMode)};
const SettingsMessageTree aboutChildren[3] = {SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId)};
#if OS_WITH_SOFTWARE_UPDATE_PROMPT
const SettingsNode menu[8] =
const SettingsMessageTree menu[8] =
#else
const SettingsNode menu[7] =
const SettingsMessageTree menu[7] =
#endif
{SettingsNode(I18n::Message::AngleUnit, angleChildren, 2), SettingsNode(I18n::Message::DisplayMode, FloatDisplayModeChildren, 2), SettingsNode(I18n::Message::ComplexFormat, complexFormatChildren, 2),
SettingsNode(I18n::Message::Brightness), SettingsNode(I18n::Message::Language), SettingsNode(I18n::Message::ExamMode, examChildren, 1),
{SettingsMessageTree(I18n::Message::AngleUnit, angleChildren, 2), SettingsMessageTree(I18n::Message::DisplayMode, FloatDisplayModeChildren, 2), SettingsMessageTree(I18n::Message::ComplexFormat, complexFormatChildren, 2),
SettingsMessageTree(I18n::Message::Brightness), SettingsMessageTree(I18n::Message::Language), SettingsMessageTree(I18n::Message::ExamMode, examChildren, 1),
#if OS_WITH_SOFTWARE_UPDATE_PROMPT
SettingsNode(I18n::Message::UpdatePopUp),
SettingsMessageTree(I18n::Message::UpdatePopUp),
#endif
SettingsNode(I18n::Message::About, aboutChildren, 3)};
SettingsMessageTree(I18n::Message::About, aboutChildren, 3)};
#if OS_WITH_SOFTWARE_UPDATE_PROMPT
const SettingsNode model = SettingsNode(I18n::Message::SettingsApp, menu, 8);
const SettingsMessageTree model = SettingsMessageTree(I18n::Message::SettingsApp, menu, 8);
#else
const SettingsNode model = SettingsNode(I18n::Message::SettingsApp, menu, 7);
const SettingsMessageTree model = SettingsMessageTree(I18n::Message::SettingsApp, menu, 7);
#endif
MainController::MainController(Responder * parentResponder) :
@@ -43,7 +43,7 @@ MainController::MainController(Responder * parentResponder) :
m_complexFormatLayout(nullptr),
m_selectableTableView(this, this, 0, 1, Metric::CommonTopMargin, Metric::CommonRightMargin,
Metric::CommonBottomMargin, Metric::CommonLeftMargin, this),
m_nodeModel((Node *)&model),
m_messageTreeModel((MessageTree *)&model),
m_subController(this),
m_languageController(this, 13)
{
@@ -59,7 +59,7 @@ MainController::~MainController() {
}
}
const char * MainController::title() {
return I18n::translate(m_nodeModel->label());
return I18n::translate(m_messageTreeModel->label());
}
View * MainController::view() {
@@ -74,9 +74,9 @@ void MainController::didBecomeFirstResponder() {
}
bool MainController::handleEvent(Ion::Events::Event event) {
if (m_nodeModel->children(selectedRow())->numberOfChildren() == 0) {
if (m_messageTreeModel->children(selectedRow())->numberOfChildren() == 0) {
#if OS_WITH_SOFTWARE_UPDATE_PROMPT
if (m_nodeModel->children(selectedRow())->label() == I18n::Message::UpdatePopUp) {
if (m_messageTreeModel->children(selectedRow())->label() == I18n::Message::UpdatePopUp) {
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
GlobalPreferences::sharedGlobalPreferences()->setShowUpdatePopUp(!GlobalPreferences::sharedGlobalPreferences()->showUpdatePopUp());
m_selectableTableView.reloadCellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow());
@@ -85,7 +85,7 @@ bool MainController::handleEvent(Ion::Events::Event event) {
return false;
}
#endif
if (m_nodeModel->children(selectedRow())->label() == I18n::Message::Brightness) {
if (m_messageTreeModel->children(selectedRow())->label() == I18n::Message::Brightness) {
if (event == Ion::Events::Right || event == Ion::Events::Left || event == Ion::Events::Plus || event == Ion::Events::Minus) {
int delta = Ion::Backlight::MaxBrightness/GlobalPreferences::NumberOfBrightnessStates;
int direction = (event == Ion::Events::Right || event == Ion::Events::Plus) ? delta : -delta;
@@ -95,7 +95,7 @@ bool MainController::handleEvent(Ion::Events::Event event) {
}
return false;
}
if (m_nodeModel->children(selectedRow())->label() == I18n::Message::Language) {
if (m_messageTreeModel->children(selectedRow())->label() == I18n::Message::Language) {
if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) {
stackController()->push(&m_languageController);
return true;
@@ -104,7 +104,7 @@ bool MainController::handleEvent(Ion::Events::Event event) {
}
}
if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) {
m_subController.setNodeModel(m_nodeModel->children(selectedRow()));
m_subController.setMessageTreeModel(m_messageTreeModel->children(selectedRow()));
StackViewController * stack = stackController();
stack->push(&m_subController);
return true;
@@ -113,7 +113,7 @@ bool MainController::handleEvent(Ion::Events::Event event) {
}
int MainController::numberOfRows() {
return m_nodeModel->numberOfChildren();
return m_messageTreeModel->numberOfChildren();
};
KDCoordinate MainController::rowHeight(int j) {
@@ -170,7 +170,7 @@ int MainController::typeAtLocation(int i, int j) {
void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) {
MessageTableCell * myCell = (MessageTableCell *)cell;
myCell->setMessage(m_nodeModel->children(index)->label());
myCell->setMessage(m_messageTreeModel->children(index)->label());
if (index == 2) {
if (m_complexFormatLayout) {
@@ -211,13 +211,13 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) {
MessageTableCellWithChevronAndMessage * myTextCell = (MessageTableCellWithChevronAndMessage *)cell;
switch (index) {
case 0:
myTextCell->setSubtitle(m_nodeModel->children(index)->children((int)Preferences::sharedPreferences()->angleUnit())->label());
myTextCell->setSubtitle(m_messageTreeModel->children(index)->children((int)Preferences::sharedPreferences()->angleUnit())->label());
break;
case 1:
myTextCell->setSubtitle(m_nodeModel->children(index)->children((int)Preferences::sharedPreferences()->displayMode())->label());
myTextCell->setSubtitle(m_messageTreeModel->children(index)->children((int)Preferences::sharedPreferences()->displayMode())->label());
break;
case 4:
myTextCell->setSubtitle(m_nodeModel->children(index)->children((int)GlobalPreferences::sharedGlobalPreferences()->language()-1)->label());
myTextCell->setSubtitle(m_messageTreeModel->children(index)->children((int)GlobalPreferences::sharedGlobalPreferences()->language()-1)->label());
break;
default:
myTextCell->setSubtitle(I18n::Message::Default);

View File

@@ -3,7 +3,7 @@
#include <escher.h>
#include "sub_controller.h"
#include "settings_node.h"
#include "settings_message_tree.h"
#include "language_controller.h"
namespace Settings {
@@ -43,7 +43,7 @@ private:
MessageTableCellWithGauge m_brightnessCell;
Poincare::ExpressionLayout * m_complexFormatLayout;
SelectableTableView m_selectableTableView;
Node * m_nodeModel;
MessageTree * m_messageTreeModel;
SubController m_subController;
LanguageController m_languageController;
};

View File

@@ -0,0 +1,9 @@
#include "settings_message_tree.h"
namespace Settings {
const MessageTree * SettingsMessageTree::children(int index) const {
return &m_children[index];
}
}

View File

@@ -0,0 +1,23 @@
#ifndef SETTINGS_MESSAGE_TREE_H
#define SETTINGS_MESSAGE_TREE_H
#include <escher/message_tree.h>
#include <apps/i18n.h>
namespace Settings {
class SettingsMessageTree : public MessageTree {
public:
constexpr SettingsMessageTree(I18n::Message label = I18n::Message::Default, const SettingsMessageTree * children = nullptr, int numberOfChildren = 0) :
MessageTree(label, numberOfChildren),
m_children(children)
{
};
const MessageTree * children(int index) const override;
private:
const SettingsMessageTree * m_children;
};
}
#endif

View File

@@ -1,9 +0,0 @@
#include "settings_node.h"
namespace Settings {
const Node * SettingsNode::children(int index) const {
return &m_children[index];
}
}

View File

@@ -1,23 +0,0 @@
#ifndef SETTINGS_NODE_H
#define SETTINGS_NODE_H
#include "../node.h"
namespace Settings {
class SettingsNode : public Node {
public:
constexpr SettingsNode(I18n::Message label = I18n::Message::Default, const SettingsNode * children = nullptr, int numberOfChildren = 0) :
Node(label, numberOfChildren),
m_children(children)
{
};
const Node * children(int index) const override;
private:
const SettingsNode * m_children;
};
}
#endif

View File

@@ -13,7 +13,7 @@ SubController::SubController(Responder * parentResponder) :
ViewController(parentResponder),
m_selectableTableView(this, this, 0, 1, k_topBottomMargin, Metric::CommonRightMargin,
k_topBottomMargin, Metric::CommonLeftMargin, this),
m_nodeModel(nullptr)
m_messageTreeModel(nullptr)
{
for (int i = 0; i < k_totalNumberOfCell; i++) {
m_cells[i].setMessageFontSize(KDText::FontSize::Large);
@@ -40,8 +40,8 @@ SubController::~SubController() {
}
const char * SubController::title() {
if (m_nodeModel) {
return I18n::translate(m_nodeModel->label());
if (m_messageTreeModel) {
return I18n::translate(m_messageTreeModel->label());
}
return "";
}
@@ -52,12 +52,12 @@ View * SubController::view() {
void SubController::didEnterResponderChain(Responder * previousResponder) {
if (previousResponder->commonAncestorWith(this) == parentResponder()) {
/* We want to select the prefered setting node only when the previous page
/* We want to select the prefered SettingMessageTree only when the previous page
* was the main setting page. We do not to change the selection when
* dismissing a pop-up for instance. */
selectCellAtLocation(0, valueIndexForPreference(m_nodeModel->label()));
selectCellAtLocation(0, valueIndexForPreference(m_messageTreeModel->label()));
}
if (m_nodeModel->label() == I18n::Message::ExamMode) {
if (m_messageTreeModel->label() == I18n::Message::ExamMode) {
m_selectableTableView.reloadData();
}
app()->setFirstResponder(&m_selectableTableView);
@@ -66,13 +66,13 @@ void SubController::didEnterResponderChain(Responder * previousResponder) {
bool SubController::handleEvent(Ion::Events::Event event) {
/* We hide here the activation hardware test app: in the menu "about", by
* clicking on '6' on the last row. */
if ((event == Ion::Events::Six || event == Ion::Events::LowerT || event == Ion::Events::UpperT) && m_nodeModel->label() == I18n::Message::About && selectedRow() == numberOfRows()-1) {
if ((event == Ion::Events::Six || event == Ion::Events::LowerT || event == Ion::Events::UpperT) && m_messageTreeModel->label() == I18n::Message::About && selectedRow() == numberOfRows()-1) {
app()->displayModalViewController(&m_hardwareTestPopUpController, 0.f, 0.f, Metric::ExamPopUpTopMargin, Metric::PopUpRightMargin, Metric::ExamPopUpBottomMargin, Metric::PopUpLeftMargin);
return true;
}
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
/* Behavious of "Exam mode" menu*/
if (m_nodeModel->label() == I18n::Message::ExamMode) {
if (m_messageTreeModel->label() == I18n::Message::ExamMode) {
if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) {
return false;
}
@@ -81,7 +81,7 @@ bool SubController::handleEvent(Ion::Events::Event event) {
return true;
}
/* Behaviour of "About" menu */
if (m_nodeModel->label() == I18n::Message::About) {
if (m_messageTreeModel->label() == I18n::Message::About) {
if (selectedRow() == 0) {
MessageTableCellWithBuffer * myCell = (MessageTableCellWithBuffer *)m_selectableTableView.selectedCell();
if (strcmp(myCell->accessoryText(), Ion::patchLevel()) == 0) {
@@ -94,7 +94,7 @@ bool SubController::handleEvent(Ion::Events::Event event) {
return false;
}
/* Generic behaviour of preference menu*/
setPreferenceWithValueIndex(m_nodeModel->label(), selectedRow());
setPreferenceWithValueIndex(m_messageTreeModel->label(), selectedRow());
AppsContainer * myContainer = (AppsContainer * )app()->container();
myContainer->refreshPreferences();
StackViewController * stack = stackController();
@@ -109,8 +109,8 @@ bool SubController::handleEvent(Ion::Events::Event event) {
}
int SubController::numberOfRows() {
if (m_nodeModel) {
return m_nodeModel->numberOfChildren();
if (m_messageTreeModel) {
return m_messageTreeModel->numberOfChildren();
}
return 0;
}
@@ -118,14 +118,14 @@ int SubController::numberOfRows() {
HighlightCell * SubController::reusableCell(int index) {
assert(index >= 0);
assert(index < k_totalNumberOfCell);
if (m_nodeModel->label() == I18n::Message::ComplexFormat) {
if (m_messageTreeModel->label() == I18n::Message::ComplexFormat) {
return &m_complexFormatCells[index];
}
return &m_cells[index];
}
int SubController::reusableCellCount() {
if (m_nodeModel->label() == I18n::Message::ComplexFormat) {
if (m_messageTreeModel->label() == I18n::Message::ComplexFormat) {
return 2;
}
return k_totalNumberOfCell;
@@ -136,17 +136,17 @@ KDCoordinate SubController::cellHeight() {
}
void SubController::willDisplayCellForIndex(HighlightCell * cell, int index) {
if (m_nodeModel->label() == I18n::Message::ComplexFormat) {
if (m_messageTreeModel->label() == I18n::Message::ComplexFormat) {
return;
}
MessageTableCellWithBuffer * myCell = (MessageTableCellWithBuffer *)cell;
myCell->setMessage(m_nodeModel->children(index)->label());
myCell->setMessage(m_messageTreeModel->children(index)->label());
myCell->setMessageFontSize(KDText::FontSize::Large);
myCell->setAccessoryText("");
if (m_nodeModel->label() == I18n::Message::ExamMode && GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) {
if (m_messageTreeModel->label() == I18n::Message::ExamMode && GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) {
myCell->setMessage(I18n::Message::ExamModeActive);
}
if (m_nodeModel->label() == I18n::Message::About) {
if (m_messageTreeModel->label() == I18n::Message::About) {
myCell->setMessageFontSize(KDText::FontSize::Small);
const char * accessoryMessage = Ion::softwareVersion();
switch (index) {
@@ -167,8 +167,8 @@ void SubController::willDisplayCellForIndex(HighlightCell * cell, int index) {
}
}
void SubController::setNodeModel(const Node * nodeModel) {
m_nodeModel = (Node *)nodeModel;
void SubController::setMessageTreeModel(const MessageTree * messageTreeModel) {
m_messageTreeModel = (MessageTree *)messageTreeModel;
}
void SubController::viewWillAppear() {

View File

@@ -2,7 +2,7 @@
#define SETTINGS_SUB_CONTROLLER_H
#include <escher.h>
#include "settings_node.h"
#include "settings_message_tree.h"
#include "../hardware_test/pop_up_controller.h"
namespace Settings {
@@ -24,7 +24,7 @@ public:
HighlightCell * reusableCell(int index) override;
int reusableCellCount() override;
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
void setNodeModel(const Node * nodeModel);
void setMessageTreeModel(const MessageTree * messageTreeModel);
void viewWillAppear() override;
void viewDidDisappear() override;
private:
@@ -37,7 +37,7 @@ private:
ExpressionTableCell m_complexFormatCells[2];
Poincare::ExpressionLayout * m_complexFormatLayout[2];
SelectableTableView m_selectableTableView;
Node * m_nodeModel;
MessageTree * m_messageTreeModel;
HardwareTest::PopUpController m_hardwareTestPopUpController;
};

View File

@@ -1,13 +0,0 @@
#include "toolbox_node.h"
I18n::Message ToolboxNode::text() const {
return m_text;
}
I18n::Message ToolboxNode::insertedText() const {
return m_insertedText;
}
const Node * ToolboxNode::children(int index) const {
return &m_children[index];
}

View File

@@ -1,25 +0,0 @@
#ifndef APPS_TOOLBOX_NODE_H
#define APPS_TOOLBOX_NODE_H
#include "node.h"
class ToolboxNode : public Node {
public:
constexpr ToolboxNode(I18n::Message label = I18n::Message::Default, I18n::Message text = I18n::Message::Default, I18n::Message insertedText = I18n::Message::Default, const ToolboxNode * children = nullptr, int numberOfChildren = 0) :
Node(label, numberOfChildren),
m_children(children),
m_text(text),
m_insertedText(insertedText)
{
};
const Node * children(int index) const override;
I18n::Message text() const;
I18n::Message insertedText() const;
private:
const ToolboxNode * m_children;
I18n::Message m_text;
I18n::Message m_insertedText;
};
#endif

View File

@@ -37,6 +37,7 @@ objs += $(addprefix escher/src/,\
message_table_cell_with_message.o\
message_table_cell_with_switch.o\
message_text_view.o\
message_tree.o\
modal_view_controller.o\
palette.o\
responder.o\
@@ -66,8 +67,9 @@ objs += $(addprefix escher/src/,\
text_field.o\
text_view.o\
tiled_view.o\
toolbox.o\
timer.o\
toolbox.o\
toolbox_message_tree.o\
view.o\
view_controller.o\
warning_controller.o\

View File

@@ -40,6 +40,7 @@
#include <escher/message_table_cell_with_message.h>
#include <escher/message_table_cell_with_switch.h>
#include <escher/message_text_view.h>
#include <escher/message_tree.h>
#include <escher/metric.h>
#include <escher/modal_view_controller.h>
#include <escher/palette.h>
@@ -69,6 +70,7 @@
#include <escher/tiled_view.h>
#include <escher/timer.h>
#include <escher/toolbox.h>
#include <escher/toolbox_message_tree.h>
#include <escher/view.h>
#include <escher/view_controller.h>
#include <escher/warning_controller.h>

View File

@@ -0,0 +1,23 @@
#ifndef ESCHER_MESSAGE_TREE_H
#define ESCHER_MESSAGE_TREE_H
#include <escher/i18n.h>
class MessageTree {
public:
constexpr MessageTree(I18n::Message label = (I18n::Message)0, int numberOfChildren = 0) :
m_label(label),
m_numberOfChildren(numberOfChildren)
{
};
virtual const MessageTree * children(int index) const = 0;
I18n::Message label() const;
int numberOfChildren() const;
bool isNull() const;
protected:
I18n::Message m_label;
int m_numberOfChildren;
};
#endif

View File

@@ -1,19 +1,92 @@
#ifndef ESCHER_TOOLBOX_H
#define ESCHER_TOOLBOX_H
#include <escher/highlight_cell.h>
#include <escher/list_view_data_source.h>
#include <escher/message_table_cell_with_message.h>
#include <escher/message_table_cell_with_chevron.h>
#include <escher/selectable_table_view.h>
#include <escher/stack_view_controller.h>
#include <escher/toolbox_message_tree.h>
class Toolbox : public StackViewController {
class Toolbox : public StackViewController, public ListViewDataSource, public SelectableTableViewDataSource {
public:
Toolbox(Responder * parentResponder, ViewController * rootViewController);
Toolbox(Responder * parentResponder, const char * title = 0);
void setSender(Responder * sender);
// StackViewController
bool handleEvent(Ion::Events::Event event) override;
void didBecomeFirstResponder() override;
void viewWillAppear() override;
void viewDidDisappear() override;
//ListViewDataSource
int numberOfRows() override;
HighlightCell * reusableCell(int index, int type) override;
int reusableCellCount(int type) override;
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
KDCoordinate cumulatedHeightFromIndex(int j) override;
int indexFromCumulatedHeight(KDCoordinate offsetY) override;
int typeAtLocation(int i, int j) override;
protected:
class Stack {
public:
class State {
public:
State(int selectedRow = -1, KDCoordinate verticalScroll = 0);
bool isNull();
int selectedRow() { return m_selectedRow; }
KDCoordinate verticalScroll() { return m_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 = 3;
State m_statesStack[k_maxModelTreeDepth];
};
class ListController : public ViewController {
public:
ListController(Responder * parentResponder, SelectableTableView * tableView, const char * title);
const char * title() override;
View * view() override;
void didBecomeFirstResponder() override;
void setFirstSelectedRow(int firstSelectedRow);
private:
SelectableTableView * m_selectableTableView;
int m_firstSelectedRow;
const char * m_title;
};
static constexpr int LeafCellType = 0;
static constexpr int NodeCellType = 1;
int stackDepth();
bool handleEventForRow(Ion::Events::Event event, int selectedRow);
bool selectSubMenu(ToolboxMessageTree * selectedMessageTree);
bool returnToPreviousMenu();
virtual Responder * sender();
virtual bool selectLeaf(ToolboxMessageTree * selectedMessageTree) = 0;
virtual const ToolboxMessageTree * rootModel() = 0;
virtual MessageTableCellWithMessage * leafCellAtIndex(int index) = 0;
virtual MessageTableCellWithChevron * nodeCellAtIndex(int index) = 0;
virtual int maxNumberOfDisplayedRows() = 0;
SelectableTableView m_selectableTableView;
Stack m_stack;
ListController m_listController;
ToolboxMessageTree * m_messageTreeModel;
/* m_messageTreeModel points at the messageTree of the tree (describing the
* whole model) where we are located. It enables to know which rows are leaves
* and which are subtrees. */
private:
Responder * m_sender;
};
#endif

View File

@@ -0,0 +1,25 @@
#ifndef ESCHER_TOOLBOX_MESSAGE_TREE_H
#define ESCHER_TOOLBOX_MESSAGE_TREE_H
#include <escher/message_tree.h>
class ToolboxMessageTree : public MessageTree {
public:
constexpr ToolboxMessageTree(I18n::Message label = (I18n::Message)0, I18n::Message text = (I18n::Message)0, I18n::Message insertedText = (I18n::Message)0, const ToolboxMessageTree * children = nullptr, int numberOfChildren = 0) :
MessageTree(label, numberOfChildren),
m_children(children),
m_text(text),
m_insertedText(insertedText)
{
};
const MessageTree * children(int index) const override;
I18n::Message text() const;
I18n::Message insertedText() const;
private:
const ToolboxMessageTree * m_children;
I18n::Message m_text;
I18n::Message m_insertedText;
};
#endif

View File

@@ -0,0 +1,13 @@
#include <escher/message_tree.h>
int MessageTree::numberOfChildren() const {
return m_numberOfChildren;
}
I18n::Message MessageTree::label() const {
return m_label;
}
bool MessageTree::isNull() const {
return (m_label == (I18n::Message)0);
}

View File

@@ -1,7 +1,94 @@
#include <escher/toolbox.h>
#include <assert.h>
#include <string.h>
Toolbox::Toolbox(Responder * parentResponder, ViewController * rootViewController) :
StackViewController(parentResponder, rootViewController, true, KDColorWhite, Palette::PurpleBright, Palette::PurpleDark),
/* State */
Toolbox::Stack::State::State(int selectedRow, KDCoordinate verticalScroll) :
m_selectedRow(selectedRow),
m_verticalScroll(verticalScroll)
{
}
bool Toolbox::Stack::State::isNull(){
if (m_selectedRow == -1) {
return true;
}
return false;
}
/* Stack */
void Toolbox::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);
}
Toolbox::Stack::State * Toolbox::Stack::stateAtIndex(int index) {
return &m_statesStack[index];
}
int Toolbox::Stack::depth() {
int depth = 0;
for (int i = 0; i < k_maxModelTreeDepth; i++) {
depth += (!m_statesStack[i].isNull());
}
return depth;
}
void Toolbox::Stack::pop() {
int stackDepth = depth();
if (stackDepth == 0) {
return;
}
m_statesStack[stackDepth-1] = State();
}
void Toolbox::Stack::resetStack() {
for (int i = 0; i < k_maxModelTreeDepth; i++) {
m_statesStack[i] = State();
}
}
/* List Controller */
Toolbox::ListController::ListController(Responder * parentResponder, SelectableTableView * tableView, const char * title) :
ViewController(parentResponder),
m_selectableTableView(tableView),
m_firstSelectedRow(0),
m_title(title)
{
}
const char * Toolbox::ListController::title() {
return m_title;
}
View * Toolbox::ListController::view() {
return m_selectableTableView;
}
void Toolbox::ListController::didBecomeFirstResponder() {
m_selectableTableView->reloadData();
m_selectableTableView->selectCellAtLocation(0, m_firstSelectedRow);
app()->setFirstResponder(m_selectableTableView);
}
void Toolbox::ListController::setFirstSelectedRow(int firstSelectedRow) {
m_firstSelectedRow = firstSelectedRow;
}
/* Toolbox */
Toolbox::Toolbox(Responder * parentResponder, const char * title) :
StackViewController(parentResponder, &m_listController, true, KDColorWhite, Palette::PurpleBright, Palette::PurpleDark),
m_selectableTableView(&m_listController, this, 0, 1, 0, 0, 0, 0, this, nullptr, false),
m_listController(this, &m_selectableTableView, title),
m_messageTreeModel(nullptr),
m_sender(nullptr)
{
}
@@ -10,12 +97,141 @@ void Toolbox::setSender(Responder * sender) {
m_sender = sender;
}
bool Toolbox::handleEvent(Ion::Events::Event event) {
return handleEventForRow(event, selectedRow());
}
void Toolbox::didBecomeFirstResponder() {
app()->setFirstResponder(&m_listController);
}
void Toolbox::viewWillAppear() {
StackViewController::viewWillAppear();
m_messageTreeModel = (ToolboxMessageTree *)rootModel();
m_selectableTableView.reloadData();
m_stack.resetStack();
m_listController.setFirstSelectedRow(0);
}
void Toolbox::viewDidDisappear() {
StackViewController::viewDidDisappear();
m_selectableTableView.deselectTable();
}
int Toolbox::numberOfRows() {
if (m_messageTreeModel == nullptr) {
m_messageTreeModel = (ToolboxMessageTree *)rootModel();
}
return m_messageTreeModel->numberOfChildren();
}
HighlightCell * Toolbox::reusableCell(int index, int type) {
assert(type < 2);
assert(index >= 0);
assert(index < maxNumberOfDisplayedRows());
if (type == LeafCellType) {
return leafCellAtIndex(index);
}
return nodeCellAtIndex(index);
}
int Toolbox::reusableCellCount(int type) {
return maxNumberOfDisplayedRows();
}
void Toolbox::willDisplayCellForIndex(HighlightCell * cell, int index) {
ToolboxMessageTree * messageTree = (ToolboxMessageTree *)m_messageTreeModel->children(index);
if (messageTree->numberOfChildren() == 0) {
MessageTableCellWithMessage * myCell = (MessageTableCellWithMessage *)cell;
myCell->setMessage(messageTree->label());
myCell->setAccessoryMessage(messageTree->text());
myCell->setAccessoryTextColor(Palette::GreyDark);
return;
}
MessageTableCell * myCell = (MessageTableCell *)cell;
myCell->setMessage(messageTree->label());
}
KDCoordinate Toolbox::cumulatedHeightFromIndex(int j) {
int result = 0;
for (int k = 0; k < j; k++) {
result += rowHeight(k);
}
return result;
}
int Toolbox::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 Toolbox::typeAtLocation(int i, int j) {
MessageTree * messageTree = (MessageTree *)m_messageTreeModel->children(j);
if (messageTree->numberOfChildren() == 0) {
return LeafCellType;
}
return NodeCellType;
}
int Toolbox::stackDepth() {
return m_stack.depth();
}
bool Toolbox::handleEventForRow(Ion::Events::Event event, int selectedRow) {
int depth = m_stack.depth();
if (event == Ion::Events::Back && depth == 0) {
m_selectableTableView.deselectTable();
app()->dismissModalViewController();
return true;
}
if ((event == Ion::Events::Back || event == Ion::Events::Left) && depth > 0) {
return returnToPreviousMenu();
}
ToolboxMessageTree * selectedMessageTree = (ToolboxMessageTree *)m_messageTreeModel->children(selectedRow);
if ((event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) && selectedMessageTree->numberOfChildren() > 0) {
return selectSubMenu(selectedMessageTree);
}
if ((event == Ion::Events::OK || event == Ion::Events::EXE) && selectedMessageTree->numberOfChildren() == 0) {
return selectLeaf(selectedMessageTree);
}
return false;
}
bool Toolbox::selectSubMenu(ToolboxMessageTree * selectedMessageTree) {
m_stack.push(selectedRow(), m_selectableTableView.contentOffset().y());
m_selectableTableView.deselectTable();
m_messageTreeModel = selectedMessageTree;
m_listController.setFirstSelectedRow(0);
app()->setFirstResponder(&m_listController);
return true;
}
bool Toolbox::returnToPreviousMenu() {
m_selectableTableView.deselectTable();
int depth = m_stack.depth();
int index = 0;
// We want to get the current ToolboxMessageTree's parent ToolboxMessageTree,
// but there is no ToolboxMessageTree::getParent() method. We thus have to
// start from the root ToolboxMessageTree and sequentially get the selected
// child until it has the wanted depth.
ToolboxMessageTree * parentMessageTree = (ToolboxMessageTree *)rootModel();
Stack::State * previousState = m_stack.stateAtIndex(index++);;
while (depth-- > 1) {
parentMessageTree = (ToolboxMessageTree *)parentMessageTree->children(previousState->selectedRow());
previousState = m_stack.stateAtIndex(index++);
}
m_selectableTableView.deselectTable();
m_messageTreeModel = parentMessageTree;
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;
}
Responder * Toolbox::sender() {

View File

@@ -0,0 +1,13 @@
#include <escher/toolbox_message_tree.h>
I18n::Message ToolboxMessageTree::text() const {
return m_text;
}
I18n::Message ToolboxMessageTree::insertedText() const {
return m_insertedText;
}
const MessageTree * ToolboxMessageTree::children(int index) const {
return &m_children[index];
}