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
8
9#pragma once
10
11#include "widget.hpp"
12#include "../GFX/GFX.hpp"
13#include "../geometry/geometry.hpp"
14#include "../l10n/l10n.hpp"
15#include "../macros.hpp"
16#include <memory>
17#include <string>
18#include <array>
19#include <optional>
20#include <future>
21
22hi_export_module(hikogui.widgets.icon_widget);
23
24hi_export namespace hi {
25inline namespace v1 {
26
27template<typename Context>
29
36class icon_widget : public widget {
37public:
38 using super = widget;
39
42 observer<icon> icon = hi::icon{};
43
46 observer<hi::phrasing> phrasing = hi::phrasing::regular;
47
50 observer<alignment> alignment = hi::alignment::middle_center();
51
52 template<icon_widget_attribute... Attributes>
53 icon_widget(Attributes&&... attributes) noexcept : icon_widget()
54 {
55 set_attributes(std::forward<Attributes>(attributes)...);
56 }
57
58 void set_attributes() noexcept {}
59
60 template<icon_widget_attribute First, icon_widget_attribute... Rest>
61 void set_attributes(First&& first, Rest&&... rest) noexcept
62 {
63 if constexpr (forward_of<First, observer<hi::icon>>) {
65 } else if constexpr (forward_of<First, observer<hi::alignment>>) {
67 } else if constexpr (forward_of<First, observer<hi::phrasing>>) {
69 } else {
70 hi_static_no_default();
71 }
72 set_attributes(std::forward<Rest>(rest)...);
73 }
74
76 [[nodiscard]] box_constraints update_constraints() noexcept override
77 {
78 _layout = {};
79
80 if (_icon_has_modified.exchange(false)) {
81 _icon_type = icon_type::no;
82 _icon_size = {};
83 _glyph = {};
84 _pixmap_backing = {};
85
86 if (auto const pixmap = std::get_if<hi::pixmap<sfloat_rgba16>>(&icon)) {
87 _icon_type = icon_type::pixmap;
88 _icon_size = extent2{narrow_cast<float>(pixmap->width()), narrow_cast<float>(pixmap->height())};
89
90 if (not(_pixmap_backing = gfx_pipeline_image::paged_image{surface(), *pixmap})) {
91 // Could not get an image, retry.
92 _icon_has_modified = true;
93 ++global_counter<"icon_widget:no-backing-image:constrain">;
95 }
96
97 } else if (auto const g1 = std::get_if<font_glyph_ids>(&icon)) {
98 _glyph = *g1;
99 auto const icon_style = theme().text_style_set()[{phrasing::regular}];
100 _icon_type = icon_type::glyph;
101 _icon_size = _glyph.front_glyph_metrics().bounding_rectangle.size() *
102 (icon_style.size() * theme().pixel_density).in(unit::pixels_per_em);
103
104 } else if (auto const g2 = std::get_if<elusive_icon>(&icon)) {
105 _glyph = find_glyph(*g2);
106 auto const icon_style = theme().text_style_set()[{phrasing::regular}];
107 _icon_type = icon_type::glyph;
108 _icon_size = _glyph.front_glyph_metrics().bounding_rectangle.size() *
109 (icon_style.size() * theme().pixel_density).in(unit::pixels_per_em);
110
111 } else if (auto const g3 = std::get_if<hikogui_icon>(&icon)) {
112 _glyph = find_glyph(*g3);
113 auto const icon_style = theme().text_style_set()[{phrasing::regular}];
114 _icon_type = icon_type::glyph;
115 _icon_size = _glyph.front_glyph_metrics().bounding_rectangle.size() *
116 (icon_style.size() * theme().pixel_density).in(unit::pixels_per_em);
117 }
118 }
119
120 auto const resolved_alignment = resolve(*alignment, os_settings::left_to_right());
121 auto const icon_constraints = box_constraints{
122 extent2{0, 0},
123 narrow_cast<extent2>(_icon_size),
124 narrow_cast<extent2>(_icon_size),
125 resolved_alignment,
126 theme().margin<float>()};
127 return icon_constraints.constrain(*minimum, *maximum);
128 }
129 void set_layout(widget_layout const& context) noexcept override
130 {
131 if (compare_store(_layout, context)) {
132 if (_icon_type == icon_type::no or not _icon_size) {
133 _icon_rectangle = {};
134 } else {
135 auto const width = std::clamp(context.shape.width(), minimum->width(), maximum->width());
136 auto const height = std::clamp(context.shape.height(), minimum->height(), maximum->height());
137
138 auto const icon_scale =
139 scale2::uniform(_icon_size, extent2{narrow_cast<float>(width), narrow_cast<float>(height)});
140 auto const new_icon_size = narrow_cast<extent2>(icon_scale * _icon_size);
141 auto const resolved_alignment = resolve(*alignment, os_settings::left_to_right());
142 _icon_rectangle = align(context.rectangle(), new_icon_size, resolved_alignment);
143 }
144 }
145 }
146
147 color icon_color() noexcept
148 {
149 return theme().text_style_set()[{*phrasing}].color();
150 }
151
152 void draw(draw_context const& context) noexcept override
153 {
154 if (mode() > widget_mode::invisible and overlaps(context, layout())) {
155 switch (_icon_type) {
156 case icon_type::no:
157 break;
158
159 case icon_type::pixmap:
160 if (not context.draw_image(layout(), _icon_rectangle, _pixmap_backing)) {
161 // Continue redrawing until the image is loaded.
163 }
164 break;
165
166 case icon_type::glyph:
167 {
168 context.draw_glyph(layout(), _icon_rectangle, _glyph, icon_color());
169 }
170 break;
171
172 default:
173 hi_no_default();
174 }
175 }
176 }
178private:
179 enum class icon_type { no, glyph, pixmap };
180
181 icon_type _icon_type;
182 font_glyph_ids _glyph;
183 gfx_pipeline_image::paged_image _pixmap_backing;
184 std::atomic<bool> _icon_has_modified = true;
185
186 extent2 _icon_size;
187 aarectangle _icon_rectangle;
188
189 callback<void(hi::icon)> _icon_cbt;
190
191 icon_widget() noexcept : super()
192 {
193 _icon_cbt = icon.subscribe([this](auto...) {
194 _icon_has_modified = true;
195 ++global_counter<"icon_widget:icon:constrain">;
197 });
198 }
199};
200
201} // namespace v1
202} // namespace hi::v1
Defines widget.
@ window_reconstrain
Request that widget get constraint on the next frame.
Definition gui_event_type.hpp:48
@ invisible
The widget is invisible.
Definition widget_state.hpp:41
The HikoGUI namespace.
Definition array_generic.hpp:21
The HikoGUI API version 1.
Definition array_generic.hpp:22
@ color
A color value was modified.
Definition style_modify_mask.hpp:27
@ pixel_density
The attributes that need to be modified when the pixel density changes.
Definition style_modify_mask.hpp:59
bool compare_store(T &lhs, U &&rhs) noexcept
Compare then store if there was a change.
Definition misc.hpp:53
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:378
font_glyph_ids find_glyph(font_id font, grapheme grapheme) noexcept
Find a glyph using the given code-point.
Definition font_book.hpp:362
static constexpr scale2 uniform(extent2 src_extent, extent2 dst_extent) noexcept
Get a uniform-scale-transform to scale an extent to another extent.
Definition scale2.hpp:51
widget_layout const & layout() const noexcept
Get the current layout for this widget.
Definition widget_intf.hpp:241
A observer pointing to the whole or part of a observed_base.
Definition observer_intf.hpp:32
An simple GUI widget that displays an icon.
Definition icon_widget.hpp:36
observer< hi::phrasing > phrasing
The color a non-color icon will be displayed with.
Definition icon_widget.hpp:46
observer< icon > icon
The icon to be displayed.
Definition icon_widget.hpp:42
observer< alignment > alignment
Alignment of the icon inside the widget.
Definition icon_widget.hpp:50
observer< extent2 > minimum
The minimum size this widget is allowed to be.
Definition widget.hpp:42
void request_redraw() const noexcept override
Request the widget to be redrawn on the next frame.
Definition widget.hpp:136
widget() noexcept
Constructor for creating sub views.
Definition widget.hpp:50
box_constraints update_constraints() noexcept override
Update the constraints of the widget.
Definition widget.hpp:110
bool process_event(gui_event const &event) const noexcept override
Send a event to the window.
Definition widget.hpp:125
observer< extent2 > maximum
The maximum size this widget is allowed to be.
Definition widget.hpp:46
True if T is a forwarded type of Forward.
Definition concepts.hpp:137
Definition icon_widget.hpp:28
T align(T... args)
T forward(T... args)