HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
window_controls_macos_widget.hpp
Go to the documentation of this file.
1// Copyright Take Vos 2020-2021.
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 "../font/font.hpp"
13#include "../macros.hpp"
14#include <memory>
15#include <string>
16#include <array>
17
18hi_export_module(hikogui.widgets.window_controls_macos_widget);
19
20hi_export namespace hi { inline namespace v1 {
21
30public:
31 using super = widget;
32
34
36 [[nodiscard]] box_constraints update_constraints() noexcept override
37 {
38 _layout = {};
39
40 auto const size = extent2{DIAMETER * 3.0f + 2.0f * MARGIN + 2.0f * SPACING, DIAMETER + 2.0f * MARGIN};
41 return {size, size, size};
42 }
43
44 void set_layout(widget_layout const& context) noexcept override
45 {
46 if (compare_store(_layout, context)) {
47 auto extent = context.size();
48 if (extent.height() > floor_cast<int>(theme().large_size() * 1.2f)) {
49 extent = extent2{extent.width(), theme().large_size()};
50 }
51
52 closeRectangle = aarectangle{point2(MARGIN, extent.height() / 2.0f - RADIUS), extent2{DIAMETER, DIAMETER}};
53
54 minimizeRectangle =
55 aarectangle{point2(MARGIN + DIAMETER + SPACING, extent.height() / 2.0f - RADIUS), extent2{DIAMETER, DIAMETER}};
56
57 maximizeRectangle = aarectangle{
58 point2(MARGIN + DIAMETER + SPACING + DIAMETER + SPACING, extent.height() / 2.0f - RADIUS),
59 extent2{DIAMETER, DIAMETER}};
60
61 closeWindowGlyph = find_glyph(hikogui_icon::CloseWindow);
62 minimizeWindowGlyph = find_glyph(hikogui_icon::MinimizeWindow);
63 maximizeWindowGlyph = find_glyph(hikogui_icon::MaximizeWindowMacOS);
64 restoreWindowGlyph = find_glyph(hikogui_icon::RestoreWindowMacOS);
65 auto const glyph_size = 5.0f;
66
67 auto const closeWindowGlyphBB = closeWindowGlyph.get_metrics().bounding_rectangle * glyph_size;
68 auto const minimizeWindowGlyphBB = minimizeWindowGlyph.get_metrics().bounding_rectangle * glyph_size;
69 auto const maximizeWindowGlyphBB = maximizeWindowGlyph.get_metrics().bounding_rectangle * glyph_size;
70 auto const restoreWindowGlyphBB = restoreWindowGlyph.get_metrics().bounding_rectangle * glyph_size;
71
72 closeWindowGlyphRectangle = align(closeRectangle, closeWindowGlyphBB, alignment::middle_center());
73 minimizeWindowGlyphRectangle = align(minimizeRectangle, minimizeWindowGlyphBB, alignment::middle_center());
74 maximizeWindowGlyphRectangle = align(maximizeRectangle, maximizeWindowGlyphBB, alignment::middle_center());
75 restoreWindowGlyphRectangle = align(maximizeRectangle, restoreWindowGlyphBB, alignment::middle_center());
76 }
77 }
78
79 void draw(draw_context const& context) noexcept override
80 {
81 if (mode() > widget_mode::invisible and overlaps(context, layout())) {
82 auto const close_circle_color = (phase() == widget_phase::inactive) ? color(0.246f, 0.246f, 0.246f) :
83 pressedClose ? color(1.0f, 0.242f, 0.212f) :
84 color(1.0f, 0.1f, 0.082f);
85 context.draw_box(layout(), closeRectangle, close_circle_color, corner_radii{RADIUS});
86
87 auto const minimize_circle_color = (phase() == widget_phase::inactive) ? color(0.246f, 0.246f, 0.246f) :
88 pressedMinimize ? color(1.0f, 0.847f, 0.093f) :
89 color(0.784f, 0.521f, 0.021f);
90 context.draw_box(layout(), minimizeRectangle, minimize_circle_color, corner_radii{RADIUS});
91
92 auto const maximize_circle_color = (phase() == widget_phase::inactive) ? color(0.246f, 0.246f, 0.246f) :
93 pressedMaximize ? color(0.223f, 0.863f, 0.1f) :
94 color(0.082f, 0.533f, 0.024f);
95
96 context.draw_box(layout(), maximizeRectangle, maximize_circle_color, corner_radii{RADIUS});
97
98 if (phase() == widget_phase::hover) {
99 context.draw_glyph(
100 layout(), translate_z(0.1f) * closeWindowGlyphRectangle, closeWindowGlyph, color{0.319f, 0.0f, 0.0f});
101 context.draw_glyph(
102 layout(), translate_z(0.1f) * minimizeWindowGlyphRectangle, minimizeWindowGlyph, color{0.212f, 0.1f, 0.0f});
103
104 if (layout().window_size_state == gui_window_size::maximized) {
105 context.draw_glyph(
106 layout(), translate_z(0.1f) * restoreWindowGlyphRectangle, restoreWindowGlyph, color{0.0f, 0.133f, 0.0f});
107 } else {
108 context.draw_glyph(
109 layout(),
110 translate_z(0.1f) * maximizeWindowGlyphRectangle,
111 maximizeWindowGlyph,
112 color{0.0f, 0.133f, 0.0f});
113 }
114 }
115 }
116 }
117
118 bool handle_event(gui_event const& event) noexcept override
119 {
120 switch (event.type()) {
121 case gui_event_type::mouse_move:
122 case gui_event_type::mouse_drag:
123 {
124 // Check the hover states of each button.
125 auto state_has_changed = false;
126 state_has_changed |= compare_store(hoverClose, closeRectangle.contains(event.mouse().position));
127 state_has_changed |= compare_store(hoverMinimize, minimizeRectangle.contains(event.mouse().position));
128 state_has_changed |= compare_store(hoverMaximize, maximizeRectangle.contains(event.mouse().position));
129 if (state_has_changed) {
131 }
132 }
133 break;
134
135 case gui_event_type::mouse_exit:
136 hoverClose = false;
137 hoverMinimize = false;
138 hoverMaximize = false;
140 return super::handle_event(event);
141
142 case gui_event_type::mouse_down:
143 if (event.mouse().cause.left_button) {
144 if (closeRectangle.contains(event.mouse().position)) {
145 pressedClose = true;
146
147 } else if (minimizeRectangle.contains(event.mouse().position)) {
148 pressedMinimize = true;
149
150 } else if (maximizeRectangle.contains(event.mouse().position)) {
151 pressedMaximize = true;
152 }
154 return true;
155 }
156 break;
157
158 case gui_event_type::mouse_up:
159 if (event.mouse().cause.left_button) {
160 pressedClose = false;
161 pressedMinimize = false;
162 pressedMaximize = false;
164
165 if (closeRectangle.contains(event.mouse().position)) {
167
168 } else if (minimizeRectangle.contains(event.mouse().position)) {
170
171 } else if (maximizeRectangle.contains(event.mouse().position)) {
172 switch (layout().window_size_state) {
173 case gui_window_size::normal:
175
176 case gui_window_size::maximized:
178
179 default:
180 hi_no_default();
181 }
182 }
183 return true;
184 }
185 break;
186
187 default:;
188 }
189 return super::handle_event(event);
190 }
191
192 [[nodiscard]] hitbox hitbox_test(point2 position) const noexcept override
193 {
194 hi_axiom(loop::main().on_thread());
195
196 if (mode() >= widget_mode::partial and layout().contains(position) and
197 (closeRectangle.contains(position) or minimizeRectangle.contains(position) or maximizeRectangle.contains(position))) {
198 return hitbox{id, _layout.elevation, hitbox_type::button};
199 } else {
200 return {};
201 }
202 }
204private:
205 constexpr static int GLYPH_SIZE = 5;
206 constexpr static int RADIUS = 5;
207 constexpr static int DIAMETER = RADIUS * 2;
208 constexpr static int MARGIN = 10;
209 constexpr static int SPACING = 8;
210
211 aarectangle closeRectangle;
212 aarectangle minimizeRectangle;
213 aarectangle maximizeRectangle;
214
215 font_book::font_glyph_type closeWindowGlyph;
216 font_book::font_glyph_type minimizeWindowGlyph;
217 font_book::font_glyph_type maximizeWindowGlyph;
218 font_book::font_glyph_type restoreWindowGlyph;
219
220 aarectangle closeWindowGlyphRectangle;
221 aarectangle minimizeWindowGlyphRectangle;
222 aarectangle maximizeWindowGlyphRectangle;
223 aarectangle restoreWindowGlyphRectangle;
224
225 bool hoverClose = false;
226 bool hoverMinimize = false;
227 bool hoverMaximize = false;
228
229 bool pressedClose = false;
230 bool pressedMinimize = false;
231 bool pressedMaximize = false;
232};
233
234}} // namespace hi::v1
Defines widget.
@ window_normalize
Request the window to be restored to the original size after a minimize and maximize commands.
@ window_minimize
Request the window to minimize.
@ window_close
Request the window to be closed.
@ window_maximize
Request the window to maximize.
@ partial
A widget is partially enabled.
@ invisible
The widget is invisible.
The HikoGUI namespace.
Definition array_generic.hpp:20
bool compare_store(T &lhs, U &&rhs) noexcept
Compare then store if there was a change.
Definition misc.hpp:53
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
This is a RGBA floating point color.
Definition color_intf.hpp:49
Class which represents an axis-aligned rectangle.
Definition aarectangle.hpp:33
constexpr bool contains(point2 const &rhs) const noexcept
Check if a 2D coordinate is inside the rectangle.
Definition aarectangle.hpp:268
The 4 radii of the corners of a quad or rectangle.
Definition corner_radii.hpp:26
A high-level geometric extent.
Definition extent2.hpp:32
constexpr float & width() noexcept
Access the x-as-width element from the extent.
Definition extent2.hpp:107
Draw context for drawing using the HikoGUI shaders.
Definition draw_context_intf.hpp:209
point2 position
The current position of the mouse pointer.
Definition gui_event.hpp:44
mouse_buttons cause
Buttons which have caused this event.
Definition gui_event.hpp:62
A user interface event.
Definition gui_event.hpp:82
constexpr gui_event_type type() const noexcept
Get the event type.
Definition gui_event.hpp:221
mouse_event_data & mouse() noexcept
Get the mouse event information.
Definition gui_event.hpp:264
Definition widget_intf.hpp:24
widget_id id
The numeric identifier of a widget.
Definition widget_intf.hpp:30
widget_layout const & layout() const noexcept
Get the current layout for this widget.
Definition widget_intf.hpp:206
widget_intf * parent
Pointer to the parent widget.
Definition widget_intf.hpp:35
The layout of a widget.
Definition widget_layout.hpp:56
2D constraints.
Definition box_constraints.hpp:25
An interactive graphical object as part of the user-interface.
Definition widget.hpp:37
void request_redraw() const noexcept override
Request the widget to be redrawn on the next frame.
Definition widget.hpp:141
widget() noexcept
Constructor for creating sub views.
Definition widget.hpp:55
bool process_event(gui_event const &event) const noexcept override
Send a event to the window.
Definition widget.hpp:130
bool handle_event(gui_event const &event) noexcept override
Handle command.
Definition widget.hpp:150
Window control button widget.
Definition window_controls_macos_widget.hpp:29