TermOx
tuple.hpp
1 #ifndef TERMOX_WIDGET_TUPLE_HPP
2 #define TERMOX_WIDGET_TUPLE_HPP
3 #include <memory>
4 #include <tuple>
5 #include <type_traits>
6 #include <utility>
7 
8 #include <termox/widget/layouts/horizontal.hpp>
9 #include <termox/widget/layouts/stack.hpp>
10 #include <termox/widget/layouts/vertical.hpp>
11 
12 namespace ox {
13 
15 
16 template <typename Layout_t, typename... Widget_t>
17 class Tuple : public Layout_t {
18  public:
19  using Parameters = std::tuple<typename Widget_t::Parameters...>;
20 
21  public:
24  : refs_{this->indexed_init_children(
25  std::index_sequence_for<Widget_t...>())}
26  {}
27 
29  explicit Tuple(typename Widget_t::Parameters... p)
30  : refs_{this->indexed_init_children(
31  std::index_sequence_for<Widget_t...>(),
32  std::move(p)...)}
33  {}
34 
36  explicit Tuple(Tuple::Parameters p)
37  : refs_{this->tuple_init_children(
38  std::make_index_sequence<std::tuple_size_v<Tuple::Parameters>>(),
39  std::move(p))}
40  {}
41 
43  explicit Tuple(std::unique_ptr<Widget_t>... widget_ptrs)
44  : refs_{this->indexed_move_children(
45  std::index_sequence_for<Widget_t...>(),
46  std::move(widget_ptrs)...)}
47  {}
48 
49  public:
51  template <std::size_t Index>
52  [[nodiscard]] auto get() -> auto&
53  {
54  return std::get<Index>(refs_);
55  }
56 
58  template <std::size_t Index>
59  [[nodiscard]] auto get() const -> auto const&
60  {
61  return std::get<Index>(refs_);
62  }
63 
64  private:
65  std::tuple<Widget_t&...> refs_;
66 
67  private:
68  template <std::size_t... Is>
69  [[nodiscard]] auto indexed_init_children(std::index_sequence<Is...>)
70  {
71  (this->append_child(std::make_unique<Widget_t>()), ...);
72  auto children = this->get_children();
73  return std::forward_as_tuple(static_cast<Widget_t&>(children[Is])...);
74  }
75 
76  template <std::size_t... Is>
77  [[nodiscard]] auto indexed_init_children(std::index_sequence<Is...>,
78  typename Widget_t::Parameters... p)
79  {
80  // Default construct Widget_t if it doesn't have Parameters constructor.
81  // All widgets have Parameters struct inherited from Widget.
82  (this->append_child([&] {
83  if constexpr (std::is_constructible_v<
84  Widget_t, typename Widget_t::Parameters>)
85  return std::make_unique<Widget_t>(std::move(p));
86  else
87  return std::make_unique<Widget_t>();
88  }()),
89  ...);
90  auto children = this->get_children();
91  return std::forward_as_tuple(static_cast<Widget_t&>(children[Is])...);
92  }
93 
94  template <std::size_t... Is>
95  [[nodiscard]] auto indexed_move_children(
96  std::index_sequence<Is...>,
97  std::unique_ptr<Widget_t>... widget_ptrs)
98  {
99  (this->append_child(std::move(widget_ptrs)), ...);
100  auto children = this->get_children();
101  return std::forward_as_tuple(static_cast<Widget_t&>(children[Is])...);
102  }
103 
104  template <std::size_t... Is>
105  [[nodiscard]] auto tuple_init_children(std::index_sequence<Is...>,
106  Tuple::Parameters parameters)
107  {
108  (this->append_child(
109  std::make_unique<Widget_t>(std::move(std::get<Is>(parameters)))),
110  ...);
111  auto children = this->get_children();
112  return std::forward_as_tuple(static_cast<Widget_t&>(children[Is])...);
113  }
114 
115  private:
116  using Layout_t::append_child;
117  using Layout_t::delete_all_children;
118  using Layout_t::insert_child;
119  using Layout_t::make_child;
120  using Layout_t::remove_and_delete_child;
121  using Layout_t::remove_and_delete_child_at;
122  using Layout_t::remove_and_delete_child_if;
123  using Layout_t::remove_child;
124  using Layout_t::remove_child_at;
125  using Layout_t::remove_child_if;
126  using Layout_t::swap_children;
127 };
128 
130 template <typename Layout_t, typename... Widget_t>
131 [[nodiscard]] auto tuple() -> std::unique_ptr<Tuple<Layout_t, Widget_t...>>
132 {
133  return std::make_unique<Tuple<Layout_t, Widget_t...>>();
134 }
135 
137 template <typename Layout_t, typename... Widget_t>
138 [[nodiscard]] auto tuple(typename Widget_t::Parameters... p)
139  -> std::unique_ptr<Tuple<Layout_t, Widget_t...>>
140 {
141  return std::make_unique<Tuple<Layout_t, Widget_t...>>(std::move(p)...);
142 }
143 
145 template <typename Layout_t, typename... Widget_t>
146 [[nodiscard]] auto tuple(std::unique_ptr<Widget_t>... widget_ptrs)
147  -> std::unique_ptr<Tuple<Layout_t, Widget_t...>>
148 {
149  return std::make_unique<Tuple<Layout_t, Widget_t...>>(
150  std::move(widget_ptrs)...);
151 }
152 
154 template <typename... Widget_t>
155 using VTuple = Tuple<layout::Vertical<>, Widget_t...>;
156 
158 template <typename... Widget_t>
159 [[nodiscard]] auto vtuple() -> std::unique_ptr<VTuple<Widget_t...>>
160 {
161  return std::make_unique<VTuple<Widget_t...>>();
162 }
163 
165 template <typename... Widget_t>
166 [[nodiscard]] auto vtuple(typename Widget_t::Parameters... p)
167  -> std::unique_ptr<VTuple<Widget_t...>>
168 {
169  return std::make_unique<VTuple<Widget_t...>>(std::move(p)...);
170 }
171 
173 template <typename... Widget_t>
174 [[nodiscard]] auto vtuple(std::unique_ptr<Widget_t>... widget_ptrs)
175  -> std::unique_ptr<VTuple<Widget_t...>>
176 {
177  return std::make_unique<VTuple<Widget_t...>>(std::move(widget_ptrs)...);
178 }
179 
181 template <typename... Widget_t>
182 using HTuple = Tuple<layout::Horizontal<>, Widget_t...>;
183 
185 template <typename... Widget_t>
186 [[nodiscard]] auto htuple() -> std::unique_ptr<HTuple<Widget_t...>>
187 {
188  return std::make_unique<HTuple<Widget_t...>>();
189 }
190 
192 template <typename... Widget_t>
193 [[nodiscard]] auto htuple(typename Widget_t::Parameters... p)
194  -> std::unique_ptr<HTuple<Widget_t...>>
195 {
196  return std::make_unique<HTuple<Widget_t...>>(std::move(p)...);
197 }
198 
200 template <typename... Widget_t>
201 [[nodiscard]] auto htuple(std::unique_ptr<Widget_t>... widget_ptrs)
202  -> std::unique_ptr<HTuple<Widget_t...>>
203 {
204  return std::make_unique<HTuple<Widget_t...>>(std::move(widget_ptrs)...);
205 }
206 
208 template <typename... Widget_t>
209 using STuple = Tuple<layout::Stack<>, Widget_t...>;
210 
212 template <typename... Widget_t>
213 [[nodiscard]] auto stuple() -> std::unique_ptr<STuple<Widget_t...>>
214 {
215  return std::make_unique<STuple<Widget_t...>>();
216 }
217 
219 template <typename... Widget_t>
220 [[nodiscard]] auto stuple(typename Widget_t::Parameters... p)
221  -> std::unique_ptr<STuple<Widget_t...>>
222 {
223  return std::make_unique<STuple<Widget_t...>>(std::move(p)...);
224 }
225 
227 template <typename... Widget_t>
228 [[nodiscard]] auto stuple(std::unique_ptr<Widget_t>... widget_ptrs)
229  -> std::unique_ptr<STuple<Widget_t...>>
230 {
231  return std::make_unique<STuple<Widget_t...>>(std::move(widget_ptrs)...);
232 }
233 
234 } // namespace ox
235 #endif // TERMOX_WIDGET_TUPLE_HPP
Heterogeneous collection of Widgets within a Layout_t.
Definition: tuple.hpp:17
auto get() -> auto &
Get child by index.
Definition: tuple.hpp:52
Tuple()
Default construct each Widget.
Definition: tuple.hpp:23
Tuple(std::unique_ptr< Widget_t >... widget_ptrs)
Move existing Widgets into a Tuple.
Definition: tuple.hpp:43
auto get() const -> auto const &
Get child by index.
Definition: tuple.hpp:59
Tuple(typename Widget_t::Parameters... p)
Construct each Widget with a Widget_t::Parameters object.
Definition: tuple.hpp:29
Tuple(Tuple::Parameters p)
Construct from a Tuple::Parameters object.
Definition: tuple.hpp:36