mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
181 lines
5.3 KiB
C++
181 lines
5.3 KiB
C++
#include <escher/nested_menu_controller.h>
|
|
#include <escher/container.h>
|
|
#include <escher/metric.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
/* State */
|
|
|
|
NestedMenuController::Stack::State::State(int selectedRow, KDCoordinate verticalScroll) :
|
|
m_selectedRow(selectedRow),
|
|
m_verticalScroll(verticalScroll)
|
|
{
|
|
}
|
|
|
|
bool NestedMenuController::Stack::State::isNull() const {
|
|
if (m_selectedRow == -1) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Stack */
|
|
|
|
void NestedMenuController::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);
|
|
}
|
|
|
|
NestedMenuController::Stack::State * NestedMenuController::Stack::stateAtIndex(int index) {
|
|
return &m_statesStack[index];
|
|
}
|
|
|
|
int NestedMenuController::Stack::depth() const {
|
|
int depth = 0;
|
|
for (int i = 0; i < k_maxModelTreeDepth; i++) {
|
|
depth += (!m_statesStack[i].isNull());
|
|
}
|
|
return depth;
|
|
}
|
|
|
|
NestedMenuController::Stack::State NestedMenuController::Stack::pop() {
|
|
int stackDepth = depth();
|
|
if (stackDepth == 0) {
|
|
return State();
|
|
}
|
|
NestedMenuController::Stack::State state = m_statesStack[stackDepth-1];
|
|
m_statesStack[stackDepth-1] = State();
|
|
return state;
|
|
}
|
|
|
|
void NestedMenuController::Stack::resetStack() {
|
|
for (int i = 0; i < k_maxModelTreeDepth; i++) {
|
|
m_statesStack[i] = State();
|
|
}
|
|
}
|
|
|
|
/* List Controller */
|
|
|
|
NestedMenuController::ListController::ListController(Responder * parentResponder, SelectableTableView * tableView, I18n::Message title) :
|
|
ViewController(parentResponder),
|
|
m_selectableTableView(tableView),
|
|
m_firstSelectedRow(0),
|
|
m_title(title)
|
|
{
|
|
}
|
|
|
|
const char * NestedMenuController::ListController::title() {
|
|
return I18n::translate(m_title);
|
|
}
|
|
|
|
View * NestedMenuController::ListController::view() {
|
|
return m_selectableTableView;
|
|
}
|
|
|
|
void NestedMenuController::ListController::didBecomeFirstResponder() {
|
|
m_selectableTableView->reloadData();
|
|
Container::activeApp()->setFirstResponder(m_selectableTableView);
|
|
m_selectableTableView->selectCellAtLocation(0, m_firstSelectedRow);
|
|
}
|
|
|
|
void NestedMenuController::ListController::setFirstSelectedRow(int firstSelectedRow) {
|
|
m_firstSelectedRow = firstSelectedRow;
|
|
}
|
|
|
|
/* NestedMenuController */
|
|
|
|
NestedMenuController::NestedMenuController(Responder * parentResponder, I18n::Message title) :
|
|
StackViewController(parentResponder, &m_listController, Palette::ToolboxHeaderText, Palette::ToolboxHeaderBackground, Palette::ToolboxHeaderBorder),
|
|
m_selectableTableView(&m_listController, this, this, this),
|
|
m_listController(this, &m_selectableTableView, title),
|
|
m_sender(nullptr)
|
|
{
|
|
m_selectableTableView.setMargins(0);
|
|
m_selectableTableView.setDecoratorType(ScrollView::Decorator::Type::None);
|
|
}
|
|
|
|
void NestedMenuController::setTitle(I18n::Message title) {
|
|
m_listController.setTitle(title);
|
|
}
|
|
|
|
bool NestedMenuController::handleEvent(Ion::Events::Event event) {
|
|
return handleEventForRow(event, selectedRow());
|
|
}
|
|
|
|
void NestedMenuController::didBecomeFirstResponder() {
|
|
Container::activeApp()->setFirstResponder(&m_listController);
|
|
}
|
|
|
|
void NestedMenuController::viewWillAppear() {
|
|
StackViewController::viewWillAppear();
|
|
m_selectableTableView.reloadData();
|
|
m_stack.resetStack();
|
|
m_listController.setFirstSelectedRow(0);
|
|
}
|
|
|
|
void NestedMenuController::viewDidDisappear() {
|
|
StackViewController::viewDidDisappear();
|
|
m_selectableTableView.deselectTable();
|
|
}
|
|
|
|
KDCoordinate NestedMenuController::rowHeight(int j) {
|
|
return Metric::ToolboxRowHeight;
|
|
}
|
|
|
|
HighlightCell * NestedMenuController::reusableCell(int index, int type) {
|
|
assert(type < 2);
|
|
assert(index >= 0);
|
|
if (type == LeafCellType) {
|
|
return leafCellAtIndex(index);
|
|
}
|
|
return nodeCellAtIndex(index);
|
|
}
|
|
|
|
int NestedMenuController::stackDepth() const {
|
|
return m_stack.depth();
|
|
}
|
|
|
|
bool NestedMenuController::handleEventForRow(Ion::Events::Event event, int rowIndex) {
|
|
int depth = m_stack.depth();
|
|
if ((event == Ion::Events::Back || event == Ion::Events::Left) && depth > 0) {
|
|
return returnToPreviousMenu();
|
|
}
|
|
if ((event == Ion::Events::ShiftLeft || event == Ion::Events::AlphaLeft) && depth > 0) {
|
|
for (int i = depth; i > 0; i--) {
|
|
returnToPreviousMenu();
|
|
}
|
|
return true;
|
|
}
|
|
if (selectedRow() < 0) {
|
|
return false;
|
|
}
|
|
if ((event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) && typeAtLocation(0, selectedRow()) == NodeCellType) {
|
|
return selectSubMenu(rowIndex);
|
|
}
|
|
if ((event == Ion::Events::OK || event == Ion::Events::EXE) && typeAtLocation(0, selectedRow()) == LeafCellType) {
|
|
return selectLeaf(rowIndex);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool NestedMenuController::selectSubMenu(int selectedRow) {
|
|
m_stack.push(selectedRow, m_selectableTableView.contentOffset().y());
|
|
m_listController.setFirstSelectedRow(0);
|
|
Container::activeApp()->setFirstResponder(&m_listController);
|
|
return true;
|
|
}
|
|
|
|
bool NestedMenuController::returnToPreviousMenu() {
|
|
assert(m_stack.depth() > 0);
|
|
NestedMenuController::Stack::State state = m_stack.pop();
|
|
m_listController.setFirstSelectedRow(state.selectedRow() + stackRowOffset());
|
|
KDPoint scroll = m_selectableTableView.contentOffset();
|
|
m_selectableTableView.setContentOffset(KDPoint(scroll.x(), state.verticalScroll()));
|
|
Container::activeApp()->setFirstResponder(&m_listController);
|
|
return true;
|
|
}
|