The Battle for Wesnoth  1.17.10+dev
distributor.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2022
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 "events.hpp"
21 #include "gui/core/log.hpp"
22 #include "gui/core/timer.hpp"
23 #include "gui/widgets/settings.hpp"
25 #include "gui/widgets/widget.hpp"
26 #include "gui/widgets/window.hpp"
27 #include "sdl/userevent.hpp"
28 #include "sdl/input.hpp" // get_mouse_button_mask
29 
30 #include <array>
31 #include <functional>
32 
33 namespace gui2::event
34 {
35 /**
36  * Small helper to keep a resource (boolean) locked.
37  *
38  * Some of the event handling routines can't be called recursively, this due to
39  * the fact that they are attached to the pre queue and when the forward an
40  * event the pre queue event gets triggered recursively causing infinite
41  * recursion.
42  *
43  * To prevent that those functions check the lock and exit when the lock is
44  * held otherwise grab the lock here.
45  */
47 {
48 public:
49  resource_locker(bool& locked) : locked_(locked)
50  {
51  assert(!locked_);
52  locked_ = true;
53  }
54 
56  {
57  assert(locked_);
58  locked_ = false;
59  }
60 
61 private:
62  bool& locked_;
63 };
64 
65 
66 /***** ***** ***** ***** mouse_motion ***** ***** ***** ***** *****/
67 
68 #define LOG_HEADER "distributor mouse motion [" << owner_.id() << "]: "
69 
71  : mouse_focus_(nullptr)
72  , mouse_captured_(false)
73  , owner_(owner)
74  , hover_timer_(0)
75  , hover_widget_(nullptr)
76  , hover_position_(0, 0)
77  , hover_shown_(true)
78  , signal_handler_sdl_mouse_motion_entered_(false)
79 {
82  this,
83  std::placeholders::_2,
84  std::placeholders::_3,
85  std::placeholders::_5),
86  queue_position);
87 
90  this,
91  std::placeholders::_2,
92  std::placeholders::_3,
93  std::placeholders::_5,
94  std::placeholders::_6),
95  queue_position);
96 
99  this,
100  std::placeholders::_2,
101  std::placeholders::_3,
102  std::placeholders::_5
103  ));
104 
107  this,
108  std::placeholders::_2,
109  std::placeholders::_3,
110  std::placeholders::_5
111  ));
112 
115  this,
116  std::placeholders::_2,
117  std::placeholders::_3,
118  std::placeholders::_5
119  ));
120 
123  this,
124  std::placeholders::_2,
125  std::placeholders::_3,
126  std::placeholders::_5
127  ));
128 
131  this,
132  std::placeholders::_2,
133  std::placeholders::_3,
134  std::placeholders::_5),
135  queue_position);
136 }
137 
139 {
141 }
142 
143 void mouse_motion::capture_mouse(const bool capture)
144 {
145  assert(mouse_focus_);
146  mouse_captured_ = capture;
147 }
148 
150 {
152  return;
153  }
155 
156  DBG_GUI_E << LOG_HEADER << event << ".";
157 
158  if(mouse_captured_) {
159  assert(mouse_focus_);
160  if(!owner_.fire(event, *mouse_focus_, coordinate)) {
161  mouse_hover(mouse_focus_, coordinate);
162  }
163  } else {
164  widget* mouse_over = owner_.find_at(coordinate, true);
165  while(mouse_over && !mouse_over->can_mouse_focus() && mouse_over->parent()) {
166  mouse_over = mouse_over->parent();
167  }
168 
169  if(mouse_over) {
170  DBG_GUI_E << LOG_HEADER << "Firing: " << event << ".";
171  if(owner_.fire(event, *mouse_over, coordinate)) {
172  return;
173  }
174  }
175 
176  if(!mouse_focus_ && mouse_over) {
177  mouse_enter(mouse_over);
178  } else if(mouse_focus_ && !mouse_over) {
179  mouse_leave();
180  } else if(mouse_focus_ && mouse_focus_ == mouse_over) {
181  mouse_hover(mouse_over, coordinate);
182  } else if(mouse_focus_ && mouse_over) {
183  // moved from one widget to the next
184  mouse_leave();
185  mouse_enter(mouse_over);
186  } else {
187  assert(!mouse_focus_ && !mouse_over);
188  }
189  }
190  handled = true;
191 }
192 
194  const event::ui_event event, bool& handled, const point& coordinate, const point& distance)
195 {
196  DBG_GUI_E << LOG_HEADER << event << ".";
197 
198  if(mouse_captured_) {
199  assert(mouse_focus_);
200  owner_.fire(event, *mouse_focus_, coordinate, distance);
201  } else {
202  if(widget* mouse_over = owner_.find_at(coordinate, true)) {
203  owner_.fire(event, *mouse_over, coordinate, distance);
204  }
205  }
206  handled = true;
207 }
208 
210 {
211  DBG_GUI_E << LOG_HEADER << event << ".";
212 
213  if(mouse_captured_) {
214  assert(mouse_focus_);
215  owner_.fire(event, *mouse_focus_, coordinate);
216  } else {
217  if(widget* mouse_over = owner_.find_at(coordinate, true)) {
218  owner_.fire(event, *mouse_over, coordinate);
219  }
220  }
221  handled = true;
222 }
223 
225 {
226  DBG_GUI_E << LOG_HEADER << event << ".";
227 
228  if(mouse_captured_) {
229  assert(mouse_focus_);
230  if(owner_.fire(event, *mouse_focus_, coordinate)) {
232  }
233  } else {
234  if(widget* mouse_over = owner_.find_at(coordinate, true)) {
235  DBG_GUI_E << LOG_HEADER << "Firing: " << event << ".";
236  if(owner_.fire(event, *mouse_over, coordinate)) {
238  }
239  }
240  }
241 
242  handled = true;
243 }
244 
246 {
247  DBG_GUI_E << LOG_HEADER << "Firing: " << event::MOUSE_ENTER << ".";
248 
249  assert(mouse_over);
250 
251  mouse_focus_ = mouse_over;
252  owner_.fire(event::MOUSE_ENTER, *mouse_over);
253 
254  hover_shown_ = false;
255  start_hover_timer(mouse_over, get_mouse_position());
256 }
257 
259 {
260  DBG_GUI_E << LOG_HEADER << "Firing: " << event::MOUSE_MOTION << ".";
261 
262  assert(mouse_over);
263 
264  owner_.fire(event::MOUSE_MOTION, *mouse_over, coordinate);
265 
266  if(hover_timer_) {
267  if((std::abs(hover_position_.x - coordinate.x) > 5) || (std::abs(hover_position_.y - coordinate.y) > 5)) {
269  start_hover_timer(mouse_over, coordinate);
270  }
271  }
272 }
273 
275 {
276  DBG_GUI_E << LOG_HEADER << "Firing: " << event::SHOW_TOOLTIP << ".";
277 
278  if(!hover_widget_) {
279  // See mouse_motion::stop_hover_timer.
280  ERR_GUI_E << LOG_HEADER << event::SHOW_TOOLTIP << " bailing out, no hover widget.";
281  return;
282  }
283 
284  /*
285  * Ignore the result of the event, always mark the tooltip as shown. If
286  * there was no handler, there is no reason to assume there will be one
287  * next time.
288  */
290 
291  hover_shown_ = true;
292 
293  hover_timer_ = 0;
294  hover_widget_ = nullptr;
296 }
297 
299 {
300  DBG_GUI_E << LOG_HEADER << "Firing: " << event::MOUSE_LEAVE << ".";
301 
302  styled_widget* control = dynamic_cast<styled_widget*>(mouse_focus_);
303  if(!control || control->get_active()) {
304  owner_.fire(event::MOUSE_LEAVE, *mouse_focus_);
305  }
306 
308 
309  mouse_focus_ = nullptr;
310 
312 }
313 
315 {
316  assert(widget);
317 
318 #ifdef __IPHONEOS__
319  // Guessing a crash location in a nasty stack in gui2::execute_timer.
320  // Either this or a long-touch menu.
321  // Remove this when the crash in gui2::execute_timer() and gui2::timer_callback() is gone and try again.
322  return;
323 #endif
324 
326 
327  if(hover_shown_ || !widget->wants_mouse_hover()) {
328  return;
329  }
330 
331  DBG_GUI_E << LOG_HEADER << "Start hover timer for widget '" << widget->id()
332  << "' at address " << widget << ".";
333 
334  hover_timer_ = add_timer(50, std::bind(&mouse_motion::show_tooltip, this));
335 
336  if(hover_timer_) {
337  hover_widget_ = widget;
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 
352  if(!remove_timer(hover_timer_)) {
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 
367 namespace
368 {
369 struct data_pod
370 {
377 };
378 
379 constexpr std::array mouse_data{
380  data_pod{
387  },
388  data_pod{
395  },
396  data_pod{
403  },
404 };
405 
406 } // namespace
407 
408 template<std::size_t I>
410  : mouse_motion(owner, queue_position)
411  , last_click_stamp_(0)
412  , last_clicked_widget_(nullptr)
413  , focus_(nullptr)
414  , is_down_(false)
415  , signal_handler_sdl_button_down_entered_(false)
416  , signal_handler_sdl_button_up_entered_(false)
417 {
418  static_assert(I < mouse_data.size(), "Out-of-bounds mouse_button template index");
419 
420  owner_.connect_signal<mouse_data[I].sdl_button_down_event>(
422  this,
423  std::placeholders::_2,
424  std::placeholders::_3,
425  std::placeholders::_5),
426  queue_position);
427 
428  owner_.connect_signal<mouse_data[I].sdl_button_up_event>(
430  this,
431  std::placeholders::_2,
432  std::placeholders::_3,
433  std::placeholders::_5),
434  queue_position);
435 }
436 
437 template<std::size_t I>
438 void mouse_button<I>::initialize_state(int32_t button_state)
439 {
440  last_click_stamp_ = 0;
441  last_clicked_widget_ = nullptr;
442  focus_ = 0;
443  // SDL_BUTTON_LEFT, SDL_BUTTON_MIDDLE, and SDL_BUTTON_RIGHT correspond to 1,2,3
444  is_down_ = button_state & SDL_BUTTON(I + 1);
445 }
446 
447 template<std::size_t I>
449  const event::ui_event event, bool& handled, const point& coordinate)
450 {
452  return;
453  }
455 
456  DBG_GUI_E << LOG_HEADER << event << ".";
457 
458  if(is_down_) {
459 #ifdef GUI2_SHOW_UNHANDLED_EVENT_WARNINGS
460  WRN_GUI_E << LOG_HEADER << event << ". The mouse button is already down, we missed an event.";
461 #endif
462  return;
463  }
464  is_down_ = true;
465 
466  if(mouse_captured_) {
467  assert(mouse_focus_);
469  DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].sdl_button_down_event << ".";
470  if(!owner_.fire(mouse_data[I].sdl_button_down_event, *focus_, coordinate)) {
471  DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_down_event << ".";
472  owner_.fire(mouse_data[I].button_down_event, *mouse_focus_);
473  }
474  } else {
475  widget* mouse_over = owner_.find_at(coordinate, true);
476  if(!mouse_over) {
477  return;
478  }
479 
480  if(mouse_over != mouse_focus_) {
481 #ifdef GUI2_SHOW_UNHANDLED_EVENT_WARNINGS
482  WRN_GUI_E << LOG_HEADER << ". Mouse down on non focused widget "
483  << "and mouse not captured, we missed events.";
484 #endif
485  mouse_focus_ = mouse_over;
486  }
487 
488  focus_ = mouse_over;
489  DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].sdl_button_down_event << ".";
490  if(!owner_.fire(mouse_data[I].sdl_button_down_event, *focus_, coordinate)) {
491  DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_down_event << ".";
492  owner_.fire(mouse_data[I].button_down_event, *focus_);
493  }
494  }
495  handled = true;
496 }
497 
498 template<std::size_t I>
500  const event::ui_event event, bool& handled, const point& coordinate)
501 {
503  return;
504  }
506 
507  DBG_GUI_E << LOG_HEADER << event << ".";
508 
509  if(!is_down_) {
510 #ifdef GUI2_SHOW_UNHANDLED_EVENT_WARNINGS
511  WRN_GUI_E << LOG_HEADER << event << ". The mouse button is already up, we missed an event.";
512 #endif
513  return;
514  }
515  is_down_ = false;
516 
517  if(focus_) {
518  DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].sdl_button_up_event << ".";
519  if(!owner_.fire(mouse_data[I].sdl_button_up_event, *focus_, coordinate)) {
520  DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_up_event << ".";
521  owner_.fire(mouse_data[I].button_up_event, *focus_);
522  }
523  }
524 
525  // FIXME: The block below is strange diamond inheritance - it's code that could be in
526  // mouse_motion which applies to all three buttons, but it will be run in one of the
527  // three mouse_button<T> subclasses, and then the other two mouse_button<T> subclasses
528  // will reach here with mouse_captured_ == false.
529  widget* mouse_over = owner_.find_at(coordinate, true);
530  if(mouse_captured_) {
531  const unsigned mask = SDL_BUTTON_LMASK | SDL_BUTTON_MMASK | SDL_BUTTON_RMASK;
532 
533  if((sdl::get_mouse_button_mask() & mask) == 0) {
534  mouse_captured_ = false;
535  }
536 
537  if(mouse_focus_ == mouse_over) {
539  } else if(!mouse_captured_) {
540  mouse_leave();
541 
542  if(mouse_over) {
543  mouse_enter(mouse_over);
544  }
545  }
546  } else if(focus_ && focus_ == mouse_over) {
548  }
549 
550  focus_ = nullptr;
551  handled = true;
552 }
553 
554 template<std::size_t I>
556 {
557  uint32_t stamp = SDL_GetTicks();
559  DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_double_click_event << ".";
560 
561  owner_.fire(mouse_data[I].button_double_click_event, *widget);
562  last_click_stamp_ = 0;
563  last_clicked_widget_ = nullptr;
564 
565  } else {
566  DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_click_event << ".";
567  owner_.fire(mouse_data[I].button_click_event, *widget);
568  last_click_stamp_ = stamp;
569  last_clicked_widget_ = widget;
570  }
571 }
572 
573 /***** ***** ***** ***** distributor ***** ***** ***** ***** *****/
574 
575 #undef LOG_HEADER
576 #define LOG_HEADER "distributor mouse motion [" << owner_.id() << "]: "
577 
578 /**
579  * @todo Test whether the state is properly tracked when an input blocker is
580  * used.
581  */
583  : mouse_motion(owner, queue_position)
584  , mouse_button_left(owner, queue_position)
585  , mouse_button_middle(owner, queue_position)
586  , mouse_button_right(owner, queue_position)
587  , keyboard_focus_(nullptr)
588  , keyboard_focus_chain_()
589 {
590  if(SDL_WasInit(SDL_INIT_TIMER) == 0) {
591  if(SDL_InitSubSystem(SDL_INIT_TIMER) == -1) {
592  assert(false);
593  }
594  }
595 
598  this,
599  std::placeholders::_5,
600  std::placeholders::_6,
601  std::placeholders::_7
602  ));
603 
606  this,
607  std::placeholders::_5,
608  std::placeholders::_6,
609  std::placeholders::_7
610  ));
611 
614  this,
615  std::placeholders::_5,
616  std::placeholders::_6,
617  std::placeholders::_7
618  ));
619 
622  this,
623  std::placeholders::_1,
624  std::placeholders::_2
625  ));
626 
628 }
629 
631 {
634  this,
635  std::placeholders::_5,
636  std::placeholders::_6,
637  std::placeholders::_7
638  ));
639 
642  this,
643  std::placeholders::_5,
644  std::placeholders::_6,
645  std::placeholders::_7
646  ));
647 
650  this,
651  std::placeholders::_5,
652  std::placeholders::_6,
653  std::placeholders::_7
654  ));
655 
658  this,
659  std::placeholders::_1,
660  std::placeholders::_2
661  ));
662 }
663 
665 {
666  const uint32_t button_state = sdl::get_mouse_button_mask();
667 
671 
673 }
674 
676 {
677  return keyboard_focus_;
678 }
679 
681 {
682  if(keyboard_focus_) {
683  DBG_GUI_E << LOG_HEADER << "Firing: " << event::LOSE_KEYBOARD_FOCUS << ".";
684  owner_.fire(event::LOSE_KEYBOARD_FOCUS, *keyboard_focus_, nullptr);
685  }
686 
687  keyboard_focus_ = widget;
688 
689  if(keyboard_focus_) {
690  DBG_GUI_E << LOG_HEADER << "Firing: " << event::RECEIVE_KEYBOARD_FOCUS << ".";
691  owner_.fire(event::RECEIVE_KEYBOARD_FOCUS, *keyboard_focus_, nullptr);
692  }
693 }
694 
696 {
697  assert(widget);
698  assert(std::find(keyboard_focus_chain_.begin(), keyboard_focus_chain_.end(), widget) == keyboard_focus_chain_.end());
699  keyboard_focus_chain_.push_back(widget);
700 }
701 
703 {
704  assert(w);
705  auto itor = std::find(keyboard_focus_chain_.begin(), keyboard_focus_chain_.end(), w);
706 
707  if(itor != keyboard_focus_chain_.end()) {
708  keyboard_focus_chain_.erase(itor);
709  }
710 }
711 
712 template<typename Fcn, typename P1, typename P2, typename P3>
714 {
715  /** @todo Test whether recursion protection is needed. */
716 
717  DBG_GUI_E << LOG_HEADER << evt << ".";
718 
719  if(keyboard_focus_) {
720  // Attempt to cast to styled_widget, to avoid sending events if the
721  // widget is disabled. If the cast fails, we assume the widget
722  // is enabled and ready to receive events.
723  styled_widget* control = dynamic_cast<styled_widget*>(keyboard_focus_);
724  if(!control || control->get_active()) {
725  DBG_GUI_E << LOG_HEADER << "Firing: " << evt << ".";
726  if(owner_.fire(evt, *keyboard_focus_, p1, p2, p3)) {
727  return;
728  }
729  }
730 
731  if(text_box_base* tb = dynamic_cast<text_box_base*>(keyboard_focus_)) {
732  if(tb->is_composing()) {
733  return; // Skip the keyboard chain if composition is in progress.
734  }
735  }
736  }
737 
738  for(auto ritor = keyboard_focus_chain_.rbegin(); ritor != keyboard_focus_chain_.rend(); ++ritor) {
739  if(*ritor == keyboard_focus_) {
740  continue;
741  }
742 
743  if(*ritor == &owner_) {
744  /**
745  * @todo Make sure we're not in the event chain.
746  *
747  * No idea why we're here, but needs to be fixed, otherwise we keep
748  * calling this function recursively upon unhandled events...
749  *
750  * Probably added to make sure the window can grab the events and
751  * handle + block them when needed, this is no longer needed with
752  * the chain.
753  */
754  continue;
755  }
756 
757  // Attempt to cast to styled_widget, to avoid sending events if the
758  // widget is disabled. If the cast fails, we assume the widget
759  // is enabled and ready to receive events.
760  styled_widget* control = dynamic_cast<styled_widget*>(keyboard_focus_);
761  if(control != nullptr && !control->get_active()) {
762  continue;
763  }
764 
765  DBG_GUI_E << LOG_HEADER << "Firing: " << evt << ".";
766  if(owner_.fire(evt, **ritor, p1, p2, p3)) {
767  return;
768  }
769  }
770 }
771 
772 void distributor::signal_handler_sdl_key_down(const SDL_Keycode key, const SDL_Keymod modifier, const std::string& unicode)
773 {
774  signal_handler_keyboard_internal<signal_keyboard>(event::SDL_KEY_DOWN, key, modifier, unicode);
775 }
776 
777 void distributor::signal_handler_sdl_text_input(const std::string& unicode, int32_t start, int32_t end)
778 {
779  signal_handler_keyboard_internal<signal_text_input>(event::SDL_TEXT_INPUT, unicode, start, end);
780 }
781 
782 void distributor::signal_handler_sdl_text_editing(const std::string& unicode, int32_t start, int32_t end)
783 {
784  signal_handler_keyboard_internal<signal_text_input>(event::SDL_TEXT_EDITING, unicode, start, end);
785 }
786 
788 {
789  DBG_GUI_E << LOG_HEADER << event << ".";
790 
791  /**
792  * @todo Evaluate whether moving the cleanup parts in the subclasses.
793  *
794  * It might be cleaner to do it that way, but creates extra small
795  * functions...
796  */
797 
798  if(hover_widget_ == &w) {
800  }
801 
804  }
805  if(mouse_button_left::focus_ == &w) {
806  mouse_button_left::focus_ = nullptr;
807  }
808 
811  }
812  if(mouse_button_middle::focus_ == &w) {
813  mouse_button_middle::focus_ = nullptr;
814  }
815 
818  }
819  if(mouse_button_right::focus_ == &w) {
820  mouse_button_right::focus_ = nullptr;
821  }
822 
823  if(mouse_focus_ == &w) {
824  mouse_focus_ = nullptr;
825  }
826 
827  if(keyboard_focus_ == &w) {
828  keyboard_focus_ = nullptr;
829  }
830 
831  const auto itor = std::find(keyboard_focus_chain_.begin(), keyboard_focus_chain_.end(), &w);
832  if(itor != keyboard_focus_chain_.end()) {
833  keyboard_focus_chain_.erase(itor);
834  }
835 }
836 
837 } // namespace gui2::event
Define the common log macros for the gui toolkit.
#define ERR_GUI_E
Definition: log.hpp:38
bool hover_shown_
Has the hover been shown for the widget?
Definition: distributor.hpp:99
void signal_handler_sdl_touch_motion(const event::ui_event event, bool &handled, const point &coordinate, const point &distance)
Abstract base class for text items.
std::vector< widget * > keyboard_focus_chain_
Fall back keyboard focus_ items.
const ui_event button_down_event
unsigned double_click_time
Definition: settings.cpp:45
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
Base class for event handling.
Definition: dispatcher.hpp:151
void signal_handler_sdl_wheel(const event::ui_event event, bool &handled, const point &coordinate)
virtual bool get_active() const =0
Gets the active state of the styled_widget.
void keyboard_capture(widget *widget)
Captures the keyboard input.
const std::string & id() const
Definition: widget.cpp:111
This file contains the window object, this object is a top level container which has the event manage...
Base class for all widgets.
Definition: widget.hpp:53
An SDL text input (commit) event.
Definition: handler.hpp:153
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.
bool wants_mouse_hover() const
Contains the event distributor.
uint32_t last_click_stamp_
The time of the last click used for double clicking.
Contains functions for cleanly handling SDL input.
void mouse_hover(widget *mouse_over, const point &coordinate)
Called when the mouse moves over a widget.
void init_mouse_location()
Initializes the location of the mouse.
Definition: handler.cpp:880
void signal_handler_show_helptip(const event::ui_event event, bool &handled, const point &coordinate)
void keyboard_add_to_chain(widget *widget)
Adds the widget to the keyboard chain.
const ui_event button_double_click_event
bool is_down_
Is the button down?
distributor(widget &owner, const dispatcher::queue_position queue_position)
Small helper to keep a resource (boolean) locked.
Definition: distributor.cpp:46
const ui_event sdl_button_up_event
An SDL text editing (IME) event.
Definition: handler.hpp:154
void signal_handler_keyboard_internal(event::ui_event evt, P1 &&p1, P2 &&p2, P3 &&p3)
This file contains the settings handling of the widget library.
widget * focus_
If the mouse isn&#39;t captured we need to verify the up is on the same widget as the down so we send a p...
widget & owner_
The widget that owns us.
Definition: distributor.hpp:81
EXIT_STATUS start(const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
Definition: editor_main.cpp:30
void signal_handler_sdl_button_down(const event::ui_event event, bool &handled, const point &coordinate)
widget * keyboard_focus_
The widget that holds the keyboard focus_.
widget * parent()
Definition: widget.cpp:161
void signal_handler_sdl_button_up(const event::ui_event event, bool &handled, const point &coordinate)
void start_hover_timer(widget *widget, const point &coordinate)
Starts the hover timer.
void mouse_button_click(widget *widget)
uint32_t get_mouse_button_mask()
Returns the current mouse button mask.
Definition: input.cpp:49
virtual bool can_mouse_focus() const
Whether the mouse move/click event go &#39;through&#39; this widget.
Definition: widget.hpp:332
point hover_position_
The anchor point of the hover event.
Definition: distributor.hpp:90
void disconnect_signal(const F &func, const queue_position position=back_child)
Removes a callback from the appropriate queue based on event type.
Definition: dispatcher.hpp:372
void signal_handler_notify_removal(dispatcher &widget, const ui_event event)
void mouse_enter(widget *mouse_over)
Called when the mouse enters a widget.
#define DBG_GUI_E
Definition: log.hpp:35
void capture_mouse(const bool capture=true)
Captures the mouse input.
widget * mouse_focus_
The widget that currently has the mouse focus_.
Definition: distributor.hpp:75
#define WRN_GUI_E
Definition: log.hpp:37
std::size_t hover_timer_
The timer for the hover event.
Definition: distributor.hpp:84
void connect_signal(const F &func, const queue_position position=back_child)
Adds a callback to the appropriate queue based on event type.
Definition: dispatcher.hpp:353
Contains the gui2 timer routines.
Holds a 2D point.
Definition: point.hpp:24
void mouse_leave()
Called when the mouse leaves the current widget.
std::size_t add_timer(const uint32_t interval, const std::function< void(std::size_t id)> &callback, const bool repeat)
Adds a new timer.
Definition: timer.cpp:127
const ui_event sdl_button_down_event
int w
Base class for all visible items.
void signal_handler_sdl_mouse_motion(const event::ui_event event, bool &handled, const point &coordinate)
queue_position
The position where to add a new callback in the signal handler.
Definition: dispatcher.hpp:333
void keyboard_remove_from_chain(widget *widget)
Remove the widget from the keyboard chain.
bool mouse_captured_
Did the current widget capture the focus_?
Definition: distributor.hpp:78
point get_mouse_position()
Returns the current mouse position.
Definition: helper.cpp:114
mouse_motion(widget &owner, const dispatcher::queue_position queue_position)
Definition: distributor.cpp:70
mouse_button(widget &owner, const dispatcher::queue_position queue_position)
void stop_hover_timer()
Stops the current hover timer.
widget * last_clicked_widget_
The widget the last click was on, used for double clicking.
#define LOG_HEADER
void show_tooltip()
Called when the mouse wants the widget to show its tooltip.
widget * keyboard_focus() const
Return the widget currently capturing keyboard input.
void initialize_state(int32_t button_state)
Initializes the state of the button.
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:76
const ui_event button_click_event
widget * hover_widget_
The widget which should get the hover event.
Definition: distributor.hpp:87
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:193
virtual widget * find_at(const point &coordinate, const bool must_be_active)
Returns the widget at the wanted coordinates.
Definition: widget.cpp:530
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
const ui_event button_up_event
void signal_handler_sdl_text_editing(const std::string &unicode, int32_t start, int32_t len)
void initialize_state()
Initializes the state of the keyboard and mouse.
void signal_handler_sdl_text_input(const std::string &unicode, int32_t start, int32_t len)
bool remove_timer(const std::size_t id)
Removes a timer.
Definition: timer.cpp:168