#include #include #include #include /* 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, KDColorWhite, Palette::PurpleBright, Palette::PurpleDark), m_selectableTableView(&m_listController, this, this), m_listController(this, &m_selectableTableView, title), m_messageTreeModel(nullptr), m_sender(nullptr) { m_selectableTableView.setMargins(0); m_selectableTableView.setShowsIndicators(false); } 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(); } KDCoordinate Toolbox::rowHeight(int j) { return Metric::ToolboxRowHeight; } 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()); } 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 || 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() { int currentDepth = 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 (currentDepth-- > 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; }