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 "widget.hpp"
12#include "../GFX/GFX.hpp"
13#include "../geometry/module.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
22namespace hi { inline namespace v1 {
23
24template<typename Context>
26
33class icon_widget final : public widget {
34public:
35 using super = widget;
36
39 observer<icon> icon = hi::icon{};
40
43 observer<color> color = color::foreground();
44
47 observer<alignment> alignment = hi::alignment::middle_center();
48
51 {
52 set_attributes(hi_forward(attributes)...);
53 }
54
55 void set_attributes() noexcept {}
56 void set_attributes(icon_widget_attribute auto&& first, icon_widget_attribute auto&&...rest) noexcept
57 {
58 if constexpr (forward_of<decltype(first), observer<hi::icon>>) {
59 icon = hi_forward(first);
60 } else if constexpr (forward_of<decltype(first), observer<hi::alignment>>) {
61 alignment = hi_forward(first);
62 } else if constexpr (forward_of<decltype(first), observer<hi::color>>) {
63 color = hi_forward(first);
64 } else {
65 hi_static_no_default();
66 }
67 set_attributes(hi_forward(rest)...);
68 }
69
71 [[nodiscard]] box_constraints update_constraints() noexcept override
72 {
73 _layout = {};
74
75 if (_icon_has_modified.exchange(false)) {
76 _icon_type = icon_type::no;
77 _icon_size = {};
78 _glyph = {};
79 _pixmap_backing = {};
80
81 if (hilet pixmap = std::get_if<hi::pixmap<sfloat_rgba16>>(&icon.read())) {
82 _icon_type = icon_type::pixmap;
83 _icon_size = extent2{narrow_cast<float>(pixmap->width()), narrow_cast<float>(pixmap->height())};
84
85 if (not(_pixmap_backing = gfx_pipeline_image::paged_image{surface(), *pixmap})) {
86 // Could not get an image, retry.
87 _icon_has_modified = true;
88 ++global_counter<"icon_widget:no-backing-image:constrain">;
90 }
91
92 } else if (hilet g1 = std::get_if<font_book::font_glyph_type>(&icon.read())) {
93 _glyph = *g1;
94 _icon_type = icon_type::glyph;
95 _icon_size =
96 _glyph.get_metrics().bounding_rectangle.size() * theme().text_style(semantic_text_style::label)->size * theme().scale;
97
98 } else if (hilet g2 = std::get_if<elusive_icon>(&icon.read())) {
99 _glyph = find_glyph(*g2);
100 _icon_type = icon_type::glyph;
101 _icon_size =
102 _glyph.get_metrics().bounding_rectangle.size() * theme().text_style(semantic_text_style::label)->size * theme().scale;
103
104 } else if (hilet g3 = std::get_if<hikogui_icon>(&icon.read())) {
105 _glyph = find_glyph(*g3);
106 _icon_type = icon_type::glyph;
107 _icon_size =
108 _glyph.get_metrics().bounding_rectangle.size() * theme().text_style(semantic_text_style::label)->size * theme().scale;
109 }
110 }
111
112 hilet resolved_alignment = resolve(*alignment, os_settings::left_to_right());
113 hilet icon_constraints = box_constraints{
114 extent2{0, 0},
115 narrow_cast<extent2>(_icon_size),
116 narrow_cast<extent2>(_icon_size),
117 resolved_alignment,
118 theme().margin<float>()};
119 return icon_constraints.constrain(*minimum, *maximum);
120 }
121 void set_layout(widget_layout const& context) noexcept override
122 {
123 if (compare_store(_layout, context)) {
124 if (_icon_type == icon_type::no or not _icon_size) {
125 _icon_rectangle = {};
126 } else {
127 hilet width = std::clamp(context.shape.width(), minimum->width(), maximum->width());
128 hilet height = std::clamp(context.shape.height(), minimum->height(), maximum->height());
129
130 hilet icon_scale = scale2::uniform(_icon_size, extent2{narrow_cast<float>(width), narrow_cast<float>(height)});
131 hilet new_icon_size = narrow_cast<extent2>(icon_scale * _icon_size);
132 hilet resolved_alignment = resolve(*alignment, os_settings::left_to_right());
133 _icon_rectangle = align(context.rectangle(), new_icon_size, resolved_alignment);
134 }
135 }
136 }
137 void draw(draw_context const& context) noexcept override
138 {
139 if (*mode > widget_mode::invisible and overlaps(context, layout())) {
140 switch (_icon_type) {
141 case icon_type::no:
142 break;
143
144 case icon_type::pixmap:
145 if (not context.draw_image(layout(), _icon_rectangle, _pixmap_backing)) {
146 // Continue redrawing until the image is loaded.
148 }
149 break;
150
151 case icon_type::glyph:
152 {
153 context.draw_glyph(layout(), _icon_rectangle, _glyph, theme().color(*color));
154 }
155 break;
156
157 default:
158 hi_no_default();
159 }
160 }
161 }
163private:
164 enum class icon_type { no, glyph, pixmap };
165
166 icon_type _icon_type;
167 font_book::font_glyph_type _glyph;
168 gfx_pipeline_image::paged_image _pixmap_backing;
169 decltype(icon)::callback_token _icon_cbt;
170 std::atomic<bool> _icon_has_modified = true;
171
172 extent2 _icon_size;
173 aarectangle _icon_rectangle;
174
175 icon_widget(widget *parent) noexcept : super(parent)
176 {
177 _icon_cbt = icon.subscribe([this](auto...) {
178 _icon_has_modified = true;
179 ++global_counter<"icon_widget:icon:constrain">;
181 });
182 }
183};
184
185}} // namespace hi::v1
Defines widget.
@ window_reconstrain
Request that widget get constraint on the next frame.
@ invisible
The widget is invisible.
DOXYGEN BUG.
Definition algorithm.hpp:16
hi_export auto find_glyph(font const &font, grapheme grapheme) noexcept
Find a glyph using the given code-point.
Definition font_book.hpp:437
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
bool compare_store(T &lhs, U &&rhs) noexcept
Compare then store if there was a change.
Definition misc.hpp:56
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
This is a RGBA floating point color.
Definition color.hpp:45
Horizontal/Vertical alignment combination.
Definition alignment.hpp:242
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:46
widget_intf * parent
Pointer to the parent widget.
Definition widget_intf.hpp:28
A 2D pixel-based image.
Definition pixmap.hpp:38
An simple GUI widget that displays an icon.
Definition icon_widget.hpp:33
observer< icon > icon
The icon to be displayed.
Definition icon_widget.hpp:39
observer< alignment > alignment
Alignment of the icon inside the widget.
Definition icon_widget.hpp:47
observer< color > color
The color a non-color icon will be displayed with.
Definition icon_widget.hpp:43
An interactive graphical object as part of the user-interface.
Definition widget.hpp:37
widget_layout const & layout() const noexcept override
Get the current layout for this widget.
Definition widget.hpp:169
observer< extent2 > minimum
The minimum size this widget is allowed to be.
Definition widget.hpp:79
widget(widget *parent) noexcept
Definition widget.hpp:87
void request_redraw() const noexcept override
Request the widget to be redrawn on the next frame.
Definition widget.hpp:189
bool process_event(gui_event const &event) const noexcept override
Send a event to the window.
Definition widget.hpp:178
observer< widget_mode > mode
The widget mode.
Definition widget.hpp:42
observer< extent2 > maximum
The maximum size this widget is allowed to be.
Definition widget.hpp:83
True if T is a forwarded type of Forward.
Definition concepts.hpp:131
Definition icon_widget.hpp:25
T align(T... args)
T exchange(T... args)