TermOx
layout.hpp
1 #ifndef TERMOX_WIDGET_LAYOUT_HPP
2 #define TERMOX_WIDGET_LAYOUT_HPP
3 #include <algorithm>
4 #include <cstddef>
5 #include <memory>
6 #include <type_traits>
7 #include <utility>
8 #include <vector>
9 
10 #include <termox/common/transform_view.hpp>
11 #include <termox/system/event.hpp>
12 #include <termox/system/system.hpp>
13 #include <termox/widget/area.hpp>
14 #include <termox/widget/point.hpp>
15 #include <termox/widget/widget.hpp>
16 
17 namespace ox::layout {
18 
20 
22 template <typename Child = Widget>
23 class Layout : public Widget {
24  public:
25  using Child_t = Child;
26 
27  struct Parameters {
28  std::vector<std::unique_ptr<Child_t>> children;
29  };
30 
31  static_assert(std::is_base_of_v<Widget, Child_t>,
32  "Layout: Child type must be a Widget type.");
33 
34  private:
35  template <typename UnaryPredicate>
36  using enable_if_invocable = std::enable_if_t<
37  std::is_invocable_v<UnaryPredicate,
38  std::add_lvalue_reference_t<Child_t>>,
39  int>;
40 
41  public:
42  template <typename... Widgets>
43  Layout(std::unique_ptr<Widgets>... children)
44  {
45  (this->append_child(std::move(children)), ...);
46  }
47 
48  Layout(Parameters parameters)
49  {
50  for (auto& child : parameters.children)
51  this->append_child(std::move(child));
52  }
53 
54  public:
56  [[nodiscard]] auto get_children()
57  {
58  auto constexpr downcast = [](auto& widg_ptr) -> Child_t& {
59  return static_cast<Child_t&>(*widg_ptr);
60  };
61  return Transform_view(children_, downcast);
62  }
63 
65  [[nodiscard]] auto get_children() const
66  {
67  auto constexpr downcast = [](auto const& widg_ptr) -> Child_t const& {
68  return static_cast<Child_t const&>(*widg_ptr);
69  };
70  return Transform_view(children_, downcast);
71  }
72 
74 
77  template <typename Widget_t>
78  auto insert_child(std::unique_ptr<Widget_t> w, std::size_t index)
79  -> Widget_t&
80  {
81  static_assert(std::is_base_of_v<Child_t, Widget_t>,
82  "Layout::insert: Widget_t must be a Child_t type");
83  assert(index <= this->child_count());
84  auto& inserted = *w;
85  children_.emplace(this->iter_at(index), std::move(w));
86  inserted.set_parent(this);
87  inserted.enable(this->is_enabled());
88  System::post_event(Child_added_event{*this, inserted});
89  return inserted;
90  }
91 
93 
94  template <typename Widget_t>
95  auto append_child(std::unique_ptr<Widget_t> w) -> Widget_t&
96  {
97  return this->insert_child(std::move(w), this->child_count());
98  }
99 
101 
102  template <typename Widget_t = Child_t, typename... Args>
103  auto make_child(Args&&... args) -> Widget_t&
104  {
105  return this->append_child(
106  std::make_unique<Widget_t>(std::forward<Args>(args)...));
107  }
108 
110  template <typename Widget_t = Child_t>
111  auto make_child(typename Widget_t::Parameters p) -> Widget_t&
112  {
113  return this->append_child(std::make_unique<Widget_t>(std::move(p)));
114  }
115 
117 
118  [[nodiscard]] auto remove_child(Child_t const* child)
119  -> std::unique_ptr<Widget>
120  {
121  auto const at = this->find_iter(child);
122  if (at == std::end(children_))
123  return nullptr;
124  auto removed = this->iter_remove(at);
125  this->uninitialize(*removed);
126  return removed;
127  }
128 
130 
131  template <typename UnaryPredicate,
132  typename = enable_if_invocable<UnaryPredicate>>
133  [[nodiscard]] auto remove_child_if(UnaryPredicate&& predicate)
134  -> std::unique_ptr<Widget>
135  {
136  Widget* found =
137  this->find_child_if(std::forward<UnaryPredicate>(predicate));
138  return this->remove_child(found);
139  }
140 
142 
143  [[nodiscard]] auto remove_child_at(std::size_t index)
144  -> std::unique_ptr<Widget>
145  {
146  if (index >= this->child_count())
147  return nullptr;
148  auto removed = this->iter_remove(this->iter_at(index));
149  this->uninitialize(*removed);
150  return removed;
151  }
152 
154 
155  auto remove_and_delete_child(Child_t const* child) -> bool
156  {
157  auto removed = this->remove_child(child);
158  if (removed == nullptr)
159  return false;
160  System::post_event(Delete_event{std::move(removed)});
161  return true;
162  }
163 
165 
166  template <typename UnaryPredicate,
167  typename = enable_if_invocable<UnaryPredicate>>
168  auto remove_and_delete_child_if(UnaryPredicate&& predicate) -> bool
169  {
170  Widget* found =
171  this->find_child_if(std::forward<UnaryPredicate>(predicate));
172  if (found == nullptr)
173  return false;
174  this->remove_and_delete_child(found);
175  return true;
176  }
177 
179 
180  auto remove_and_delete_child_at(std::size_t index) -> bool
181  {
182  auto removed = this->remove_child_at(index);
183  if (removed == nullptr)
184  return false;
185  System::post_event(Delete_event{std::move(removed)});
186  return true;
187  }
188 
191  {
192  while (this->child_count() != 0)
194  }
195 
197  void swap_children(std::size_t index_a, std::size_t index_b)
198  {
199  std::iter_swap(this->iter_at(index_a), this->iter_at(index_b));
200  System::post_event(Child_polished_event{*this, *children_[index_b]});
201  System::post_event(Child_polished_event{*this, *children_[index_a]});
202  }
203 
205 
207  template <typename UnaryPredicate>
208  [[nodiscard]] auto find_child_if(UnaryPredicate&& predicate) const
209  -> Child_t const*
210  {
211  auto const view = this->get_children();
212  auto const found =
213  std::find_if(std::cbegin(view), std::cend(view),
214  std::forward<UnaryPredicate>(predicate));
215  return found == std::cend(view) ? nullptr : std::addressof(*found);
216  }
217 
219 
221  template <typename UnaryPredicate>
222  [[nodiscard]] auto find_child_if(UnaryPredicate&& predicate) -> Child_t*
223  {
224  auto view = this->get_children();
225  auto const found =
226  std::find_if(std::begin(view), std::end(view),
227  std::forward<UnaryPredicate>(predicate));
228  return found == std::end(view) ? nullptr : std::addressof(*found);
229  }
230 
232  [[nodiscard]] auto find_child_by_name(std::string const& name) -> Child_t*
233  {
234  return this->find_child_if(
235  [&](Child_t const& w) { return w.name() == name; });
236  }
237 
239  [[nodiscard]] auto find_child_by_name(std::string const& name) const
240  -> Child_t const*
241  {
242  return this->find_child_if(
243  [&](Child_t const& w) { return w.name() == name; });
244  }
245 
247 
248  [[nodiscard]] auto find_child_position(Widget const* w) const -> std::size_t
249  {
250  auto const found = std::find_if(
251  std::cbegin(children_), std::cend(children_),
252  [w](std::unique_ptr<Widget> const& x) { return x.get() == w; });
253  if (found == std::cend(children_))
254  return -1uL;
255  return std::distance(std::cbegin(children_), found);
256  }
257 
259  [[nodiscard]] auto contains_child(Widget const* w) const -> bool
260  {
261  auto const begin = std::cbegin(children_);
262  auto const end = std::cend(children_);
263  return std::find_if(begin, end, [w](auto const& w_ptr) {
264  return w_ptr.get() == w;
265  }) != end;
266  }
267 
269 
270  [[nodiscard]] auto contains_descendant(Widget const* descendant) const
271  -> bool
272  {
273  auto const d = this->get_descendants();
274  return std::find(std::begin(d), std::end(d), descendant) != std::end(d);
275  }
276 
277  void update() final override {}
278 
279  protected:
280  struct Dimensions {
281  Widget* widget;
282  std::size_t width;
283  std::size_t height;
284  };
285 
287  Widget* widget;
288  std::size_t* width;
289  std::size_t* height;
290  };
291 
292  private:
294  [[nodiscard]] auto iter_at(std::size_t index) -> Children_t::iterator
295  {
296  return std::next(std::begin(children_), index);
297  }
298 
300  [[nodiscard]] auto iter_at(std::size_t index) const
301  -> Children_t::const_iterator
302  {
303  return std::next(std::cbegin(children_), index);
304  }
305 
307  [[nodiscard]] auto is_target(Child_t const* target)
308  {
309  return [target](std::unique_ptr<Widget> const& w) -> bool {
310  return w.get() == target;
311  };
312  }
313 
315  [[nodiscard]] auto find_iter(Child_t const* w) const
316  -> Children_t::const_iterator
317  {
318  return std::find_if(std::cbegin(children_), std::cend(children_),
319  is_target(w));
320  }
321 
323  [[nodiscard]] auto find_iter(Child_t const* w) -> Children_t::iterator
324  {
325  return std::find_if(std::begin(children_), std::end(children_),
326  is_target(w));
327  }
328 
330  [[nodiscard]] auto iter_remove(Children_t::iterator at)
331  -> std::unique_ptr<Widget>
332  {
333  auto removed = std::move(*at);
334  children_.erase(at);
335  return removed;
336  }
337 
339  void uninitialize(Widget& w)
340  {
341  w.disable();
342  System::post_event(Child_removed_event{*this, w});
343  w.set_parent(nullptr);
344  }
345 
347  [[nodiscard]] auto is_layout_type() const -> bool final override
348  {
349  return true;
350  }
351 };
352 
353 } // namespace ox::layout
354 #endif // TERMOX_WIDGET_LAYOUT_HPP
static void post_event(Event e)
Append the event to the Event_queue for the thread it was called on.
Definition: system.cpp:112
Read only Container view that applies transformation to elements at access.
Definition: transform_view.hpp:16
Definition: widget.hpp:31
Widget(std::string name="", Focus_policy focus_policy_=Focus_policy::None, Size_policy width_policy_=Size_policy{}, Size_policy height_policy_=Size_policy{}, Brush brush_=Brush{}, Glyph wallpaper=U' ', bool brush_paints_wallpaper=true, Cursor cursor=Cursor{})
Create an empty Widget.
Definition: widget.cpp:40
auto is_enabled() const -> bool
Check whether the Widget is enabled.
Definition: widget.cpp:102
auto get_descendants() const -> std::vector< Widget * >
Return container of all descendants of self_.
Definition: widget.cpp:165
auto name() const -> std::string const &
Return the name of the Widget.
Definition: widget.cpp:77
auto child_count() const -> std::size_t
Return the number of children held by this Widget.
Definition: widget.cpp:198
Provided as a uniform interface for arranging child Widgets.
Definition: layout.hpp:23
auto remove_and_delete_child_if(UnaryPredicate &&predicate) -> bool
Erase first element that satisfies pred.
Definition: layout.hpp:168
auto get_children()
Return a View of all children.
Definition: layout.hpp:56
auto remove_child(Child_t const *child) -> std::unique_ptr< Widget >
Removes and returns the child pointed to by child.
Definition: layout.hpp:118
auto find_child_by_name(std::string const &name) -> Child_t *
Find a child widget by name, returns nullptr if not found.
Definition: layout.hpp:232
void update() final override
Post a paint event to this Widget.
Definition: layout.hpp:277
auto contains_child(Widget const *w) const -> bool
Returns true if w is a child of *this.
Definition: layout.hpp:259
auto remove_and_delete_child_at(std::size_t index) -> bool
Removes the child at index and sends a Delete_event to it.
Definition: layout.hpp:180
auto remove_and_delete_child(Child_t const *child) -> bool
Removes the child with given pointer and sends a Delete_event to it.
Definition: layout.hpp:155
auto contains_descendant(Widget const *descendant) const -> bool
Returns true if descendant is a child or some other child's child etc.
Definition: layout.hpp:270
void swap_children(std::size_t index_a, std::size_t index_b)
Swap two child widgets, no index range check.
Definition: layout.hpp:197
auto find_child_position(Widget const *w) const -> std::size_t
Finds the index of the given child pointer in the child container.
Definition: layout.hpp:248
auto find_child_if(UnaryPredicate &&predicate) const -> Child_t const *
Find first child satisfying predicate.
Definition: layout.hpp:208
auto insert_child(std::unique_ptr< Widget_t > w, std::size_t index) -> Widget_t &
Inserts w at index, sending child added event to *this.
Definition: layout.hpp:78
auto find_child_if(UnaryPredicate &&predicate) -> Child_t *
Find first child satisfying predicate.
Definition: layout.hpp:222
auto get_children() const
Return a const View of all children.
Definition: layout.hpp:65
auto make_child(Args &&... args) -> Widget_t &
Create a Widget and append it to the child container.
Definition: layout.hpp:103
auto remove_child_at(std::size_t index) -> std::unique_ptr< Widget >
Removes and returns the child at index in the child container.
Definition: layout.hpp:143
void delete_all_children()
Removes all children and sends Delete_events to each.
Definition: layout.hpp:190
auto find_child_by_name(std::string const &name) const -> Child_t const *
Find a child widget by name, returns nullptr if not found.
Definition: layout.hpp:239
auto make_child(typename Widget_t::Parameters p) -> Widget_t &
Helper so Parameters type does not have to be specified at call site.
Definition: layout.hpp:111
auto append_child(std::unique_ptr< Widget_t > w) -> Widget_t &
Move w to the end of the child container. Forwards to insert_child()
Definition: layout.hpp:95
auto remove_child_if(UnaryPredicate &&predicate) -> std::unique_ptr< Widget >
Removes and returns the first child where predicate(child) returns true.
Definition: layout.hpp:133
Definition: event.hpp:57
Definition: event.hpp:67
Definition: event.hpp:72
Definition: layout.hpp:280
Definition: layout.hpp:27