concat-menu

bitrex/xod-menu-system-11/concat-menu

No description
concat-menu
@/concat-menu
IN1@/leaf-menu-item-impl
IN2@/leaf-menu-item-impl (variadic)
concat-menu
IN1
IN2
OUT
OUT@/leaf-menu-item-impl
To use the node in your project you should have the bitrex/xod-menu-system-11 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;

/* A derived type of BiDirectionalListView, used to concatenate two
   bi-directional lists and iterate forward and backwards over both
   as a single unit. This can also be instantiated recursively. See
   e.g. the XOD standard library class "ConcatListView"*/

template <typename T>
class BiDirectionalConcatListView : public menu_base::BiDirectionalListView<T> {
 public:
  class Cursor : public menu_base::BiDirectionalCursor<T> {
   public:
     Cursor(const BiDirectionalConcatListView<T>* owner)
        : _left(std::move(owner->_left.biterate())),
          _right(std::move(owner->_right.biterate())),
          _owner(owner) {}

    bool isValid() const override { return _left && _right; }

    bool value(T* out) const override {
      return _cursor < _owner->_length_left ? _left.value(out) : _right.value(out);
    }

    void next() override {
      const auto total = _owner->_length_left + _owner->_length_right;
      if (_cursor < _owner->_length_left - 1) {
        ++_left;
      } else if (_cursor >= _owner->_length_left - 1 && _cursor < total) {
        if (_cursor != _owner->_length_left - 1) {
          ++_right;
        }
      }
      ++_cursor;
    }

    void prev() override {
      const auto total = _owner->_length_left + _owner->_length_right;
      if (_cursor > _owner->_length_left - 1 && _cursor != total - _owner->_length_right) {
        --_right;
      } else if (_cursor <= _owner->_length_left - 1) {
        --_left;
      }
      if (_cursor) {
        --_cursor;
      }
    }

   private:
    menu_base::BiDirectionalIterator<T> _left;
    menu_base::BiDirectionalIterator<T> _right;
    const BiDirectionalConcatListView<T>* _owner;
    size_t _cursor = 0;
  };

 public:
  BiDirectionalConcatListView() = default;

  BiDirectionalConcatListView(menu_base::BiDirectionalList<T> left,
                              menu_base::BiDirectionalList<T> right)
      : _left(left), _right(right), _length_left(length(left)), _length_right(length(right)) {}

  BiDirectionalConcatListView& operator=(
      const BiDirectionalConcatListView& rhs) {
    _left = rhs._left;
    _right = rhs._right;
    _length_left = rhs._length_left;
    _length_right = rhs._length_right;
    return *this;
  }

  Iterator<T> iterate() const override {
     return Iterator<T>(new Cursor(this));
  }

  menu_base::BiDirectionalIterator<T> biterate() const override {
    return menu_base::BiDirectionalIterator<T>(new Cursor(this));
  }

 private:
  friend class Cursor;
  menu_base::BiDirectionalList<T> _left;
  menu_base::BiDirectionalList<T> _right;
  size_t _length_left;
  size_t _length_right;
};

/* The state for this node contains a BiDirectionalConcatListView
   of over the two BiDirectionalLists of menu_base_t-type pointers
   it accepts as  inputs. This node is employed variadically so there
   will be an additional BiDirectionalConcatListView-containing state
   genearted for each additional input created beyond the first two. */

struct State {
    BiDirectionalConcatListView<menu_base_t*> menu_ptr_list_view;
};

{{ GENERATED_CODE }}

void evaluate(Context ctx) {
    if(isSettingUp()) {
        using menu_base::BiDirectionalList;
        auto state = getState(ctx);
        const auto in1 = getValue<input_IN1>(ctx);
        const auto in2 = getValue<input_IN2>(ctx);
        //create a new concat-view join the incoming lists once on startup,
        //the outputs remain static after that
        state->menu_ptr_list_view = BiDirectionalConcatListView<menu_base_t*>(in1, in2);
        //output is a list that can be further concatenated
        emitValue<output_OUT>(ctx, BiDirectionalList<menu_base_t*>(&state->menu_ptr_list_view));
    }
}