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
/* include the base class type of a Menu item */
namespace menu_base = ____menu_base;
using menu_base_t = menu_base::MenuBase;
/* A wrapper for a raw BiDirectionalList that allows a Branch-type
menu to retain/manage location state when the user is paging thru its
sub-menus */
template <typename MenuBase>
class SubMenuIterator {
public:
SubMenuIterator() = default;
explicit SubMenuIterator(menu_base::BiDirectionalList<MenuBase*> sub_menus) :
sub_menu_ptr_list_(sub_menus), length_(xod::length(sub_menus)) {}
menu_base::BiDirectionalList<MenuBase*> menu_ptr_list() const {
return sub_menu_ptr_list_;
}
SubMenuIterator<MenuBase>& operator++() {
if (cursor_ < length_ - 1) ++cursor_;
return *this;
}
SubMenuIterator<MenuBase>& operator--() {
if (cursor_ > 0) --cursor_;
return *this;
}
MenuBase* current_menu_ptr() {
auto it = sub_menu_ptr_list_.iterate();
for (uint8_t i = 0; i < cursor_; ++i) { ++it; }
return *it;
}
void reset() {
cursor_ = 0;
}
private:
menu_base::BiDirectionalList<MenuBase*> sub_menu_ptr_list_;
uint8_t length_ = 0;
uint8_t cursor_ = 0;
};
/* An interface class for a Branch-type menu page which inherits the default
MenuInterface methods plus additional Branch-type specific methods to allow
navigation thru its sub-menus. */
template <typename MenuBase, template <typename> class BranchMenuImpl>
class BranchMenuInterface : public menu_base::MenuInterface<MenuBase, BranchMenuImpl> {
public:
MenuBase* sub_menu_ptr() {
return static_cast<BranchMenuImpl<MenuBase>*>(this)->sub_menu_ptr_();
}
MenuBase* next() {
return static_cast<BranchMenuImpl<MenuBase>*>(this)->next_();
}
MenuBase* prev() {
return static_cast<BranchMenuImpl<MenuBase>*>(this)->prev_();
}
BranchMenuImpl<MenuBase>* parent() {
return static_cast<BranchMenuImpl<MenuBase>*>(this)->parent_();
}
void set_parent(BranchMenuImpl<MenuBase>* parent) {
static_cast<BranchMenuImpl<MenuBase>*>(this)->set_parent_(parent);
}
};
/* an implementation of a Branch-type menu page satisfying the requirements
from the above interface. */
template <typename MenuBase>
class BranchMenuImpl final
: public BranchMenuInterface<MenuBase, BranchMenuImpl>,
public MenuBase {
friend class menu_base::MenuInterface<MenuBase, BranchMenuImpl>;
friend class BranchMenuInterface<MenuBase, BranchMenuImpl>;
public:
constexpr BranchMenuImpl()
: MenuBase(0),
menu_text_lines_view_(PlainListView<XString>(nullptr, 0)) {}
BranchMenuImpl(menu_base::BiDirectionalList<MenuBase*> sub_menu_ptr_list,
XString menu_text_1, XString menu_text_2, Number user_id)
: MenuBase(user_id),
menu_text_({menu_text_1, menu_text_2}),
menu_text_lines_view_(PlainListView<XString>(menu_text_, 2)),
sub_menu_it_(SubMenuIterator<MenuBase>(sub_menu_ptr_list))
{}
protected:
List<XString> text_() override {
menu_text_lines_view_ = PlainListView<XString>(menu_text_, 2);
return List<XString>(&menu_text_lines_view_);
}
MenuBase* invoke_(Number /* param */) override {
sub_menu_it_.reset();
return this;
}
MenuBase* sub_menu_ptr_() {
return sub_menu_it_.current_menu_ptr();
}
MenuBase* next_() {
++sub_menu_it_;
return sub_menu_it_.current_menu_ptr();
}
MenuBase* prev_() {
--sub_menu_it_;
return sub_menu_it_.current_menu_ptr();
}
BranchMenuImpl<MenuBase>* parent_() const {
return parent_ptr_;
}
void set_parent_(BranchMenuImpl<MenuBase>* parent) {
parent_ptr_ = parent;
}
private:
XString menu_text_[2];
PlainListView<XString> menu_text_lines_view_;
SubMenuIterator<MenuBase> sub_menu_it_;
BranchMenuImpl<MenuBase>* parent_ptr_ = nullptr;
};
/* The state for this node contains an instance of a Branch-type menu class
plus a ListView, so that the node can output a List-type wrapper holding its
pointer, so that its pointer can be appended into further lists of Menu-type
pointers to allow automatic construction of a tree-like data structure. */
struct State {
BranchMenuImpl<menu_base_t> branch_menu;
menu_base_t* branch_menu_ptr;
menu_base::BiDirectionalPlainListView<menu_base_t*> branch_menu_ptr_view =
menu_base::BiDirectionalPlainListView<menu_base_t*>(&branch_menu_ptr, 1);
};
{{ GENERATED_CODE }}
void evaluate(Context ctx) {
if (isSettingUp()) {
using menu_base::BiDirectionalList;
auto state = getState(ctx);
auto in = getValue<input_IN>(ctx);
auto text1 = getValue<input_LINE1>(ctx);
auto text2 = getValue<input_LINE2>(ctx);
auto id = getValue<input_ID>(ctx);
state->branch_menu = BranchMenuImpl<menu_base_t>(in, text1, text2, id);
state->branch_menu_ptr = &state->branch_menu;
emitValue<output_OUT>(ctx, menu_base::BiDirectionalList<menu_base_t*>(&state->branch_menu_ptr_view));
}
}