TermOx
label.hpp
1 #ifndef TERMOX_WIDGET_WIDGETS_LABEL_HPP
2 #define TERMOX_WIDGET_WIDGETS_LABEL_HPP
3 #include <memory>
4 #include <utility>
5 
6 #include <termox/painter/glyph_string.hpp>
7 #include <termox/painter/painter.hpp>
8 #include <termox/widget/align.hpp>
9 #include <termox/widget/area.hpp>
10 #include <termox/widget/growth.hpp>
11 #include <termox/widget/layouts/horizontal.hpp>
12 #include <termox/widget/layouts/opposite.hpp>
13 #include <termox/widget/layouts/vertical.hpp>
14 #include <termox/widget/pipe.hpp>
15 #include <termox/widget/tuple.hpp>
16 
17 namespace ox {
18 
20 
21 template <template <typename> typename Layout_t>
22 class Label : public Widget {
23  static_assert(layout::is_vertical_v<Layout_t<Widget>> ||
24  layout::is_horizontal_v<Layout_t<Widget>>);
25 
26  public:
27  struct Parameters {
28  Glyph_string text = Glyph_string{U""};
29  Align alignment = Align::Left;
30  int extra_left = 0;
31  int extra_right = 0;
32  Growth growth_strategy = Growth::Static;
33  };
34 
35  public:
37 
43  explicit Label(Glyph_string text = U"",
44  Align alignment = Align::Left,
45  int extra_left = 0,
46  int extra_right = 0,
47  Growth growth_strategy = Growth::Static);
48 
50  explicit Label(Parameters p);
51 
52  public:
55 
57  [[nodiscard]] auto text() const noexcept -> Glyph_string const&;
58 
60  void set_alignment(Align x);
61 
63  [[nodiscard]] auto alignment() const noexcept -> Align;
64 
66  void set_extra_left(int x);
67 
69  [[nodiscard]] auto extra_left() const noexcept -> int;
70 
72  void set_extra_right(int x);
73 
75  [[nodiscard]] auto extra_right() const noexcept -> int;
76 
78  void set_growth_strategy(Growth type);
79 
81  [[nodiscard]] auto growth_strategy() const noexcept -> Growth;
82 
83  protected:
84  auto paint_event(Painter& p) -> bool override;
85 
86  auto resize_event(Area new_size, Area old_size) -> bool override;
87 
88  private:
89  inline static auto constexpr is_vertical =
90  layout::is_vertical_v<Layout_t<Widget>>;
91 
92  Glyph_string text_;
93  Align alignment_;
94  int extra_left_;
95  int extra_right_;
96  Growth growth_strategy_;
97 
98  int offset_ = 0;
99 
100  private:
102  void update_offset();
103 
104  void paint_vertical(Painter& p);
105 
106  void paint_horizontal(Painter& p);
107 
109  [[nodiscard]] auto find_offset(int text_length,
110  int box_length,
111  int extra_left,
112  int extra_right) -> int;
113 };
114 
116 template <template <typename> typename Layout_t>
117 [[nodiscard]] auto label(Glyph_string text = U"",
118  Align alignment = Align::Left,
119  int extra_left = 0,
120  int extra_right = 0,
121  Growth growth_strategy = Growth::Static)
122  -> std::unique_ptr<Label<Layout_t>>;
123 
125 template <template <typename> typename Layout_t>
126 [[nodiscard]] auto label(typename Label<Layout_t>::Parameters p)
127  -> std::unique_ptr<Label<Layout_t>>;
128 
130 using HLabel = Label<layout::Horizontal>;
131 
133 [[nodiscard]] auto hlabel(Glyph_string text = U"",
134  Align alignment = Align::Left,
135  int extra_left = 0,
136  int extra_right = 0,
137  Growth growth_strategy = Growth::Static)
138  -> std::unique_ptr<HLabel>;
139 
141 [[nodiscard]] auto hlabel(HLabel::Parameters p) -> std::unique_ptr<HLabel>;
142 
144 using VLabel = Label<layout::Vertical>;
145 
147 [[nodiscard]] auto vlabel(Glyph_string text = U"",
148  Align alignment = Align::Left,
149  int extra_left = 0,
150  int extra_right = 0,
151  Growth growth_strategy = Growth::Static)
152  -> std::unique_ptr<VLabel>;
153 
155 [[nodiscard]] auto vlabel(VLabel::Parameters p) -> std::unique_ptr<VLabel>;
156 
157 } // namespace ox
158 
159 // -----------------------------------------------------------------------------
160 
161 namespace ox::detail {
162 
164 
166 template <template <typename> typename Label_layout,
167  typename Widget_t,
168  template <typename>
169  typename Wrapper_layout,
170  bool label_last>
171 class Label_wrapper : public Wrapper_layout<Widget> {
172  private:
175  Widget,
176  Label_t,
177  Widget>;
178 
179  public:
180  // Instead of inheriting Label_t::Parmeters, because default alignment.
181  struct Parameters {
183  Align alignment = label_last ? Align::Left : Align::Right;
184  int extra_left = 0;
185  int extra_right = 0;
186  Growth growth_strategy = Growth::Static;
187  };
188 
189  public:
190  Label_t& label;
191  Widget& padding = this->template make_child() | padding_policy();
192  Widget_t& wrapped;
193 
194  public:
196 
199  Align alignment = Align::Left,
200  int extra_left = 0,
201  int extra_right = 0,
202  Growth growth_strategy = Growth::Static)
205  {}
206 
208  template <typename... Args>
209  explicit Label_wrapper(Parameters p, Args&&... args)
210  : label{this->template make_child<Padded_label>(
211  {{},
212  {std::move(p.text), p.alignment, p.extra_left,
213  p.extra_right, p.growth_strategy},
214  {}})
215  .template get<1>()},
216  wrapped{
217  this->template make_child<Widget_t>(std::forward<Args>(args)...)}
218  {
219  if constexpr (layout::is_vertical_v<Wrapper_layout<Widget>>)
220  this->width_policy = wrapped.width_policy;
221  else
222  this->height_policy = wrapped.height_policy;
223 
224  *this | pipe::forward_focus(wrapped);
225 
226  if constexpr (label_last)
227  this->swap_children(0, 2);
228  }
229 
230  private:
231  [[nodiscard]] auto padding_policy()
232  {
233  if constexpr (layout::is_vertical_v<Wrapper_layout<Widget>>)
234  return pipe::fixed_height(0);
235  else
236  return pipe::fixed_width(1);
237  }
238 };
239 
240 } // namespace ox::detail
241 
242 namespace ox {
243 
244 // -----------------------------------------------------------------------------
245 
247 template <template <typename> typename Label_layout_t, typename Widget_t>
248 using Label_left =
249  detail::Label_wrapper<Label_layout_t, Widget_t, layout::Horizontal, false>;
250 
251 // Helper function to create a Label_left instance.
252 template <template <typename> typename Layout_t,
253  typename Widget_t,
254  typename... Args>
255 [[nodiscard]] auto label_left(typename Label<Layout_t>::Parameters p,
256  Args&&... args)
257  -> std::unique_ptr<Label_left<Layout_t, Widget_t>>
258 {
259  return std::make_unique<Label_left<Layout_t, Widget_t>>(
260  std::move(p), std::forward<Args>(args)...);
261 }
262 
264 
266 template <template <typename> typename Layout_t, typename Widget_t>
267 [[nodiscard]] auto label_left(Glyph_string text = U"",
268  Align alignment = Align::Left,
269  int extra_left = 0,
270  int extra_right = 0,
271  Growth growth_strategy = Growth::Static)
272  -> std::unique_ptr<Label_left<Layout_t, Widget_t>>
273 {
274  return label_left<Layout_t, Widget_t>(typename Label<Layout_t>::Parameters{
276 }
277 
279 template <typename Widget_t>
280 using HLabel_left = Label_left<layout::Horizontal, Widget_t>;
281 
282 // Helper function to create an HLabel_left instance.
283 template <typename Widget_t, typename... Args>
284 [[nodiscard]] auto hlabel_left(HLabel::Parameters p, Args&&... args)
285  -> std::unique_ptr<HLabel_left<Widget_t>>
286 {
287  return std::make_unique<HLabel_left<Widget_t>>(std::move(p),
288  std::forward<Args>(args)...);
289 }
290 
292 
294 template <typename Widget_t>
295 [[nodiscard]] auto hlabel_left(Glyph_string text = U"",
296  Align alignment = Align::Left,
297  int extra_left = 0,
298  int extra_right = 0,
299  Growth growth_strategy = Growth::Static)
300  -> std::unique_ptr<HLabel_left<Widget_t>>
301 {
302  return hlabel_left<Widget_t>(HLabel::Parameters{
304 }
305 
307 template <typename Widget_t>
308 using VLabel_left = Label_left<layout::Vertical, Widget_t>;
309 
310 // Helper function to create a VLabel_left instance.
311 template <typename Widget_t, typename... Args>
312 [[nodiscard]] auto vlabel_left(VLabel::Parameters p, Args&&... args)
313  -> std::unique_ptr<VLabel_left<Widget_t>>
314 {
315  return std::make_unique<VLabel_left<Widget_t>>(std::move(p),
316  std::forward<Args>(args)...);
317 }
318 
320 
322 template <typename Widget_t>
323 [[nodiscard]] auto vlabel_left(Glyph_string text = U"",
324  Align alignment = Align::Left,
325  int extra_left = 0,
326  int extra_right = 0,
327  Growth growth_strategy = Growth::Static)
328  -> std::unique_ptr<VLabel_left<Widget_t>>
329 {
330  return vlabel_left<Widget_t>(VLabel::Parameters{
332 }
333 
335 template <template <typename> typename Label_layout_t, typename Widget_t>
336 using Label_right =
337  detail::Label_wrapper<Label_layout_t, Widget_t, layout::Horizontal, true>;
338 
340 template <template <typename> typename Layout_t,
341  typename Widget_t,
342  typename... Args>
343 [[nodiscard]] auto label_right(typename Label<Layout_t>::Parameters p,
344  Args&&... args)
345  -> std::unique_ptr<Label_right<Layout_t, Widget_t>>
346 {
347  return std::make_unique<Label_right<Layout_t, Widget_t>>(
348  std::move(p), std::forward<Args>(args)...);
349 }
350 
352 
354 template <template <typename> typename Layout_t, typename Widget_t>
355 [[nodiscard]] auto label_right(Glyph_string text = U"",
356  Align alignment = Align::Left,
357  int extra_left = 0,
358  int extra_right = 0,
359  Growth growth_strategy = Growth::Static)
360  -> std::unique_ptr<Label_left<Layout_t, Widget_t>>
361 {
362  return label_right(typename Label<Layout_t>::Parameters{
364 }
365 
367 template <typename Widget_t>
368 using HLabel_right = Label_right<layout::Horizontal, Widget_t>;
369 
370 // Helper function to create a HLabel_right instance.
371 template <typename Widget_t, typename... Args>
372 [[nodiscard]] auto hlabel_right(HLabel::Parameters p, Args&&... args)
373  -> std::unique_ptr<HLabel_right<Widget_t>>
374 {
375  return std::make_unique<HLabel_right<Widget_t>>(
376  std::move(p), std::forward<Args>(args)...);
377 }
378 
380 
382 template <typename Widget_t>
383 [[nodiscard]] auto hlabel_right(Glyph_string text = U"",
384  Align alignment = Align::Left,
385  int extra_left = 0,
386  int extra_right = 0,
387  Growth growth_strategy = Growth::Static)
388  -> std::unique_ptr<HLabel_right<Widget_t>>
389 {
390  return hlabel_right<Widget_t>(HLabel::Parameters{
392 }
393 
395 template <typename Widget_t>
396 using VLabel_right = Label_right<layout::Vertical, Widget_t>;
397 
398 // Helper function to create a VLabel_right instance.
399 template <typename Widget_t, typename... Args>
400 [[nodiscard]] auto vlabel_right(VLabel::Parameters p, Args&&... args)
401  -> std::unique_ptr<VLabel_right<Widget_t>>
402 {
403  return std::make_unique<VLabel_right<Widget_t>>(
404  std::move(p), std::forward<Args>(args)...);
405 }
406 
408 
410 template <typename Widget_t>
411 [[nodiscard]] auto vlabel_right(Glyph_string text = U"",
412  Align alignment = Align::Left,
413  int extra_left = 0,
414  int extra_right = 0,
415  Growth growth_strategy = Growth::Static)
416  -> std::unique_ptr<VLabel_right<Widget_t>>
417 {
418  return vlabel_right<Widget_t>(VLabel::Parameters{
420 }
421 
423 template <template <typename> typename Label_layout_t, typename Widget_t>
424 using Label_top =
425  detail::Label_wrapper<Label_layout_t, Widget_t, layout::Vertical, false>;
426 
428 template <template <typename> typename Layout_t,
429  typename Widget_t,
430  typename... Args>
431 [[nodiscard]] auto label_top(typename Label<Layout_t>::Parameters p,
432  Args&&... args)
433  -> std::unique_ptr<Label_top<Layout_t, Widget_t>>
434 {
435  return std::make_unique<Label_top<Layout_t, Widget_t>>(
436  std::move(p), std::forward<Args>(args)...);
437 }
438 
440 
442 template <template <typename> typename Layout_t, typename Widget_t>
443 [[nodiscard]] auto label_top(Glyph_string text = U"",
444  Align alignment = Align::Left,
445  int extra_top = 0,
446  int extra_bottom = 0,
447  Growth growth_strategy = Growth::Static)
448  -> std::unique_ptr<Label_left<Layout_t, Widget_t>>
449 {
450  return label_top(typename Label<Layout_t>::Parameters{
451  std::move(text), alignment, extra_top, extra_bottom, growth_strategy});
452 }
453 
455 template <typename Widget_t>
456 using VLabel_top = Label_top<layout::Vertical, Widget_t>;
457 
458 // Helper function to create a VLabel_top instance.
459 template <typename Widget_t, typename... Args>
460 [[nodiscard]] auto vlabel_top(VLabel::Parameters p, Args&&... args)
461  -> std::unique_ptr<VLabel_top<Widget_t>>
462 {
463  return std::make_unique<VLabel_top<Widget_t>>(std::move(p),
464  std::forward<Args>(args)...);
465 }
466 
468 
470 template <typename Widget_t>
471 [[nodiscard]] auto vlabel_top(Glyph_string text = U"",
472  Align alignment = Align::Left,
473  int extra_left = 0,
474  int extra_right = 0,
475  Growth growth_strategy = Growth::Static)
476  -> std::unique_ptr<VLabel_top<Widget_t>>
477 {
478  return vlabel_top<Widget_t>(VLabel::Parameters{
480 }
481 
483 template <typename Widget_t>
484 using HLabel_top = Label_top<layout::Horizontal, Widget_t>;
485 
486 // Helper function to create an HLabel_top instance.
487 template <typename Widget_t, typename... Args>
488 [[nodiscard]] auto hlabel_top(HLabel::Parameters p, Args&&... args)
489  -> std::unique_ptr<HLabel_top<Widget_t>>
490 {
491  return std::make_unique<HLabel_top<Widget_t>>(std::move(p),
492  std::forward<Args>(args)...);
493 }
494 
496 
498 template <typename Widget_t>
499 [[nodiscard]] auto hlabel_top(Glyph_string text = U"",
500  Align alignment = Align::Left,
501  int extra_left = 0,
502  int extra_right = 0,
503  Growth growth_strategy = Growth::Static)
504  -> std::unique_ptr<HLabel_top<Widget_t>>
505 {
506  return hlabel_top<Widget_t>(HLabel::Parameters{
508 }
509 
511 template <template <typename> typename Label_layout_t, typename Widget_t>
512 using Label_bottom =
513  detail::Label_wrapper<Label_layout_t, Widget_t, layout::Vertical, true>;
514 
516 template <template <typename> typename Layout_t,
517  typename Widget_t,
518  typename... Args>
519 [[nodiscard]] auto label_bottom(typename Label<Layout_t>::Parameters p,
520  Args&&... args)
521  -> std::unique_ptr<Label_bottom<Layout_t, Widget_t>>
522 {
523  return std::make_unique<Label_bottom<Layout_t, Widget_t>>(
524  std::move(p), std::forward<Args>(args)...);
525 }
526 
528 
530 template <template <typename> typename Layout_t, typename Widget_t>
531 [[nodiscard]] auto label_bottom(Glyph_string text = U"",
532  Align alignment = Align::Left,
533  int extra_top = 0,
534  int extra_bottom = 0,
535  Growth growth_strategy = Growth::Static)
536  -> std::unique_ptr<Label_left<Layout_t, Widget_t>>
537 {
538  return label_bottom(typename Label<Layout_t>::Parameters{
539  std::move(text), alignment, extra_top, extra_bottom, growth_strategy});
540 }
541 
543 template <typename Widget_t>
544 using VLabel_bottom = Label_bottom<layout::Vertical, Widget_t>;
545 
546 // Helper function to create a VLabel_bottom instance.
547 template <typename Widget_t, typename... Args>
548 [[nodiscard]] auto vlabel_bottom(VLabel::Parameters p, Args&&... args)
549  -> std::unique_ptr<VLabel_bottom<Widget_t>>
550 {
551  return std::make_unique<VLabel_bottom<Widget_t>>(
552  std::move(p), std::forward<Args>(args)...);
553 }
554 
556 
558 template <typename Widget_t>
559 [[nodiscard]] auto vlabel_bottom(Glyph_string text = U"",
560  Align alignment = Align::Left,
561  int extra_left = 0,
562  int extra_right = 0,
563  Growth growth_strategy = Growth::Static)
564  -> std::unique_ptr<VLabel_bottom<Widget_t>>
565 {
566  return vlabel_bottom<Widget_t>(VLabel::Parameters{
568 }
569 
571 template <typename Widget_t>
572 using HLabel_bottom = Label_bottom<layout::Horizontal, Widget_t>;
573 
574 // Helper function to create an HLabel_bottom instance.
575 template <typename Widget_t, typename... Args>
576 [[nodiscard]] auto hlabel_bottom(HLabel::Parameters p, Args&&... args)
577  -> std::unique_ptr<HLabel_bottom<Widget_t>>
578 {
579  return std::make_unique<HLabel_bottom<Widget_t>>(
580  std::move(p), std::forward<Args>(args)...);
581 }
582 
584 
586 template <typename Widget_t>
587 [[nodiscard]] auto hlabel_bottom(Glyph_string text = U"",
588  Align alignment = Align::Left,
589  int extra_left = 0,
590  int extra_right = 0,
591  Growth growth_strategy = Growth::Static)
592  -> std::unique_ptr<HLabel_bottom<Widget_t>>
593 {
594  return hlabel_bottom<Widget_t>(HLabel::Parameters{
596 }
597 
598 } // namespace ox
599 #endif // TERMOX_WIDGET_WIDGETS_LABEL_HPP
Holds a collection of Glyphs with a similar interface to std::string.
Definition: glyph_string.hpp:19
A single line of text with alignment, non-editable.
Definition: label.hpp:22
auto alignment() const noexcept -> Align
Return the Align given to set_alignment().
Definition: label.cpp:111
auto text() const noexcept -> Glyph_string const &
Return the text given to set_text().
Definition: label.cpp:98
void set_extra_left(int x)
Inform Label about space to left of Label for centered text offset.
Definition: label.cpp:117
Label(Glyph_string text=U"", Align alignment=Align::Left, int extra_left=0, int extra_right=0, Growth growth_strategy=Growth::Static)
Create a new Label Widget.
Definition: label.cpp:47
auto extra_left() const noexcept -> int
Return the amount given to set_extra_left().
Definition: label.cpp:124
void set_alignment(Align x)
Set text alignment of Label and update display.
Definition: label.cpp:104
void set_text(Glyph_string text)
Set text contents of Label and update display.
Definition: label.cpp:81
auto extra_right() const noexcept -> int
Return the amount given to set_extra_right().
Definition: label.cpp:137
void set_extra_right(int x)
Inform Label about space to right of Label for centered text offset.
Definition: label.cpp:130
void set_growth_strategy(Growth type)
Enable/Disable Dynamic size, where the Label's size is the text length.
Definition: label.cpp:143
auto resize_event(Area new_size, Area old_size) -> bool override
Handles Resize_event objects.
Definition: label.cpp:171
auto growth_strategy() const noexcept -> Growth
Return the value given to set_growth_strategy().
Definition: label.cpp:155
auto paint_event(Painter &p) -> bool override
Handles Paint_event objects.
Definition: label.cpp:161
Contains functions to paint Glyphs to a Widget's screen area.
Definition: painter.hpp:21
Heterogeneous collection of Widgets within a Layout_t.
Definition: tuple.hpp:17
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
Size_policy height_policy
Describes how the height of this Widget should be modified by a Layout.
Definition: widget.hpp:102
Size_policy width_policy
Describes how the width of this Widget should be modified by a Layout.
Definition: widget.hpp:99
Wraps a Widget_t object with a label.
Definition: label.hpp:171
Label_wrapper(Glyph_string text=U"", Align alignment=Align::Left, int extra_left=0, int extra_right=0, Growth growth_strategy=Growth::Static)
Construct a new Label and wrapped Widget_t.
Definition: label.hpp:198
Label_wrapper(Parameters p, Args &&... args)
Constructs Label with given parameters, and Widget_t with args...
Definition: label.hpp:209
Definition: label.hpp:27
Definition: label.hpp:181