TermOx
menu_stack.hpp
1 #ifndef TERMOX_WIDGET_WIDGETS_MENU_STACK_HPP
2 #define TERMOX_WIDGET_WIDGETS_MENU_STACK_HPP
3 #include <cstddef>
4 #include <memory>
5 #include <utility>
6 
7 #include <termox/painter/glyph_string.hpp>
8 #include <termox/system/system.hpp>
9 #include <termox/widget/focus_policy.hpp>
10 #include <termox/widget/layouts/stack.hpp>
11 #include <termox/widget/widgets/menu.hpp>
12 
13 namespace ox {
14 
15 // maybe TODO
16 // You could simplify the index math if you hold:
17 // STuple<Main_menu, layout::Stack<Child_t>> and make it a template on Child_t
18 // Then the widgets are in their own stack, you arn't mixing, and you can also
19 // have a template parameter if you only want to hold a specific type of Widget,
20 // since this is a layout technically.
21 
23 
24 class Menu_stack : public layout::Stack<Widget> {
25  private:
26  static auto constexpr menu_index_ = 0uL;
27 
28  public:
30  Menu_stack() : menu_{this->Stack::make_page<Menu>()}
31  {
32  this->Stack::set_active_page(menu_index_);
33  this->focus_policy = Focus_policy::Direct;
34  }
35 
36  public:
38 
42  template <typename Widget_t, typename... Args>
43  auto make_page(Glyph_string title, Args&&... args) -> Widget_t&
44  {
45  static_assert(std::is_base_of<Widget, Widget_t>::value,
46  "Menu_stack::make_page: Widget_t must be a Widget type");
47  auto& child =
48  this->Stack::make_page<Widget_t>(std::forward<Args>(args)...);
49  this->connect_to_menu(std::move(title), this->Stack::size() - 1);
50  return child;
51  }
52 
54  template <typename Widget_t>
55  void append_page(Glyph_string title, std::unique_ptr<Widget_t> w_ptr)
56  {
57  static_assert(
58  std::is_base_of<Child_t, Widget_t>::value,
59  "Menu_stack::append_page: Widget_t must be a Child_t type");
60  this->Stack::append_page(std::move(w_ptr));
61  this->connect_to_menu(std::move(title), this->Stack::size() - 1);
62  }
63 
65 
67  std::unique_ptr<Widget> widget,
68  std::size_t index)
69  {
70  this->Stack::insert_page(std::move(widget), index + 1);
71  this->connect_to_menu(std::move(title), index + 1);
72  }
73 
75 
77  void delete_page(std::size_t index)
78  {
79  this->remove_from_menu(index + 1);
80  this->Stack::delete_page(index + 1);
81  }
82 
84 
87  [[nodiscard]] auto remove_page(std::size_t index) -> std::unique_ptr<Widget>
88  {
89  this->remove_from_menu(index + 1);
90  return this->Stack::remove_page(index + 1);
91  }
92 
94  void clear()
95  {
96  this->goto_menu();
97  // Can't use a range-for loop, delete_page modifies the child_list_
98  while (this->child_count() > 1)
99  this->delete_page(1);
100  }
101 
103  [[nodiscard]] auto size() const -> std::size_t
104  {
105  return this->Stack::size() - 1;
106  }
107 
109  [[nodiscard]] auto menu() -> Menu& { return menu_; }
110 
112  [[nodiscard]] auto menu() const -> Menu const& { return menu_; }
113 
115  void goto_menu() { this->Stack::set_active_page(menu_index_); }
116 
118  void set_active_page(std::size_t index)
119  {
120  this->Stack::set_active_page(index + 1);
121  }
122 
123  private:
124  Menu& menu_;
125 
126  private:
128 
129  void remove_from_menu(std::size_t index)
130  {
131  menu_.remove_item(index - 1);
132  if (this->Stack::active_page_index() == index)
133  this->Stack::set_active_page(menu_index_);
134  }
135 
137 
138  void connect_to_menu(Glyph_string title, std::size_t index)
139  {
140  auto& signal = menu_.insert_item(std::move(title), index - 1);
141  signal.connect(slot::set_active_page(*this, index));
142  }
143 };
144 
146 template <typename... Args>
147 [[nodiscard]] auto menu_stack(Args&&... args) -> std::unique_ptr<Menu_stack>
148 {
149  return std::make_unique<Menu_stack>(std::forward<Args>(args)...);
150 }
151 
152 } // namespace ox
153 #endif // TERMOX_WIDGET_WIDGETS_MENU_STACK_HPP
Holds a collection of Glyphs with a similar interface to std::string.
Definition: glyph_string.hpp:19
A Stack layout with a Menu to switch between pages.
Definition: menu_stack.hpp:24
void append_page(Glyph_string title, std::unique_ptr< Widget_t > w_ptr)
Add an existing Widget as a page to the end of the Stack.
Definition: menu_stack.hpp:55
auto menu() -> Menu &
Return reference to the Menu Widget at the front of the Stack.
Definition: menu_stack.hpp:109
void set_active_page(std::size_t index)
Set the active page, first page is index 0, etc...
Definition: menu_stack.hpp:118
auto remove_page(std::size_t index) -> std::unique_ptr< Widget >
Remove a page from the Stack, by index value, and return it.
Definition: menu_stack.hpp:87
void clear()
Remove and delete all pages except menu.
Definition: menu_stack.hpp:94
auto size() const -> std::size_t
Return the number of pages in this Stack, not including the Menu Widget.
Definition: menu_stack.hpp:103
Menu_stack()
Construct an empty Menu_stack.
Definition: menu_stack.hpp:30
auto menu() const -> Menu const &
Return const reference to the Menu Widget at the front of the Stack.
Definition: menu_stack.hpp:112
void delete_page(std::size_t index)
Remove a page from the Stack, by index value, and delete it.
Definition: menu_stack.hpp:77
void insert_page(Glyph_string title, std::unique_ptr< Widget > widget, std::size_t index)
Insert a Widget at index.
Definition: menu_stack.hpp:66
void goto_menu()
Set the active page to the menu, useful to control returning to menu.
Definition: menu_stack.hpp:115
auto make_page(Glyph_string title, Args &&... args) -> Widget_t &
Construct and append a page to the Stack.
Definition: menu_stack.hpp:43
Definition: menu.hpp:55
void remove_item(std::size_t index)
Remove item a index in the Menu_list, no-op if index is invalid.
Definition: menu.cpp:95
auto insert_item(Glyph_string label, std::size_t index) -> sl::Signal< void()> &
Insert item at index into the Menu_list, displayed with label.
Definition: menu.cpp:89
auto child_count() const -> std::size_t
Return the number of children held by this Widget.
Definition: widget.cpp:198
Focus_policy focus_policy
Describes how focus is given to this Widget.
Definition: widget.hpp:93
A Layout enabling only a single Widget at a time.
Definition: stack.hpp:29