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 icon_widget(widget *parent, icon_widget_attribute auto&&...attributes) noexcept : icon_widget(parent)
47 {
48 set_attributes(hi_forward(attributes)...);
49 }
50
51 void set_attributes() noexcept {}
52 void set_attributes(icon_widget_attribute auto&& first, icon_widget_attribute auto&&...rest) noexcept
53 {
54 if constexpr (forward_of<decltype(first), observer<hi::icon>>) {
55 icon = hi_forward(first);
56 } else if constexpr (forward_of<decltype(first), observer<hi::alignment>>) {
57 alignment = hi_forward(first);
58 } else {
60 }
61 set_attributes(hi_forward(rest)...);
62 }
63
65 [[nodiscard]] box_constraints update_constraints() noexcept override
66 {
67 if (_icon_has_modified.exchange(false)) {
68 _icon_type = icon_type::no;
69 _icon_size = {};
70 _glyph = {};
71 _pixmap_backing = {};
72
73 if (hilet pixmap = std::get_if<hi::pixmap<sfloat_rgba16>>(&icon.read())) {
74 _icon_type = icon_type::pixmap;
75 _icon_size = extent2i{narrow_cast<int>(pixmap->width()), narrow_cast<int>(pixmap->height())};
76
77 if (_pixmap_backing = paged_image{surface, *pixmap}; not _pixmap_backing) {
78 // Could not get an image, retry.
79 _icon_has_modified = true;
80 ++global_counter<"icon_widget:no-backing-image:constrain">;
82 }
83
84 } else if (hilet g1 = std::get_if<font_book::font_glyph_type>(&icon.read())) {
85 _glyph = *g1;
86 _icon_type = icon_type::glyph;
87 _icon_size = narrow_cast<extent2i>(_glyph.get_bounding_rectangle().size() * theme<prefix>.line_height(this));
88
89 } else if (hilet g2 = std::get_if<elusive_icon>(&icon.read())) {
90 _glyph = find_glyph(*g2);
91 _icon_type = icon_type::glyph;
92 _icon_size = narrow_cast<extent2i>(_glyph.get_bounding_rectangle().size() * theme<prefix>.line_height(this));
93
94 } else if (hilet g3 = std::get_if<hikogui_icon>(&icon.read())) {
95 _glyph = find_glyph(*g3);
96 _icon_type = icon_type::glyph;
97 _icon_size = narrow_cast<extent2i>(_glyph.get_bounding_rectangle().size() * theme<prefix>.line_height(this));
98 }
99 }
100
101 hilet resolved_alignment = resolve(*alignment, os_settings::left_to_right());
102 hilet icon_constraints = box_constraints{
103 extent2i{0, 0},
104 _icon_size,
105 _icon_size,
106 resolved_alignment,
107 theme<prefix>.margin(this)};
108 return icon_constraints.constrain(*minimum, *maximum);
109 }
110
111 void set_layout(widget_layout const& context) noexcept override
112 {
113 if (compare_store(layout, context)) {
114 if (_icon_type == icon_type::no or not _icon_size) {
115 _icon_rectangle = {};
116 } else {
117 hilet widget_size = narrow_cast<extent2>(clamp(context.shape.size(), *minimum, *maximum));
118 hilet original_icon_size = narrow_cast<extent2>(_icon_size);
119
120 hilet icon_scale = scale2::uniform(original_icon_size, widget_size);
121 hilet new_icon_size = narrow_cast<extent2i>(icon_scale * original_icon_size);
122
123 hilet resolved_alignment = resolve(*alignment, os_settings::left_to_right());
124 _icon_rectangle = align(context.rectangle(), new_icon_size, resolved_alignment);
125 }
126 }
127 }
128
129 void draw(widget_draw_context& context) noexcept override
130 {
131 if (*mode > widget_mode::invisible and overlaps(context, layout)) {
132 switch (_icon_type) {
133 case icon_type::no:
134 break;
135
136 case icon_type::pixmap:
137 if (not context.draw_image(layout, _icon_rectangle, _pixmap_backing)) {
138 // Continue redrawing until the image is loaded.
140 }
141 break;
142
143 case icon_type::glyph:
144 {
145 context.draw_glyph(layout, _icon_rectangle, *_glyph.font, _glyph.glyph, theme<prefix>.fill_color(this));
146 }
147 break;
148
149 default:
151 }
152 }
153 }
155private:
156 enum class icon_type { no, glyph, pixmap };
157
158 icon_type _icon_type;
159 font_book::font_glyph_type _glyph;
160 paged_image _pixmap_backing;
161 decltype(icon)::callback_token _icon_cbt;
162 std::atomic<bool> _icon_has_modified = true;
163
164 extent2i _icon_size;
165 aarectanglei _icon_rectangle;
166
167 icon_widget(widget *parent) noexcept : super(parent)
168 {
169 _icon_cbt = icon.subscribe([this](auto...) {
170 _icon_has_modified = true;
171 ++global_counter<"icon_widget:icon:constrain">;
172 process_event({gui_event_type::window_reconstrain});
173 });
174 }
175};
176
177}} // 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< int, 2 > extent2i
A 2D extent.
Definition extent.hpp:512
@ window_reconstrain
Request that widget get constraint on the next frame.
@ 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
bool compare_store(T &lhs, U &&rhs) noexcept
Compare then store if there was a change.
Definition utility.hpp:212
Definition widget.hpp:26
observer< extent2i > minimum
The minimum size this widget is allowed to be.
Definition widget.hpp:85
virtual void request_redraw() const noexcept
Request the widget to be redrawn on the next frame.
Definition widget.hpp:265
gfx_surface * surface
The surface this widget is drawn on.
Definition widget.hpp:44
observer< extent2i > maximum
The maximum size this widget is allowed to be.
Definition widget.hpp:89
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 align(T... args)
T exchange(T... args)