HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
icon_widget.hpp
Go to the documentation of this file.
1// Copyright Take Vos 2021-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
9#pragma once
10
11#include "../GUI/module.hpp"
12#include "../GFX/module.hpp"
13#include "../geometry/module.hpp"
14#include "../label.hpp"
15#include <memory>
16#include <string>
17#include <array>
18#include <optional>
19#include <future>
20
21namespace hi { inline namespace v1 {
22
23template<typename Context>
24concept icon_widget_attribute = forward_of<Context, observer<hi::icon>, observer<hi::alignment>>;
25
32template<fixed_string Name = "">
33class icon_widget final : public widget {
34public:
35 using super = widget;
36 constexpr static auto prefix = Name / "icon";
37
40 observer<icon> icon = hi::icon{};
41
44 observer<alignment> alignment = hi::alignment::middle_center();
45
46 extent2 minimum;
47 extent2 maximum;
48
49 icon_widget(widget *parent, icon_widget_attribute auto&&...attributes) noexcept : icon_widget(parent)
50 {
51 set_attributes(hi_forward(attributes)...);
52 }
53
54 void set_attributes() noexcept {}
55 void set_attributes(icon_widget_attribute auto&& first, icon_widget_attribute auto&&...rest) noexcept
56 {
57 if constexpr (forward_of<decltype(first), observer<hi::icon>>) {
58 icon = hi_forward(first);
59 } else if constexpr (forward_of<decltype(first), observer<hi::alignment>>) {
60 alignment = hi_forward(first);
61 } else {
63 }
64 set_attributes(hi_forward(rest)...);
65 }
66
68 void layout() noexcept override
69 {
70 if (_icon_has_modified.exchange(false)) {
71 _icon_type = icon_type::no;
72 _glyph = {};
73 _pixmap_backing = {};
74
75 if (hilet pixmap = std::get_if<hi::pixmap<sfloat_rgba16>>(&icon.read())) {
76 _icon_type = icon_type::pixmap;
77
78 hilet preferred = extent2{narrow_cast<float>(pixmap->width()), narrow_cast<float>(pixmap->height())};
79 cell.set_constraints(minimum, preferred, maximum);
80
81 if (_pixmap_backing = paged_image{surface, *pixmap}; not _pixmap_backing) {
82 // Could not get an image, retry.
83 _icon_has_modified = true;
84 ++global_counter<"icon_widget:no-backing-image:constrain">;
86 }
87
88 } else if (hilet g1 = std::get_if<font_book::font_glyph_type>(&icon.read())) {
89 _glyph = *g1;
90 _icon_type = icon_type::glyph;
91 hilet preferred = ceil(_glyph.get_bounding_rectangle().size() * theme<prefix>.line_height(this));
92 cell.set_constraints(minimum, preferred, maximum);
93
94 } else if (hilet g2 = std::get_if<elusive_icon>(&icon.read())) {
95 _glyph = find_glyph(*g2);
96 _icon_type = icon_type::glyph;
97 hilet preferred = ceil(_glyph.get_bounding_rectangle().size() * theme<prefix>.line_height(this));
98 cell.set_constraints(minimum, preferred, maximum);
99
100 } else if (hilet g3 = std::get_if<hikogui_icon>(&icon.read())) {
101 _glyph = find_glyph(*g3);
102 _icon_type = icon_type::glyph;
103 hilet preferred = ceil(_glyph.get_bounding_rectangle().size() * theme<prefix>.line_height(this));
104 cell.set_constraints(minimum, preferred, maximum);
105 }
106 }
107
108 cell.set_margin(theme<prefix>.margin(this));
109 }
110
111 void draw(widget_draw_context& context) noexcept override
112 {
113 if (*mode > widget_mode::invisible and overlaps(context, cell)) {
114 switch (_icon_type) {
115 case icon_type::no:
116 break;
117
118 case icon_type::pixmap:
119 {
120 hilet image_size = extent2{narrow_cast<float>(pixmap->width()), narrow_cast<float>(pixmap->height())};
121 hilet S = scale2::uniform(image_size, cell.size());
122 hilet icon_rectangle = aarectangle{S * image_size};
123 hilet T = translate2::align(icon_rectangle, cell.rectangle(), resolve(*alignment));
124 hilet rectangle = T * icon_rectangle;
125
126 if (not context.draw_image(rectangle, _pixmap_backing))
127 {
128 // Continue redrawing until the image is loaded.
130 }
131 }
132 break;
133
134 case icon_type::glyph:
135 {
136 hilet image_size = _glyph.get_bounding_rectangle().size();
137 hilet S = scale2::uniform(image_size, cell.size());
138 hilet icon_rectangle = aarectangle{S * image_size};
139 hilet T = translate2::align(icon_rectangle, cell.rectangle(), resolve(*alignment));
140 hilet rectangle = T * icon_rectangle;
141
142 context.draw_glyph(rectangle, *_glyph.font, _glyph.glyph, theme<prefix>.fill_color(this));
143 }
144 break;
145
146 default:
148 }
149 }
150 }
152private:
153 enum class icon_type { no, glyph, pixmap };
154
155 icon_type _icon_type;
156 font_book::font_glyph_type _glyph;
157 paged_image _pixmap_backing;
158 decltype(icon)::callback_token _icon_cbt;
159 std::atomic<bool> _icon_has_modified = true;
160
161 icon_widget(widget *parent) noexcept : super(parent)
162 {
163 _icon_cbt = icon.subscribe([this](auto...) {
164 _icon_has_modified = true;
165 layout();
166 });
167 }
168};
169
170}} // namespace hi::v1
Functionality for labels, text and icons.
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:323
#define hi_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:279
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
#define hi_forward(x)
Forward a value, based on the decltype of the value.
Definition utility.hpp:29
geo::extent< float, 2 > extent2
A 2D extent.
Definition extent.hpp:502
@ window_reconstrain
Request that widget get constraint on the next frame.
@ rectangle
The gui_event has rectangle data.
@ invisible
The widget is invisible.
DOXYGEN BUG.
Definition algorithm.hpp:13
auto find_glyph(font const &font, grapheme grapheme) noexcept
Find a glyph using the given code-point.
Definition font_book.hpp:223
geometry/margins.hpp
Definition cache.hpp:11
Definition widget.hpp:26
virtual void request_redraw() const noexcept
Request the widget to be redrawn on the next frame.
Definition widget.hpp:227
gfx_surface * surface
The surface this widget is drawn on.
Definition widget.hpp:44
widget * parent
Pointer to the parent widget.
Definition widget.hpp:40
observer< widget_mode > mode
The widget mode.
Definition widget.hpp:49
A 2D pixel-based image.
Definition pixmap.hpp:35
An simple GUI widget that displays an icon.
Definition icon_widget.hpp:33
observer< alignment > alignment
Alignment of the icon inside the widget.
Definition icon_widget.hpp:44
observer< icon > icon
The icon to be displayed.
Definition icon_widget.hpp:40
Definition icon_widget.hpp:24
T ceil(T... args)
T exchange(T... args)