neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
button.ipp
Go to the documentation of this file.
1// button.ipp
2/*
3 neogfx C++ App/Game Engine
4 Copyright (c) 2015, 2020 Leigh Johnston. All Rights Reserved.
5
6 This program is free software: you can redistribute it and / or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#pragma once
21
22#include <neogfx/neogfx.hpp>
23#include <neogfx/app/i_app.hpp>
25
26namespace neogfx
27{
28 template <typename ButtonInterface>
30 base_type{}, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, label_type::MultiLine, aAlignment }
31 {
32 init();
33 }
34
35 template <typename ButtonInterface>
36 button<ButtonInterface>::button(std::string const& aText, alignment aAlignment) :
37 base_type{}, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aText, label_type::MultiLine, aAlignment }
38 {
39 init();
40 }
41
42 template <typename ButtonInterface>
44 base_type{}, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aTexture, label_type::MultiLine, aAlignment }
45 {
46 init();
47 }
48
49 template <typename ButtonInterface>
51 base_type{}, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aImage, label_type::MultiLine, aAlignment }
52 {
53 init();
54 }
56 template <typename ButtonInterface>
57 button<ButtonInterface>::button(std::string const& aText, const i_texture& aTexture, alignment aAlignment) :
58 base_type{}, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aText, aTexture, label_type::MultiLine, aAlignment }
59 {
60 init();
61 }
63 template <typename ButtonInterface>
64 button<ButtonInterface>::button(std::string const& aText, const i_image& aImage, alignment aAlignment) :
65 base_type{}, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aText, aImage, label_type::MultiLine, aAlignment }
66 {
67 init();
68 }
70 template <typename ButtonInterface>
72 base_type{ aParent }, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, label_type::MultiLine, aAlignment }
73 {
74 init();
75 }
76
77 template <typename ButtonInterface>
78 button<ButtonInterface>::button(i_widget& aParent, std::string const& aText, alignment aAlignment) :
79 base_type{ aParent }, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aText, label_type::MultiLine, aAlignment }
80 {
81 init();
82 }
84 template <typename ButtonInterface>
85 button<ButtonInterface>::button(i_widget& aParent, const i_texture& aTexture, alignment aAlignment) :
86 base_type{ aParent }, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aTexture, label_type::MultiLine, aAlignment }
87 {
88 init();
89 }
91 template <typename ButtonInterface>
92 button<ButtonInterface>::button(i_widget& aParent, const i_image& aImage, alignment aAlignment) :
93 base_type{ aParent }, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aImage, label_type::MultiLine, aAlignment }
94 {
95 init();
96 }
98 template <typename ButtonInterface>
99 button<ButtonInterface>::button(i_widget& aParent, std::string const& aText, const i_texture& aTexture, alignment aAlignment) :
100 base_type{ aParent }, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aText, aTexture, label_type::MultiLine, aAlignment }
102 init();
105 template <typename ButtonInterface>
106 button<ButtonInterface>::button(i_widget& aParent, std::string const& aText, const i_image& aImage, alignment aAlignment) :
107 base_type{ aParent }, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aText, aImage, label_type::MultiLine, aAlignment }
108 {
109 init();
112 template <typename ButtonInterface>
114 base_type{ aLayout }, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, label_type::MultiLine, aAlignment }
115 {
116 init();
118
119 template <typename ButtonInterface>
120 button<ButtonInterface>::button(i_layout& aLayout, std::string const& aText, alignment aAlignment) :
121 base_type{ aLayout }, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aText, label_type::MultiLine, aAlignment }
122 {
123 init();
126 template <typename ButtonInterface>
127 button<ButtonInterface>::button(i_layout& aLayout, const i_texture& aTexture, alignment aAlignment) :
128 base_type{ aLayout }, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aTexture, label_type::MultiLine, aAlignment }
129 {
130 init();
131 }
132
133 template <typename ButtonInterface>
134 button<ButtonInterface>::button(i_layout& aLayout, const i_image& aImage, alignment aAlignment) :
135 base_type{ aLayout }, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aImage, label_type::MultiLine, aAlignment }
136 {
137 init();
138 }
139
140 template <typename ButtonInterface>
141 button<ButtonInterface>::button(i_layout& aLayout, std::string const& aText, const i_texture& aTexture, alignment aAlignment) :
142 base_type{ aLayout }, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aText, aTexture, label_type::MultiLine, aAlignment }
143 {
144 init();
145 }
146
147 template <typename ButtonInterface>
148 button<ButtonInterface>::button(i_layout& aLayout, std::string const& aText, const i_image& aImage, alignment aAlignment) :
149 base_type{ aLayout }, iPressed{ false }, iCheckable{ button_checkable::NotCheckable }, iCheckedState{ false }, iLayout{ *this }, iLabel{ iLayout, aText, aImage, label_type::MultiLine, aAlignment }
150 {
151 init();
152 }
153
154 template <typename ButtonInterface>
156 {
157 service<i_app>().remove_mnemonic(*this);
158 }
159
160 template <typename ButtonInterface>
162 {
163 if (base_type::has_size_policy())
164 return base_type::size_policy();
165 else if (base_type::has_fixed_size())
167 else
168 return neogfx::size_policy{ size_constraint::Expanding, size_constraint::Minimum };
169 }
170
171 template <typename ButtonInterface>
173 {
174 if (base_type::has_maximum_size())
175 return base_type::maximum_size();
176 auto result = base_type::maximum_size();
177 if (size_policy().horizontal_constraint() != size_constraint::Minimum)
178 result.cx = size::max_dimension();
179 if (size_policy().vertical_constraint() != size_constraint::Minimum)
180 result.cy = size::max_dimension();
181 return result;
182 }
183
184 template <typename ButtonInterface>
186 {
187 neogfx::padding result = base_type::padding();
188 if (!base_type::has_padding() && (label().effective_placement() & label_placement::Text) == label_placement::Text)
189 {
190 result.left *= 2.0;
191 result.right *= 2.0;
192 }
193 return result;
194 }
195
196 template <typename ButtonInterface>
198 {
199 return iPressed;
200 }
201
202 template <typename ButtonInterface>
204 {
205 return iCheckable;
206 }
207
208 template <typename ButtonInterface>
210 {
211 iCheckable = aCheckable;
212 }
213
214 template <typename ButtonInterface>
216 {
217 return iCheckedState != std::nullopt && *iCheckedState == true;
218 }
219
220 template <typename ButtonInterface>
222 {
223 return iCheckedState != std::nullopt && *iCheckedState == false;
224 }
225
226 template <typename ButtonInterface>
228 {
229 return iCheckedState == std::nullopt;
230 }
231
232 template <typename ButtonInterface>
234 {
235 set_checked_state(true);
236 }
237
238 template <typename ButtonInterface>
240 {
241 set_checked_state(false);
242 }
243
244 template <typename ButtonInterface>
246 {
247 set_checked_state(std::nullopt);
248 }
249
250 template <typename ButtonInterface>
252 {
253 set_checked_state(aChecked);
254 }
255
256 template <typename ButtonInterface>
258 {
259 if (!can_toggle())
260 return;
261 if (is_checked() || is_indeterminate())
262 set_checked(false);
263 else
264 set_checked(true);
265 }
266
267 template <typename ButtonInterface>
269 {
270 return label().text();
271 }
272
273 template <typename ButtonInterface>
275 {
276 label().set_text(aText);
277 }
278
279 template <typename ButtonInterface>
281 {
282 return label().image();
283 }
284
285 template <typename ButtonInterface>
287 {
288 label().set_image(neogfx::image{ aImageUri });
289 }
290
291 template <typename ButtonInterface>
293 {
294 label().set_image(aImage);
295 }
296
297 template <typename ButtonInterface>
299 {
300 label().set_image(aImage);
301 }
302
303 template <typename ButtonInterface>
309
310 template <typename ButtonInterface>
312 {
313 return iLabel;
314 }
315
316 template <typename ButtonInterface>
318 {
319 return iLabel;
320 }
321
322 template <typename ButtonInterface>
324 {
325 return label().text_widget();
326 }
327
328 template <typename ButtonInterface>
333
334 template <typename ButtonInterface>
336 {
337 return label().image_widget();
338 }
339
340 template <typename ButtonInterface>
342 {
343 return label().image_widget();
344 }
345
346 template <typename ButtonInterface>
348 {
349 base_type::mouse_button_pressed(aButton, aPosition, aKeyModifiers);
350 if (aButton == mouse_button::Left)
351 {
352 as_widget().update();
353 iPressed = true;
354 Pressed.trigger();
355 }
356 }
357
358 template <typename ButtonInterface>
360 {
361 base_type::mouse_button_double_clicked(aButton, aPosition, aKeyModifiers);
362 if (aButton == mouse_button::Left)
363 {
364 as_widget().update();
365 DoubleClicked.trigger();
366 }
367 }
368
369 template <typename ButtonInterface>
371 {
372 bool wasCapturing = as_widget().capturing();
373 base_type::mouse_button_released(aButton, aPosition);
374 if (aButton == mouse_button::Left)
375 {
376 as_widget().update();
377 if (wasCapturing)
378 {
379 destroyed_flag destroyed{ *this };
380 iPressed = false;
381 if (as_widget().client_rect().contains(aPosition))
382 handle_clicked();
383 if (!destroyed)
384 Released.trigger();
385 }
386 }
387 else if (aButton == mouse_button::Right)
388 {
389 if (wasCapturing && as_widget().client_rect().contains(aPosition))
390 RightClicked.trigger();
391 }
392 }
393
394 template <typename ButtonInterface>
396 {
397 if (aScanCode == ScanCode_SPACE)
398 {
399 handle_clicked();
400 return true;
401 }
402 return false;
403 }
404
405 template <typename ButtonInterface>
407 {
408 destroyed_flag destroyed{ *this };
409 Clicked.trigger();
410 if (!destroyed && iCheckable != button_checkable::NotCheckable)
411 toggle();
412 }
413
414 template <typename ButtonInterface>
416 {
417 return true;
418 }
419
420 template <typename ButtonInterface>
421 const std::optional<bool>& button<ButtonInterface>::checked_state() const
422 {
423 return iCheckedState;
424 }
425
426 template <typename ButtonInterface>
427 bool button<ButtonInterface>::set_checked_state(const std::optional<bool>& aCheckedState)
428 {
429 if (iCheckedState == aCheckedState)
430 return false;
431 if (aCheckedState == std::nullopt && iCheckable != button_checkable::TriState)
432 throw not_tri_state_checkable();
433 iCheckedState = aCheckedState;
434 as_widget().update();
435 Toggled.trigger();
436 if (is_checked())
437 Checked.trigger();
438 else if (is_unchecked())
439 Unchecked.trigger();
440 else if (is_indeterminate())
441 Indeterminate.trigger();
442 return true;
443 }
444
445 template <typename ButtonInterface>
447 {
448 return mnemonic_from_text(label().text());
449 }
450
451 template <typename ButtonInterface>
453 {
454 handle_clicked();
455 }
456
457 template <typename ButtonInterface>
459 {
460 return label().text_widget();
461 }
462
463 template <typename ButtonInterface>
465 {
466 Pressed.set_trigger_type(trigger_type::Asynchronous);
467 Clicked.set_trigger_type(trigger_type::Asynchronous);
468 DoubleClicked.set_trigger_type(trigger_type::Asynchronous);
469 RightClicked.set_trigger_type(trigger_type::Asynchronous);
470 Released.set_trigger_type(trigger_type::Asynchronous);
471 Toggled.set_trigger_type(trigger_type::Asynchronous);
472 Checked.set_trigger_type(trigger_type::Asynchronous);
473 Unchecked.set_trigger_type(trigger_type::Asynchronous);
474 Indeterminate.set_trigger_type(trigger_type::Asynchronous);
475
476 as_widget().layout().set_padding(neogfx::padding{});
477 as_widget().layout().set_alignment(alignment::Center | alignment::VCenter);
478 as_widget().set_focus_policy(focus_policy::TabFocus);
479
480 auto label_text_updated = [this]()
481 {
482 auto m = mnemonic_from_text(label().text());
483 if (!m.empty())
484 service<i_app>().add_mnemonic(*this);
485 else
486 service<i_app>().remove_mnemonic(*this);
487 };
488 iSink = label().text_widget().TextChanged(label_text_updated);
489 label_text_updated();
490 }
491}
492
493
static constexpr dimension_type max_dimension()
void set_image(i_string const &aImageUri)
Definition button.ipp:286
void set_text(i_string const &aText)
Definition button.ipp:274
void mouse_button_double_clicked(mouse_button aButton, const point &aPosition, key_modifiers_e aKeyModifiers) override
Definition button.ipp:359
virtual void handle_clicked()
Definition button.ipp:406
virtual bool set_checked_state(const std::optional< bool > &aCheckedState)
Definition button.ipp:427
const neogfx::text_widget & text_widget() const
Definition button.ipp:323
neogfx::size_policy size_policy() const override
Definition button.ipp:161
virtual const std::optional< bool > & checked_state() const
Definition button.ipp:421
bool is_checked() const override
Definition button.ipp:215
void set_checkable(button_checkable aCheckable=button_checkable::BiState) override
Definition button.ipp:209
void toggle() override
Definition button.ipp:257
button_checkable checkable() const override
Definition button.ipp:203
bool is_unchecked() const override
Definition button.ipp:221
bool key_pressed(scan_code_e aScanCode, key_code_e aKeyCode, key_modifiers_e aKeyModifiers) override
Definition button.ipp:395
void set_checked(bool aChecked) override
Definition button.ipp:251
button(alignment aAlignment=alignment::Left|alignment::VCenter)
Definition button.ipp:29
std::string mnemonic() const override
Definition button.ipp:446
void mouse_button_pressed(mouse_button aButton, const point &aPosition, key_modifiers_e aKeyModifiers) override
Definition button.ipp:347
const neogfx::image_widget & image_widget() const
Definition button.ipp:335
size maximum_size(optional_size const &) const override
Definition button.ipp:172
const texture & image() const
Definition button.ipp:280
neogfx::padding padding() const override
Definition button.ipp:185
void set_image_extents(const optional_size &aImageExtents)
Definition button.ipp:304
i_widget & mnemonic_widget() override
Definition button.ipp:458
virtual bool can_toggle() const
Definition button.ipp:415
bool is_indeterminate() const override
Definition button.ipp:227
void check() override
Definition button.ipp:233
i_string const & text() const
Definition button.ipp:268
void mnemonic_execute() override
Definition button.ipp:452
bool is_pressed() const override
Definition button.ipp:197
void mouse_button_released(mouse_button aButton, const point &aPosition) override
Definition button.ipp:370
const neogfx::label & label() const
Definition button.ipp:311
void uncheck() override
Definition button.ipp:239
void set_indeterminate() override
Definition button.ipp:245
virtual void set_alignment(optional_alignment const &aAlignment, bool aUpdateLayout=true)=0
void set_fixed_size(optional_size const &aFixedSize, bool aUpdateLayout=true)
void set_size_policy(const optional_size_policy &aSizePolicy, bool aUpdateLayout=true) override
text_widget(std::string const &aText=std::string{}, text_widget_type aType=text_widget_type::SingleLine, text_widget_flags aFlags=text_widget_flags::None)
const i_layout & layout() const override
Definition widget.ipp:611
std::string mnemonic_from_text(std::string const &aText, char aMnemonicPrefix='&')
bool contains(item_selection const &aSelection, item_presentation_model_index aIndex)
@ ScanCode_SPACE
mouse_button
Definition i_mouse.hpp:31
button_checkable
Definition i_button.hpp:30