branch-menu-item

bitrex/xod-menu-system/branch-menu-item

No description
branch-menu-item
@/branch-menu-item
IN@/leaf-menu-item-impl
LINE1string
LINE2string
IDbyte
branch-menu-item
OUT
IN
LINE1
LINE2
ID
OUT@/leaf-menu-item-impl
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));
  }
}