Sparkle 0.0.1
Loading...
Searching...
No Matches
spk_interface_window.hpp
1#pragma once
2
3#include <algorithm>
4#include <iostream>
5
6#include "structure/widget/spk_scalable_widget.hpp"
7
8#include "structure/widget/spk_frame.hpp"
9#include "structure/widget/spk_icon_button.hpp"
10#include "structure/widget/spk_linear_layout.hpp"
11#include "structure/widget/spk_text_label.hpp"
12
13namespace spk
14{
25 template <typename TContentType>
27 {
28 private:
29 class TitleBar;
30
31 class TitleBar : public spk::Widget
32 {
33 friend class InterfaceWindow;
34
35 private:
36 spk::HorizontalLayout _layout;
37
38 spk::Frame _background;
39 spk::TextLabel _titleLabel;
40 spk::IconButton _minimizeButton;
41 spk::IconButton _maximizeButton;
42 spk::IconButton _closeButton;
43
44 InterfaceWindow *_owner;
45 bool _isDragging = false;
46 bool _hasMouseFocus = false;
47 spk::Vector2Int _dragStartMousePosition;
48 spk::Extend2D _dragStartGeometry;
49
50 void _onGeometryChange() override
51 {
52 _background.setGeometry(geometry().atOrigin());
53 setHeight(geometry().size.y);
54 _layout.setGeometry(geometry().atOrigin());
55 }
56
57 public:
58 TitleBar(const std::wstring &p_name, spk::Widget *p_parent, InterfaceWindow *p_owner) :
59 spk::Widget(p_name, p_parent),
60 _background(p_name + L"/Background", this),
61 _titleLabel(p_name + L"/TitleLabel", this),
62 _minimizeButton(p_name + L"/MinimizeButton", this),
63 _maximizeButton(p_name + L"/MaximizeButton", this),
64 _closeButton(p_name + L"/CloseButton", this),
65 _owner(p_owner)
66 {
67 _background.setLayer(0);
68 _background.setCornerSize({4, 4});
69 _background.activate();
70
71 _titleLabel.setTexture(nullptr);
72 _titleLabel.setLayer(1);
73 _titleLabel.setCornerSize({0, 0});
74 _titleLabel.setAlignment(spk::HorizontalAlignment::Centered, spk::VerticalAlignment::Centered);
75 _titleLabel.activate();
76
77 _minimizeButton.setLayer(1);
78 _minimizeButton.setTexture(&spk::Widget::Style::defaultInterfaceWindowButtonReleased, spk::IconButton::State::Released);
79 _minimizeButton.setTexture(&spk::Widget::Style::defaultInterfaceWindowButtonPressed, spk::IconButton::State::Pressed);
80 _minimizeButton.setCornerSize({4, 4});
82 _minimizeButton.setIconSpriteID({3, 0});
83 _minimizeButton.setIconPadding({5, 5});
84 _minimizeButton.activate();
85
86 _maximizeButton.setLayer(1);
87 _maximizeButton.setTexture(&spk::Widget::Style::defaultInterfaceWindowButtonReleased, spk::IconButton::State::Released);
88 _maximizeButton.setTexture(&spk::Widget::Style::defaultInterfaceWindowButtonPressed, spk::IconButton::State::Pressed);
89 _maximizeButton.setCornerSize({4, 4});
91 _maximizeButton.setIconSpriteID({1, 0});
92 _maximizeButton.setIconPadding({5, 5});
93 _maximizeButton.activate();
94
95 _closeButton.setLayer(1);
96 _closeButton.setTexture(&spk::Widget::Style::defaultInterfaceWindowButtonReleased, spk::IconButton::State::Released);
97 _closeButton.setTexture(&spk::Widget::Style::defaultInterfaceWindowButtonPressed, spk::IconButton::State::Pressed);
98 _closeButton.setCornerSize({4, 4});
100 _closeButton.setIconSpriteID({0, 0});
101 _closeButton.setIconPadding({5, 5});
102 _closeButton.activate();
103
104 setHeight(16);
105
106 _layout.setPadding(2);
107 _layout.addElement(&_titleLabel, spk::Layout::SizePolicy::Extend);
108 _layout.addElement(&_minimizeButton, spk::Layout::SizePolicy::Desired);
109 _layout.addElement(&_maximizeButton, spk::Layout::SizePolicy::Desired);
110 _layout.addElement(&_closeButton, spk::Layout::SizePolicy::Desired);
111
113 return (_layout.sizeHint().minimal());
114 });
115 }
116
117 void setTitle(const std::wstring &p_title)
118 {
119 _titleLabel.setText(p_title);
120 sizeHint().release();
121 }
122
123 void setHeight(size_t p_height)
124 {
125 _minimizeButton.sizeHint().setDesired({static_cast<uint32_t>(p_height), static_cast<uint32_t>(p_height)});
126 _maximizeButton.sizeHint().setDesired({static_cast<uint32_t>(p_height), static_cast<uint32_t>(p_height)});
127 _closeButton.sizeHint().setDesired({static_cast<uint32_t>(p_height), static_cast<uint32_t>(p_height)});
128 sizeHint().release();
129 _layout.sizeHint().release();
130 }
131
132 void toggleMaximizedMode()
133 {
134 if (_maximizeButton.iconSpriteID() == spk::Vector2UInt{2, 0})
135 {
136 _maximizeButton.setIconSpriteID({1, 0});
137 }
138 else
139 {
140 _maximizeButton.setIconSpriteID({2, 0});
141 }
142 _maximizeButton.setVisualState(spk::IconButton::State::Released);
143 }
144
145 private:
146 bool _isInsideTitleLabel(const spk::Vector2Int &p_position) const
147 {
148 return (_titleLabel.geometry().contains(p_position));
149 }
150
151 void _releaseMouseFocus()
152 {
153 if (_hasMouseFocus == true)
154 {
155 releaseFocus(FocusType::Mouse);
156 _hasMouseFocus = false;
157 }
158 }
159
160 void _onMousePressEvent(spk::MousePressEvent &p_event) override
161 {
162 if (p_event.button != spk::Mouse::Button::Left || _isInsideTitleLabel(p_event.mouse.position) == false ||
163 _owner->_isMaximized == true)
164 {
165 return;
166 }
167
168 _isDragging = true;
169 _dragStartMousePosition = p_event.mouse.position;
170 _dragStartGeometry = _owner->geometry();
171
172 if (hasFocus(FocusType::Mouse) == false)
173 {
174 takeFocus(FocusType::Mouse);
175 _hasMouseFocus = true;
176 }
177
178 p_event.isConsumed = true;
179 }
180
181 void _onMouseMotionEvent(spk::MouseMotionEvent &p_event) override
182 {
183 if (_isDragging == false)
184 {
185 return;
186 }
187
188 spk::Vector2Int delta = p_event.position - _dragStartMousePosition;
189 spk::Extend2D targetGeometry = _dragStartGeometry;
190 targetGeometry.anchor += delta;
191
192 _owner->setGeometry(targetGeometry);
193 p_event.isConsumed = true;
194 }
195
196 void _onMouseReleaseEvent(spk::MouseReleaseEvent &p_event) override
197 {
198 if (_isDragging == false || p_event.button != spk::Mouse::Button::Left)
199 {
200 return;
201 }
202
203 _isDragging = false;
204 _releaseMouseFocus();
205
206 p_event.isConsumed = true;
207 }
208
210 {
211 if (p_event.button != spk::Mouse::Button::Left || _isInsideTitleLabel(p_event.mouse.position) == false)
212 {
213 return;
214 }
215
216 _owner->_toggleMaximizedMode();
217 p_event.isConsumed = true;
218 }
219 };
220
221 spk::VerticalLayout _layout;
222
223 TitleBar _titleBar;
224 TContentType _content;
225
226 spk::IconButton::Contract _minimizeContract;
227 bool _isMaximized = false;
228 spk::Extend2D _baseGeometry;
229 spk::Extend2D _maximizedGeometry;
230 spk::IconButton::Contract _maximizeContract;
231 spk::IconButton::Contract _closeContract;
232
233 void _toggleMaximizedMode()
234 {
235 _titleBar.toggleMaximizedMode();
236 spk::ScalableWidget::setGeometry(_isMaximized == false ? _maximizedGeometry : _baseGeometry);
237 _isMaximized = !_isMaximized;
238 }
239
240 void _onGeometryChange() override
241 {
242 _layout.setGeometry(geometry().atOrigin());
243 }
244
245 public:
251 InterfaceWindow(const std::wstring &p_name, spk::Widget *p_parent) :
252 spk::ScalableWidget(p_name, p_parent),
253 _titleBar(p_name + L"/TitleBar", this, this),
254 _content(p_name + L"/Content", this)
255 {
256 _layout.setPadding(2);
257 _layout.addElement(&_titleBar, spk::Layout::SizePolicy::Standard);
258 _layout.addElement(&_content, spk::Layout::SizePolicy::Extend);
259
260 _minimizeContract = _titleBar._minimizeButton.subscribe([&]() {
261 _content.toggle();
262 });
263 _maximizeContract = _titleBar._maximizeButton.subscribe([&]() {
264 _toggleMaximizedMode();
265 });
266 _closeContract = _titleBar._closeButton.subscribe([&]() {
267 deactivate();
268 });
269
270 _titleBar.activate();
271 _content.activate();
272
274 spk::Vector2UInt titleBarMinimalSize = _titleBar.sizeHint().minimal();
275 spk::Vector2UInt contentMinimalSize = _content.sizeHint().minimal();
276
277 return (spk::Vector2UInt{
278 std::max(titleBarMinimalSize.x, contentMinimalSize.x),
279 titleBarMinimalSize.y + 2 + contentMinimalSize.y});
280 });
281 }
282
287 void setGeometry(const spk::Extend2D &p_geometry) override
288 {
290 _baseGeometry = p_geometry;
291 }
292
297 void setTitle(const std::wstring &p_title)
298 {
299 _titleBar.setTitle(p_title);
300 sizeHint().release();
301 }
302
307 void setTitleBarHeight(size_t p_height)
308 {
309 _titleBar.setHeight(p_height);
310 sizeHint().release();
311 }
312
317 void setMaximizedSize(const spk::Extend2D &p_maximizedGeometry)
318 {
319 _maximizedGeometry = p_maximizedGeometry;
320 }
321
325 void maximize()
326 {
327 if (_isMaximized == false)
328 {
329 _toggleMaximizedMode();
330 }
331 }
332
336 void minimize()
337 {
338 _content.deactivate();
339 }
340
344 void restore()
345 {
346 if (_content.isActive() == false)
347 {
348 _content.activate();
349 }
350
351 if (_isMaximized == true)
352 {
353 _toggleMaximizedMode();
354 }
355 }
356
361 TContentType &content()
362 {
363 return _content;
364 }
365
370 const TContentType &content() const
371 {
372 return _content;
373 }
374 };
375}
void deactivate()
Sets the state to Deactivated.
Definition spk_activable_object.hpp:61
void activate()
Sets the state to Activated.
Definition spk_activable_object.hpp:54
Widget frame rendered using a nine-slice background.
Definition spk_frame.hpp:19
void setCornerSize(const spk::Vector2UInt &p_cornerSize)
Sets the corner size for nine-slice rendering.
Definition spk_frame.cpp:22
Button widget that displays a background and icon per state.
Definition spk_icon_button.hpp:22
void setIconPadding(const spk::Vector2UInt &p_padding, State p_state=State::Both)
Sets icon padding for a state.
Definition spk_icon_button.cpp:266
void setCornerSize(const spk::Vector2UInt &p_cornerSize, State p_state=State::Both)
Sets the background corner size for a state.
Definition spk_icon_button.cpp:215
void setTexture(const spk::SpriteSheet *p_spriteSheet, State p_state=State::Both)
Sets the background texture for a state.
Definition spk_icon_button.cpp:201
const spk::Vector2UInt & iconSpriteID(State p_state=State::Both) const
Returns the icon sprite ID for a state.
Definition spk_icon_button.cpp:299
void setVisualState(const State &p_state)
Sets the current visual state.
Definition spk_icon_button.cpp:36
spk::TContractProvider<>::Contract Contract
Contract type for click subscriptions.
Definition spk_icon_button.hpp:27
void setIconSpriteID(const spk::Vector2UInt &p_spriteID, State p_state=State::Both)
Sets the icon sprite ID for a state.
Definition spk_icon_button.cpp:252
void setIconTexture(const spk::SpriteSheet &p_spriteSheet, State p_state=State::Both)
Sets the icon texture from a sprite sheet reference.
Definition spk_icon_button.cpp:233
void restore()
Restores the window content and geometry.
Definition spk_interface_window.hpp:344
TContentType & content()
Returns the content widget.
Definition spk_interface_window.hpp:361
const TContentType & content() const
Returns the content widget.
Definition spk_interface_window.hpp:370
InterfaceWindow(const std::wstring &p_name, spk::Widget *p_parent)
Builds an interface window widget.
Definition spk_interface_window.hpp:251
void setMaximizedSize(const spk::Extend2D &p_maximizedGeometry)
Sets the maximized window geometry.
Definition spk_interface_window.hpp:317
void setTitleBarHeight(size_t p_height)
Sets the title bar height.
Definition spk_interface_window.hpp:307
void setTitle(const std::wstring &p_title)
Sets the title bar text.
Definition spk_interface_window.hpp:297
void setGeometry(const spk::Extend2D &p_geometry) override
Sets the window geometry and updates base geometry.
Definition spk_interface_window.hpp:287
void minimize()
Minimizes the window content.
Definition spk_interface_window.hpp:336
void maximize()
Maximizes the window if not already maximized.
Definition spk_interface_window.hpp:325
void setDesired(const Vector2UInt &p_desiredValue)
Sets the desired size override.
Definition spk_resizable_element.cpp:63
void release()
Releases all cached size hint values.
Definition spk_resizable_element.cpp:36
void configureMinimalGenerator(Generator p_generator)
Configures the minimal size generator.
Definition spk_resizable_element.cpp:21
SizeHint & sizeHint()
Returns mutable size hint data.
Definition spk_resizable_element.cpp:86
Widget that supports interactive resizing via anchor handles.
Definition spk_scalable_widget.hpp:13
ScalableWidget(const std::wstring &p_name, Widget *p_parent)
Builds a scalable widget.
Definition spk_scalable_widget.cpp:255
void setGeometry(const spk::Extend2D &p_extend2D) override
Sets the widget geometry and updates resize handles.
Definition spk_scalable_widget.cpp:262
Widget that renders a text region over a nine-slice background.
Definition spk_text_label.hpp:20
void setTexture(const spk::SpriteSheet *p_spriteSheet)
Assigns the sprite sheet used for the background.
Definition spk_text_label.cpp:30
void setText(const std::wstring &p_text)
Updates the label text.
Definition spk_text_label.cpp:77
void setAlignment(HorizontalAlignment p_horizontalAlignment, VerticalAlignment p_verticalAlignment)
Sets the horizontal and vertical alignment for the text.
Definition spk_text_label.cpp:88
void setCornerSize(const spk::Vector2UInt &p_cornerSize)
Sets the corner size for the nine-slice background.
Definition spk_text_label.cpp:18
Base class for interactive UI elements handling focus and events.
Definition spk_widget.hpp:52
void setGeometry(const spk::Extend2D &p_geometry) override
Requests a specific viewport and scissor region for the widget.
Definition spk_widget.cpp:168
virtual void _onMouseDoubleClickEvent(spk::MouseDoubleClickEvent &p_event)
Mouse double click handler for derived widgets.
Definition spk_widget.cpp:244
virtual void _onGeometryChange()
Notifies derived widgets that the view region changed.
Definition spk_widget.cpp:292
virtual void _onMousePressEvent(spk::MousePressEvent &p_event)
Mouse button press handler for derived widgets.
Definition spk_widget.cpp:236
virtual void _onMouseReleaseEvent(spk::MouseReleaseEvent &p_event)
Mouse button release handler for derived widgets.
Definition spk_widget.cpp:240
virtual void _onMouseMotionEvent(spk::MouseMotionEvent &p_event)
Mouse motion handler for derived widgets.
Definition spk_widget.cpp:248
const spk::Extend2D & geometry() const
Returns the current widget geometry.
Definition spk_widget.cpp:195
void releaseFocus(FocusType p_focusType)
Releases a previously acquired focus type.
Definition spk_widget.cpp:34
bool hasFocus(FocusType p_focusType) const
Checks if this widget currently owns a focus type.
Definition spk_widget.cpp:43
void takeFocus(FocusType p_focusType)
Grants this widget ownership of the requested focus type.
Definition spk_widget.cpp:29
void setLayer(const float &p_newLayer)
Updates the widget layer and propagates relative offsets to children.
Definition spk_widget.cpp:141
Axis-aligned rectangle defined by an anchor point and size.
Definition spk_extend_2d.hpp:24
bool contains(const Vector2Int &p_point) const
Tests whether a point lies within the rectangle bounds.
Definition spk_extend_2d.cpp:43
bool isConsumed
Indicates whether the event has been handled.
Definition spk_ievent.hpp:17
TType x
X component.
Definition spk_vector2.hpp:44
TType y
Y component.
Definition spk_vector2.hpp:48
Mouse button double-click event.
Definition spk_mouse_event.hpp:38
const Mouse & mouse
Snapshot of mouse state at double-click time.
Definition spk_mouse_event.hpp:43
Mouse::Button button
Mouse button that triggered the double click.
Definition spk_mouse_event.hpp:40
spk::Vector2Int position
Current cursor position.
Definition spk_mouse.hpp:39
Mouse move event carrying current position.
Definition spk_mouse_event.hpp:50
spk::Vector2Int position
Current cursor position in window coordinates.
Definition spk_mouse_event.hpp:52
Mouse button press event.
Definition spk_mouse_event.hpp:14
const Mouse & mouse
Snapshot of mouse state at press time.
Definition spk_mouse_event.hpp:19
Mouse::Button button
Mouse button that was pressed.
Definition spk_mouse_event.hpp:16
Mouse button release event.
Definition spk_mouse_event.hpp:26
Mouse::Button button
Mouse button that was released.
Definition spk_mouse_event.hpp:28
static spk::SpriteSheet defaultInterfaceWindowButtonReleased
Default sprite sheet for released interface window buttons.
Definition spk_widget.hpp:74
static spk::SpriteSheet defaultInterfaceWindowButtonPressed
Default sprite sheet for pressed interface window buttons.
Definition spk_widget.hpp:76
static spk::SpriteSheet defaultIconset
Default sprite sheet used for widget icons.
Definition spk_widget.hpp:72