The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
distributor.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2009 - 2025
3 by Mark de Wever <koraq@xs4all.nl>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
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 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16#define GETTEXT_DOMAIN "wesnoth-lib"
17
19
20#include "gui/core/log.hpp"
21#include "gui/core/timer.hpp"
25#include "sdl/input.hpp" // get_mouse_button_mask
26
27#include <SDL3/SDL_events.h>
28
29#include <array>
30#include <functional>
31
32namespace gui2::event
33{
34/**
35 * Small helper to keep a resource (boolean) locked.
36 *
37 * Some of the event handling routines can't be called recursively, this due to
38 * the fact that they are attached to the pre queue and when the forward an
39 * event the pre queue event gets triggered recursively causing infinite
40 * recursion.
41 *
42 * To prevent that those functions check the lock and exit when the lock is
43 * held otherwise grab the lock here.
44 */
46{
47public:
48 resource_locker(bool& locked) : locked_(locked)
49 {
50 assert(!locked_);
51 locked_ = true;
52 }
53
55 {
56 assert(locked_);
57 locked_ = false;
58 }
59
60private:
61 bool& locked_;
62};
63
64
65/***** ***** ***** ***** mouse_motion ***** ***** ***** ***** *****/
66
67#define LOG_HEADER "distributor mouse motion [" << owner_.id() << "]: "
68
70 : mouse_focus_(nullptr)
71 , mouse_captured_(false)
72 , owner_(owner)
73 , hover_timer_(0)
74 , hover_widget_(nullptr)
75 , hover_position_(0, 0)
76 , hover_shown_(true)
77 , signal_handler_sdl_mouse_motion_entered_(false)
78{
81 this,
82 std::placeholders::_2,
83 std::placeholders::_3,
84 std::placeholders::_5),
85 queue_position);
86
89 this,
90 std::placeholders::_2,
91 std::placeholders::_3,
92 std::placeholders::_5,
93 std::placeholders::_6),
94 queue_position);
95
98 this,
99 std::placeholders::_2,
100 std::placeholders::_3,
101 std::placeholders::_5
102 ));
103
106 this,
107 std::placeholders::_2,
108 std::placeholders::_3,
109 std::placeholders::_5
110 ));
111
114 this,
115 std::placeholders::_2,
116 std::placeholders::_3,
117 std::placeholders::_5
118 ));
119
122 this,
123 std::placeholders::_2,
124 std::placeholders::_3,
125 std::placeholders::_5
126 ));
127
130 this,
131 std::placeholders::_2,
132 std::placeholders::_3,
133 std::placeholders::_5),
134 queue_position);
135}
136
141
142void mouse_motion::capture_mouse(const bool capture)
143{
144 assert(mouse_focus_);
145 mouse_captured_ = capture;
146}
147
148void mouse_motion::signal_handler_sdl_mouse_motion(const event::ui_event event, bool& handled, const point& coordinate)
149{
151 return;
152 }
154
155 DBG_GUI_E << LOG_HEADER << event << ".";
156
157 if(mouse_captured_) {
158 assert(mouse_focus_);
159 if(!owner_.fire(event, *mouse_focus_, coordinate)) {
160 mouse_hover(mouse_focus_, coordinate);
161 }
162 } else {
163 widget* mouse_over = owner_.find_at(coordinate, true);
164 while(mouse_over && !mouse_over->can_mouse_focus() && mouse_over->parent()) {
165 mouse_over = mouse_over->parent();
166 }
167
168 if(mouse_over) {
169 DBG_GUI_E << LOG_HEADER << "Firing: " << event << ".";
170 if(owner_.fire(event, *mouse_over, coordinate)) {
171 return;
172 }
173 }
174
175 if(!mouse_focus_ && mouse_over) {
176 mouse_enter(mouse_over);
177 } else if(mouse_focus_ && !mouse_over) {
178 mouse_leave();
179 } else if(mouse_focus_ && mouse_focus_ == mouse_over) {
180 mouse_hover(mouse_over, coordinate);
181 } else if(mouse_focus_ && mouse_over) {
182 // moved from one widget to the next
183 mouse_leave();
184 mouse_enter(mouse_over);
185 } else {
186 assert(!mouse_focus_ && !mouse_over);
187 }
188 }
189 handled = true;
190}
191
193 const event::ui_event event, bool& handled, const point& coordinate, const point& distance)
194{
195 DBG_GUI_E << LOG_HEADER << event << ".";
196
197 if(mouse_captured_) {
198 assert(mouse_focus_);
199 owner_.fire(event, *mouse_focus_, coordinate, distance);
200 } else {
201 if(widget* mouse_over = owner_.find_at(coordinate, true)) {
202 owner_.fire(event, *mouse_over, coordinate, distance);
203 }
204 }
205 handled = true;
206}
207
208void mouse_motion::signal_handler_sdl_wheel(const event::ui_event event, bool& handled, const point& coordinate)
209{
210 DBG_GUI_E << LOG_HEADER << event << ".";
211
212 if(mouse_captured_) {
213 assert(mouse_focus_);
214 owner_.fire(event, *mouse_focus_, coordinate);
215 } else {
216 if(widget* mouse_over = owner_.find_at(coordinate, true)) {
217 owner_.fire(event, *mouse_over, coordinate);
218 }
219 }
220 handled = true;
221}
222
223void mouse_motion::signal_handler_show_helptip(const event::ui_event event, bool& handled, const point& coordinate)
224{
225 DBG_GUI_E << LOG_HEADER << event << ".";
226
227 if(mouse_captured_) {
228 assert(mouse_focus_);
229 if(owner_.fire(event, *mouse_focus_, coordinate)) {
231 }
232 } else {
233 if(widget* mouse_over = owner_.find_at(coordinate, true)) {
234 DBG_GUI_E << LOG_HEADER << "Firing: " << event << ".";
235 if(owner_.fire(event, *mouse_over, coordinate)) {
237 }
238 }
239 }
240
241 handled = true;
242}
243
245{
246 DBG_GUI_E << LOG_HEADER << "Firing: " << event::MOUSE_ENTER << ".";
247
248 assert(mouse_over);
249
250 mouse_focus_ = mouse_over;
251 owner_.fire(event::MOUSE_ENTER, *mouse_over);
252
253 hover_shown_ = false;
255}
256
257void mouse_motion::mouse_hover(widget* mouse_over, const point& coordinate)
258{
259 DBG_GUI_E << LOG_HEADER << "Firing: " << event::MOUSE_MOTION << ".";
260
261 assert(mouse_over);
262
263 owner_.fire(event::MOUSE_MOTION, *mouse_over, coordinate);
264
265 if(hover_timer_) {
266 if((std::abs(hover_position_.x - coordinate.x) > 5) || (std::abs(hover_position_.y - coordinate.y) > 5)) {
268 start_hover_timer(mouse_over, coordinate);
269 }
270 }
271}
272
274{
275 DBG_GUI_E << LOG_HEADER << "Firing: " << event::SHOW_TOOLTIP << ".";
276
277 if(!hover_widget_) {
278 // See mouse_motion::stop_hover_timer.
279 ERR_GUI_E << LOG_HEADER << event::SHOW_TOOLTIP << " bailing out, no hover widget.";
280 return;
281 }
282
283 /*
284 * Ignore the result of the event, always mark the tooltip as shown. If
285 * there was no handler, there is no reason to assume there will be one
286 * next time.
287 */
289
290 hover_shown_ = true;
291
292 hover_timer_ = 0;
293 hover_widget_ = nullptr;
295}
296
298{
299 DBG_GUI_E << LOG_HEADER << "Firing: " << event::MOUSE_LEAVE << ".";
300
301 styled_widget* control = dynamic_cast<styled_widget*>(mouse_focus_);
302 if(!control || control->get_active()) {
304 }
305
307
308 mouse_focus_ = nullptr;
309
311}
312
314{
315 assert(widget);
316
317#ifdef SDL_PLATFORM_IOS
318 // Guessing a crash location in a nasty stack in gui2::execute_timer.
319 // Either this or a long-touch menu.
320 // Remove this when the crash in gui2::execute_timer() and gui2::timer_callback() is gone and try again.
321 return;
322#endif
323
325
327 return;
328 }
329
330 DBG_GUI_E << LOG_HEADER << "Start hover timer for widget '" << widget->id()
331 << "' at address " << widget << ".";
332
333 using namespace std::chrono_literals;
334 hover_timer_ = add_timer(50ms, std::bind(&mouse_motion::show_tooltip, this));
335
336 if(hover_timer_) {
338 hover_position_ = coordinate;
339 } else {
340 ERR_GUI_E << LOG_HEADER << "Failed to add hover timer.";
341 }
342}
343
345{
346 if(hover_timer_) {
347 assert(hover_widget_);
348 DBG_GUI_E << LOG_HEADER << "Stop hover timer for widget '"
349 << hover_widget_->id() << "' at address " << hover_widget_
350 << ".";
351
353 ERR_GUI_E << LOG_HEADER << "Failed to remove hover timer.";
354 }
355
356 hover_timer_ = 0;
357 hover_widget_ = nullptr;
359 }
360}
361
362/***** ***** ***** ***** mouse_button ***** ***** ***** ***** *****/
363
364#undef LOG_HEADER
365#define LOG_HEADER "distributor mouse button " << I << " [" << owner_.id() << "]: "
366
367namespace
368{
369struct data_pod
370{
377};
378
379constexpr std::array mouse_data{
380 data_pod{
387 },
388 data_pod{
395 },
396 data_pod{
403 },
404 data_pod{
411 },
412 data_pod{
419 },
420};
421
422} // namespace
423
424template<std::size_t I>
426 : mouse_motion(owner, queue_position)
427 , last_click_stamp_()
428 , last_clicked_widget_(nullptr)
429 , focus_(nullptr)
430 , is_down_(false)
431 , signal_handler_sdl_button_down_entered_(false)
432 , signal_handler_sdl_button_up_entered_(false)
433{
434 static_assert(I < mouse_data.size(), "Out-of-bounds mouse_button template index");
435
436 owner_.connect_signal<mouse_data[I].sdl_button_down_event>(
438 this,
439 std::placeholders::_2,
440 std::placeholders::_3,
441 std::placeholders::_5),
442 queue_position);
443
444 owner_.connect_signal<mouse_data[I].sdl_button_up_event>(
446 this,
447 std::placeholders::_2,
448 std::placeholders::_3,
449 std::placeholders::_5),
450 queue_position);
451}
452
453template<std::size_t I>
454void mouse_button<I>::initialize_state(int32_t button_state)
455{
456 last_click_stamp_ = {};
457 last_clicked_widget_ = nullptr;
458 focus_ = nullptr;
459 // SDL_BUTTON_LEFT, SDL_BUTTON_MIDDLE, and SDL_BUTTON_RIGHT correspond to 1,2,3
460 is_down_ = button_state & SDL_BUTTON_MASK(I + 1);
461}
462
463template<std::size_t I>
465 const event::ui_event event, bool& handled, const point& coordinate)
466{
467 if(signal_handler_sdl_button_down_entered_) {
468 return;
469 }
470 resource_locker lock{signal_handler_sdl_button_down_entered_};
471
472 DBG_GUI_E << LOG_HEADER << event << ".";
473
474 if(is_down_) {
475#ifdef GUI2_SHOW_UNHANDLED_EVENT_WARNINGS
476 WRN_GUI_E << LOG_HEADER << event << ". The mouse button is already down, we missed an event.";
477#endif
478 return;
479 }
480 is_down_ = true;
481
482 if(mouse_captured_) {
483 assert(mouse_focus_);
484 focus_ = mouse_focus_;
485 DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].sdl_button_down_event << ".";
486 if(!owner_.fire(mouse_data[I].sdl_button_down_event, *focus_, coordinate)) {
487 DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_down_event << ".";
488 owner_.fire(mouse_data[I].button_down_event, *mouse_focus_);
489 }
490 } else {
491 widget* mouse_over = owner_.find_at(coordinate, true);
492 if(!mouse_over) {
493 return;
494 }
495
496 if(mouse_over != mouse_focus_) {
497#ifdef GUI2_SHOW_UNHANDLED_EVENT_WARNINGS
498 WRN_GUI_E << LOG_HEADER << ". Mouse down on non focused widget "
499 << "and mouse not captured, we missed events.";
500#endif
501 mouse_focus_ = mouse_over;
502 }
503
504 focus_ = mouse_over;
505 DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].sdl_button_down_event << ".";
506 if(!owner_.fire(mouse_data[I].sdl_button_down_event, *focus_, coordinate)) {
507 DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_down_event << ".";
508 owner_.fire(mouse_data[I].button_down_event, *focus_);
509 }
510 }
511 handled = true;
512}
513
514template<std::size_t I>
516 const event::ui_event event, bool& handled, const point& coordinate)
517{
518 if(signal_handler_sdl_button_up_entered_) {
519 return;
520 }
521 resource_locker lock{signal_handler_sdl_button_up_entered_};
522
523 DBG_GUI_E << LOG_HEADER << event << ".";
524
525 if(!is_down_) {
526#ifdef GUI2_SHOW_UNHANDLED_EVENT_WARNINGS
527 WRN_GUI_E << LOG_HEADER << event << ". The mouse button is already up, we missed an event.";
528#endif
529 return;
530 }
531 is_down_ = false;
532
533 if(focus_) {
534 DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].sdl_button_up_event << ".";
535 if(!owner_.fire(mouse_data[I].sdl_button_up_event, *focus_, coordinate)) {
536 DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_up_event << ".";
537 owner_.fire(mouse_data[I].button_up_event, *focus_);
538 }
539 }
540
541 // FIXME: The block below is strange diamond inheritance - it's code that could be in
542 // mouse_motion which applies to all three buttons, but it will be run in one of the
543 // three mouse_button<T> subclasses, and then the other two mouse_button<T> subclasses
544 // will reach here with mouse_captured_ == false.
545 widget* mouse_over = owner_.find_at(coordinate, true);
546 if(mouse_captured_) {
547 const unsigned mask
548 = SDL_BUTTON_LMASK | SDL_BUTTON_MMASK | SDL_BUTTON_RMASK | SDL_BUTTON_X1MASK | SDL_BUTTON_X2MASK;
549
550 if((sdl::get_mouse_button_mask() & mask) == 0) {
551 mouse_captured_ = false;
552 }
553
554 if(mouse_focus_ == mouse_over) {
555 mouse_button_click(mouse_focus_);
556 } else if(!mouse_captured_) {
557 mouse_leave();
558
559 if(mouse_over) {
560 mouse_enter(mouse_over);
561 }
562 }
563 } else if(focus_ && focus_ == mouse_over) {
564 mouse_button_click(focus_);
565 }
566
567 focus_ = nullptr;
568 handled = true;
569}
570
571template<std::size_t I>
573{
574 auto stamp = std::chrono::steady_clock::now();
575 if(last_click_stamp_ + settings::double_click_time >= stamp && last_clicked_widget_ == widget) {
576 DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_double_click_event << ".";
577
578 owner_.fire(mouse_data[I].button_double_click_event, *widget);
579 last_click_stamp_ = {};
580 last_clicked_widget_ = nullptr;
581
582 } else {
583 DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_click_event << ".";
584 owner_.fire(mouse_data[I].button_click_event, *widget);
585 last_click_stamp_ = stamp;
586 last_clicked_widget_ = widget;
587 }
588}
589
590/***** ***** ***** ***** distributor ***** ***** ***** ***** *****/
591
592#undef LOG_HEADER
593#define LOG_HEADER "distributor mouse motion [" << owner_.id() << "]: "
594
595/**
596 * @todo Test whether the state is properly tracked when an input blocker is
597 * used.
598 */
600 : mouse_motion(owner, queue_position)
601 , mouse_button_left(owner, queue_position)
602 , mouse_button_middle(owner, queue_position)
603 , mouse_button_right(owner, queue_position)
604 , mouse_button_back(owner, queue_position)
605 , mouse_button_forward(owner, queue_position)
606 , keyboard_focus_(nullptr)
607 , keyboard_focus_chain_()
608{
611 this,
612 std::placeholders::_5,
613 std::placeholders::_6,
614 std::placeholders::_7
615 ));
616
619 this,
620 std::placeholders::_5,
621 std::placeholders::_6,
622 std::placeholders::_7
623 ));
624
627 this,
628 std::placeholders::_5,
629 std::placeholders::_6,
630 std::placeholders::_7
631 ));
632
635 this,
636 std::placeholders::_1,
637 std::placeholders::_2
638 ));
639
641}
642
644{
647 this,
648 std::placeholders::_5,
649 std::placeholders::_6,
650 std::placeholders::_7
651 ));
652
655 this,
656 std::placeholders::_5,
657 std::placeholders::_6,
658 std::placeholders::_7
659 ));
660
663 this,
664 std::placeholders::_5,
665 std::placeholders::_6,
666 std::placeholders::_7
667 ));
668
671 this,
672 std::placeholders::_1,
673 std::placeholders::_2
674 ));
675}
676
689
694
709
716
718{
719 assert(w);
720 auto itor = std::find(keyboard_focus_chain_.begin(), keyboard_focus_chain_.end(), w);
721
722 if(itor != keyboard_focus_chain_.end()) {
723 keyboard_focus_chain_.erase(itor);
724 }
725}
726
727template<typename Fcn, typename P1, typename P2, typename P3>
729{
730 /** @todo Test whether recursion protection is needed. */
731
732 DBG_GUI_E << LOG_HEADER << evt << ".";
733
734 if(keyboard_focus_) {
735 // Attempt to cast to styled_widget, to avoid sending events if the
736 // widget is disabled. If the cast fails, we assume the widget
737 // is enabled and ready to receive events.
738 styled_widget* control = dynamic_cast<styled_widget*>(keyboard_focus_);
739 if(!control || control->get_active()) {
740 DBG_GUI_E << LOG_HEADER << "Firing: " << evt << ".";
741 if(owner_.fire(evt, *keyboard_focus_, p1, p2, p3)) {
742 return;
743 }
744 }
745
746 if(text_box_base* tb = dynamic_cast<text_box_base*>(keyboard_focus_)) {
747 if(tb->is_composing()) {
748 return; // Skip the keyboard chain if composition is in progress.
749 }
750 }
751 }
752
753 for(auto ritor = keyboard_focus_chain_.rbegin(); ritor != keyboard_focus_chain_.rend(); ++ritor) {
754 if(*ritor == keyboard_focus_) {
755 continue;
756 }
757
758 if(*ritor == &owner_) {
759 /**
760 * @todo Make sure we're not in the event chain.
761 *
762 * No idea why we're here, but needs to be fixed, otherwise we keep
763 * calling this function recursively upon unhandled events...
764 *
765 * Probably added to make sure the window can grab the events and
766 * handle + block them when needed, this is no longer needed with
767 * the chain.
768 */
769 continue;
770 }
771
772 // Attempt to cast to styled_widget, to avoid sending events if the
773 // widget is disabled. If the cast fails, we assume the widget
774 // is enabled and ready to receive events.
775 styled_widget* control = dynamic_cast<styled_widget*>(keyboard_focus_);
776 if(control != nullptr && !control->get_active()) {
777 continue;
778 }
779
780 DBG_GUI_E << LOG_HEADER << "Firing: " << evt << ".";
781 if(owner_.fire(evt, **ritor, p1, p2, p3)) {
782 return;
783 }
784 }
785}
786
787void distributor::signal_handler_sdl_key_down(const SDL_Keycode key, const SDL_Keymod modifier, const std::string& unicode)
788{
789 signal_handler_keyboard_internal<signal_keyboard>(event::SDL_KEY_DOWN, key, modifier, unicode);
790}
791
792void distributor::signal_handler_sdl_text_input(const std::string& unicode, int32_t start, int32_t end)
793{
794 signal_handler_keyboard_internal<signal_text_input>(event::SDL_TEXT_INPUT, unicode, start, end);
795}
796
797void distributor::signal_handler_sdl_text_editing(const std::string& unicode, int32_t start, int32_t end)
798{
799 signal_handler_keyboard_internal<signal_text_input>(event::SDL_TEXT_EDITING, unicode, start, end);
800}
801
803{
804 DBG_GUI_E << LOG_HEADER << event << ".";
805
806 /**
807 * @todo Evaluate whether moving the cleanup parts in the subclasses.
808 *
809 * It might be cleaner to do it that way, but creates extra small
810 * functions...
811 */
812
813 if(hover_widget_ == &w) {
815 }
816
819 }
822 }
823
826 }
829 }
830
833 }
836 }
837
840 }
843 }
844
847 }
850 }
851
852 if(mouse_focus_ == &w) {
853 mouse_focus_ = nullptr;
854 }
855
856 if(keyboard_focus_ == &w) {
857 keyboard_focus_ = nullptr;
858 }
859
860 const auto itor = std::find(keyboard_focus_chain_.begin(), keyboard_focus_chain_.end(), &w);
861 if(itor != keyboard_focus_chain_.end()) {
862 keyboard_focus_chain_.erase(itor);
863 }
864}
865
866} // namespace gui2::event
Base class for event handling.
void connect_signal(const F &func, const queue_position position=back_child)
Adds a callback to the appropriate queue based on event type.
queue_position
The position where to add a new callback in the signal handler.
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
void disconnect_signal(const F &func, const queue_position position=back_child)
Removes a callback from the appropriate queue based on event type.
widget * keyboard_focus_
The widget that holds the keyboard focus_.
void keyboard_add_to_chain(widget *widget)
Adds the widget to the keyboard chain.
void keyboard_capture(widget *widget)
Captures the keyboard input.
std::vector< widget * > keyboard_focus_chain_
Fall back keyboard focus_ items.
void signal_handler_keyboard_internal(event::ui_event evt, P1 &&p1, P2 &&p2, P3 &&p3)
void keyboard_remove_from_chain(widget *widget)
Remove the widget from the keyboard chain.
void signal_handler_sdl_text_editing(const std::string &unicode, int32_t start, int32_t len)
void signal_handler_sdl_key_down(const SDL_Keycode key, const SDL_Keymod modifier, const std::string &unicode)
Set of functions that handle certain events and sends them to the proper widget.
void initialize_state()
Initializes the state of the keyboard and mouse.
distributor(widget &owner, const dispatcher::queue_position queue_position)
widget * keyboard_focus() const
Return the widget currently capturing keyboard input.
void signal_handler_notify_removal(dispatcher &widget, const ui_event event)
void signal_handler_sdl_text_input(const std::string &unicode, int32_t start, int32_t len)
void signal_handler_sdl_button_down(const event::ui_event event, bool &handled, const point &coordinate)
widget * last_clicked_widget_
The widget the last click was on, used for double clicking.
mouse_button(widget &owner, const dispatcher::queue_position queue_position)
void initialize_state(int32_t button_state)
Initializes the state of the button.
void mouse_button_click(widget *widget)
void signal_handler_sdl_button_up(const event::ui_event event, bool &handled, const point &coordinate)
widget * focus_
If the mouse isn't captured we need to verify the up is on the same widget as the down so we send a p...
bool mouse_captured_
Did the current widget capture the focus_?
void mouse_hover(widget *mouse_over, const point &coordinate)
Called when the mouse moves over a widget.
widget * hover_widget_
The widget which should get the hover event.
void signal_handler_sdl_mouse_motion(const event::ui_event event, bool &handled, const point &coordinate)
mouse_motion(widget &owner, const dispatcher::queue_position queue_position)
void mouse_enter(widget *mouse_over)
Called when the mouse enters a widget.
bool hover_shown_
Has the hover been shown for the widget?
void signal_handler_sdl_touch_motion(const event::ui_event event, bool &handled, const point &coordinate, const point &distance)
void capture_mouse(const bool capture=true)
Captures the mouse input.
void signal_handler_show_helptip(const event::ui_event event, bool &handled, const point &coordinate)
void mouse_leave()
Called when the mouse leaves the current widget.
void signal_handler_sdl_wheel(const event::ui_event event, bool &handled, const point &coordinate)
point hover_position_
The anchor point of the hover event.
void stop_hover_timer()
Stops the current hover timer.
void start_hover_timer(widget *widget, const point &coordinate)
Starts the hover timer.
std::size_t hover_timer_
The timer for the hover event.
widget * mouse_focus_
The widget that currently has the mouse focus_.
widget & owner_
The widget that owns us.
void show_tooltip()
Called when the mouse wants the widget to show its tooltip.
Small helper to keep a resource (boolean) locked.
bool wants_mouse_hover() const
virtual bool get_active() const =0
Gets the active state of the styled_widget.
Abstract base class for text items.
Base class for all widgets.
Definition widget.hpp:55
virtual bool can_mouse_focus() const
Whether the mouse move/click event go 'through' this widget.
Definition widget.hpp:334
const std::string & id() const
Definition widget.cpp:110
virtual widget * find_at(const point &coordinate, const bool must_be_active)
Returns the widget at the wanted coordinates.
Definition widget.cpp:549
widget * parent()
Definition widget.cpp:170
const ui_event button_click_event
const ui_event button_double_click_event
#define LOG_HEADER
const ui_event sdl_button_up_event
const ui_event button_up_event
const ui_event sdl_button_down_event
const ui_event button_down_event
Contains the event distributor.
Define the common log macros for the gui toolkit.
#define WRN_GUI_E
Definition log.hpp:37
#define ERR_GUI_E
Definition log.hpp:38
#define DBG_GUI_E
Definition log.hpp:35
Contains functions for cleanly handling SDL input.
ui_event
The event sent to the dispatcher.
Definition handler.hpp:115
@ MIDDLE_BUTTON_DOWN
Definition handler.hpp:124
@ SDL_FORWARD_BUTTON_DOWN
Definition handler.hpp:156
@ NOTIFY_REMOVE_TOOLTIP
Definition handler.hpp:176
@ FORWARD_BUTTON_DOUBLE_CLICK
Definition handler.hpp:141
@ FORWARD_BUTTON_CLICK
Definition handler.hpp:140
@ SDL_RIGHT_BUTTON_DOWN
Definition handler.hpp:150
@ MIDDLE_BUTTON_DOUBLE_CLICK
Definition handler.hpp:127
@ FORWARD_BUTTON_DOWN
Definition handler.hpp:138
@ BACK_BUTTON_CLICK
Definition handler.hpp:136
@ MIDDLE_BUTTON_CLICK
Definition handler.hpp:126
@ SDL_LEFT_BUTTON_DOWN
Definition handler.hpp:146
@ SDL_TEXT_INPUT
An SDL text input (commit) event.
Definition handler.hpp:170
@ RIGHT_BUTTON_CLICK
Definition handler.hpp:130
@ LOSE_KEYBOARD_FOCUS
Definition handler.hpp:178
@ SDL_TEXT_EDITING
An SDL text editing (IME) event.
Definition handler.hpp:171
@ LEFT_BUTTON_DOUBLE_CLICK
Definition handler.hpp:123
@ RIGHT_BUTTON_DOWN
Definition handler.hpp:128
@ RECEIVE_KEYBOARD_FOCUS
Definition handler.hpp:177
@ BACK_BUTTON_DOUBLE_CLICK
Definition handler.hpp:137
@ LEFT_BUTTON_CLICK
Definition handler.hpp:122
@ SDL_LEFT_BUTTON_UP
Definition handler.hpp:147
@ SDL_MIDDLE_BUTTON_UP
Definition handler.hpp:149
@ SDL_BACK_BUTTON_DOWN
Definition handler.hpp:154
@ SDL_BACK_BUTTON_UP
Definition handler.hpp:155
@ FORWARD_BUTTON_UP
Definition handler.hpp:139
@ SDL_MIDDLE_BUTTON_DOWN
Definition handler.hpp:148
@ SDL_RIGHT_BUTTON_UP
Definition handler.hpp:151
@ RIGHT_BUTTON_DOUBLE_CLICK
Definition handler.hpp:131
@ SDL_FORWARD_BUTTON_UP
Definition handler.hpp:157
void init_mouse_location()
Initializes the location of the mouse.
Definition handler.cpp:891
std::chrono::milliseconds double_click_time
The interval between two clicks to be detected as double click.
Definition settings.cpp:44
std::size_t add_timer(const std::chrono::milliseconds &interval, const std::function< void(std::size_t id)> &callback, const bool repeat)
Adds a new timer.
Definition timer.cpp:123
point get_mouse_position()
Returns the current mouse position.
Definition helper.cpp:167
bool remove_timer(const std::size_t id)
Removes a timer.
Definition timer.cpp:164
uint32_t get_mouse_button_mask()
Returns the current mouse button mask.
Definition input.cpp:44
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
Definition general.hpp:88
int w
Definition pathfind.cpp:188
This file contains the settings handling of the widget library.
Holds a 2D point.
Definition point.hpp:25
Contains the gui2 timer routines.