To use the node in your project you should have the bitrex/xod-menu-system library installed. Use the “File → Add Library” menu item in XOD IDE if you don’t have it yet. See Using libraries for more info.
C++ implementation
#pragma XOD dirtiness disable
namespace menu_base = ____menu_base;
using menu_base_t = menu_base::MenuBase;
namespace branch_menu_item = ____branch_menu_item;
/* a MenuCursor interface, providing an interface from user
selections on a keypad to navigating thru the menu tree,
selecting, and invoking menu items */
template <typename MenuBase>
class MenuCursor {
public:
MenuCursor() = default;
explicit MenuCursor(branch_menu_item::BranchMenuImpl<MenuBase>* top_menu)
: top_menu_ptr_(top_menu),
current_root_menu_ptr_(nullptr),
current_sub_menu_ptr_(top_menu) {}
void back() {
auto parent_ptr = current_root_menu_ptr_->parent();
if (parent_ptr && current_sub_menu_ptr_!= top_menu_ptr_) {
current_root_menu_ptr_ = parent_ptr;
current_sub_menu_ptr_ = current_root_menu_ptr_->sub_menu_ptr();
} else {
current_sub_menu_ptr_ = top_menu_ptr_;
current_root_menu_ptr_ = nullptr;
}
}
void left() {
if (current_root_menu_ptr_) {
current_sub_menu_ptr_ = current_root_menu_ptr_->prev();
}
}
void right() {
if (current_root_menu_ptr_) {
current_sub_menu_ptr_ = current_root_menu_ptr_->next();
}
}
void invoke(Number param) {
auto menu_ptr = current_sub_menu_ptr_->invoke(param);
if (menu_ptr) {
auto prev_root_menu_ = current_root_menu_ptr_;
current_root_menu_ptr_ =
static_cast<branch_menu_item::BranchMenuImpl<MenuBase>*>(
menu_ptr);
current_root_menu_ptr_->set_parent(prev_root_menu_);
current_sub_menu_ptr_ = current_root_menu_ptr_->sub_menu_ptr();
}
}
List<XString> text() const { return current_sub_menu_ptr_->text(); }
private:
branch_menu_item::BranchMenuImpl<MenuBase>* top_menu_ptr_ = nullptr;
branch_menu_item::BranchMenuImpl<MenuBase>* current_root_menu_ptr_ = nullptr;
MenuBase* current_sub_menu_ptr_ = nullptr;
};
/* State for this node holds a branch menu to which the rest of
the menu structure is connected and derives from */
struct State {
MenuCursor<menu_base_t> menu_cursor;
branch_menu_item::BranchMenuImpl<menu_base_t> root_menu;
};
{{ GENERATED_CODE }}
static XStringCString null_string = XStringCString("");
void evaluate(Context ctx) {
auto state = getState(ctx);
if (isSettingUp()) {
auto title_1 = getValue<input_TITLE_1>(ctx);
auto title_2 = getValue<input_TITLE_2>(ctx);
state->root_menu =
branch_menu_item::BranchMenuImpl<menu_base_t>(getValue<input_MENU_TREE>(ctx), title_1,
title_2, 0);
state->root_menu.set_parent(&state->root_menu);
state->menu_cursor = MenuCursor<menu_base_t>(&state->root_menu);
}
/* update all trigger pulse inputs */
bool back = isInputDirty<input_BACK>(ctx);
bool left = isInputDirty<input_LEFT>(ctx);
bool right = isInputDirty<input_RIGHT>(ctx);
bool invoke = isInputDirty<input_INVOKE>(ctx);
if (back) {
state->menu_cursor.back();
}
if (left) {
state->menu_cursor.left();
}
if (right) {
state->menu_cursor.right();
}
if (invoke) {
// if a menu is invoked pass along the input parameter
// to the appropriate MenuBase class instance
auto param = getValue<input_PARAM_IN>(ctx);
state->menu_cursor.invoke(param);
}
//Update the menu dispaly text
auto text_list = state->menu_cursor.text();
auto text_it = text_list.iterate();
emitValue<output_LINE1>(ctx, *text_it);
if (++text_it) {
emitValue<output_LINE2>(ctx, *text_it);
} else {
emitValue<output_LINE2>(ctx, null_string);
return;
}
if (++text_it) {
emitValue<output_LINE3>(ctx, *text_it);
} else {
emitValue<output_LINE3>(ctx, null_string);
return;
}
if (++text_it) {
emitValue<output_LINE4>(ctx, *text_it);
} else {
emitValue<output_LINE4>(ctx, null_string);
return;
}
}