menu-controller

bitrex/xod-menu-system/menu-controller

No description
menu-controller
@/menu-controller
MENU_TREE@/leaf-menu-item-impl
TITLE_1string
TITLE_2string
RIGHTpulse
LEFTpulse
BACKpulse
INVOKEpulse
TOPpulse
PARAM_INnumber
menu-controller
MENU_TREE
TITLE_1
TITLE_2
RIGHT
LEFT
BACK
INVOKE
TOP
PARAM_IN
LINE1
LINE2
LINE3
LINE4
LINE4string
LINE3string
LINE2string
LINE1string
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;
  }
}