The Battle for Wesnoth  1.17.0-dev
distributor.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2021
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"
24 #include "gui/widgets/widget.hpp"
25 #include "gui/widgets/window.hpp"
27 #include "sdl/userevent.hpp"
28 
29 #include <functional>
30 
31 namespace gui2
32 {
33 
34 namespace event
35 {
36 
37 /**
38  * Small helper to keep a resource (boolean) locked.
39  *
40  * Some of the event handling routines can't be called recursively, this due to
41  * the fact that they are attached to the pre queue and when the forward an
42  * event the pre queue event gets triggered recursively causing infinite
43  * recursion.
44  *
45  * To prevent that those functions check the lock and exit when the lock is
46  * held otherwise grab the lock here.
47  */
49 {
50 public:
51  resource_locker(bool& locked) : locked_(locked)
52  {
53  assert(!locked_);
54  locked_ = true;
55  }
56 
58  {
59  assert(locked_);
60  locked_ = false;
61  }
62 
63 private:
64  bool& locked_;
65 };
66 
67 
68 /***** ***** ***** ***** mouse_motion ***** ***** ***** ***** *****/
69 
70 #define LOG_HEADER "distributor mouse motion [" << owner_.id() << "]: "
71 
73  const dispatcher::queue_position queue_position)
74  : mouse_focus_(nullptr)
75  , mouse_captured_(false)
76  , owner_(owner)
77  , hover_timer_(0)
78  , hover_widget_(nullptr)
79  , hover_position_(0, 0)
80  , hover_shown_(true)
81  , signal_handler_sdl_mouse_motion_entered_(false)
82 {
85  this,
86  std::placeholders::_2,
87  std::placeholders::_3,
88  std::placeholders::_5),
89  queue_position);
90 
93  this,
94  std::placeholders::_2,
95  std::placeholders::_3,
96  std::placeholders::_5,
97  std::placeholders::_6),
98  queue_position);
99 
101  &mouse_motion::signal_handler_sdl_wheel, this, std::placeholders::_2, std::placeholders::_3, std::placeholders::_5));
103  &mouse_motion::signal_handler_sdl_wheel, this, std::placeholders::_2, std::placeholders::_3, std::placeholders::_5));
105  &mouse_motion::signal_handler_sdl_wheel, this, std::placeholders::_2, std::placeholders::_3, std::placeholders::_5));
107  &mouse_motion::signal_handler_sdl_wheel, this, std::placeholders::_2, std::placeholders::_3, std::placeholders::_5));
108 
111  this,
112  std::placeholders::_2,
113  std::placeholders::_3,
114  std::placeholders::_5),
115  queue_position);
116 }
117 
119 {
121 }
122 
123 void mouse_motion::capture_mouse(const bool capture)
124 {
125  assert(mouse_focus_);
126  mouse_captured_ = capture;
127 }
128 
130  bool& handled,
131  const point& coordinate)
132 {
134  return;
135  }
137 
138  DBG_GUI_E << LOG_HEADER << event << ".\n";
139 
140  if(mouse_captured_) {
141  assert(mouse_focus_);
142  if(!owner_.fire(event, *mouse_focus_, coordinate)) {
143  mouse_hover(mouse_focus_, coordinate);
144  }
145  } else {
146  widget* mouse_over = owner_.find_at(coordinate, true);
147  while(mouse_over && !mouse_over->can_mouse_focus() && mouse_over->parent()) {
148  mouse_over = mouse_over->parent();
149  }
150  if(mouse_over) {
151  DBG_GUI_E << LOG_HEADER << "Firing: " << event << ".\n";
152  if(owner_.fire(event, *mouse_over, coordinate)) {
153  return;
154  }
155  }
156 
157  if(!mouse_focus_ && mouse_over) {
158  mouse_enter(mouse_over);
159  } else if(mouse_focus_ && !mouse_over) {
160  mouse_leave();
161  } else if(mouse_focus_ && mouse_focus_ == mouse_over) {
162  mouse_hover(mouse_over, coordinate);
163  } else if(mouse_focus_ && mouse_over) {
164  // moved from one widget to the next
165  mouse_leave();
166  mouse_enter(mouse_over);
167  } else {
168  assert(!mouse_focus_ && !mouse_over);
169  }
170  }
171  handled = true;
172 }
173 
175  bool& handled,
176  const point& coordinate,
177  const point& distance)
178 {
179  DBG_GUI_E << LOG_HEADER << event << ".\n";
180 
181  if(mouse_captured_) {
182  assert(mouse_focus_);
183  owner_.fire(event, *mouse_focus_, coordinate, distance);
184  } else {
185  widget* mouse_over = owner_.find_at(coordinate, true);
186  if(mouse_over) {
187  owner_.fire(event, *mouse_over, coordinate, distance);
188  }
189  }
190  handled = true;
191 }
192 
194  bool& handled,
195  const point& coordinate)
196 {
197  DBG_GUI_E << LOG_HEADER << event << ".\n";
198 
199  if(mouse_captured_) {
200  assert(mouse_focus_);
201  owner_.fire(event, *mouse_focus_, coordinate);
202  } else {
203  widget* mouse_over = owner_.find_at(coordinate, true);
204  if(mouse_over) {
205  owner_.fire(event, *mouse_over, coordinate);
206  }
207  }
208  handled = true;
209 }
210 
212  bool& handled,
213  const point& coordinate)
214 {
215  DBG_GUI_E << LOG_HEADER << event << ".\n";
216 
217  if(mouse_captured_) {
218  assert(mouse_focus_);
219  if(owner_.fire(event, *mouse_focus_, coordinate)) {
221  }
222  } else {
223  widget* mouse_over = owner_.find_at(coordinate, true);
224  if(mouse_over) {
225  DBG_GUI_E << LOG_HEADER << "Firing: " << event << ".\n";
226  if(owner_.fire(event, *mouse_over, coordinate)) {
228  }
229  }
230  }
231 
232  handled = true;
233 }
234 
236 {
237  DBG_GUI_E << LOG_HEADER << "Firing: " << event::MOUSE_ENTER << ".\n";
238 
239  assert(mouse_over);
240 
241  mouse_focus_ = mouse_over;
242  owner_.fire(event::MOUSE_ENTER, *mouse_over);
243 
244  hover_shown_ = false;
245  start_hover_timer(mouse_over, get_mouse_position());
246 }
247 
249 {
250  DBG_GUI_E << LOG_HEADER << "Firing: " << event::MOUSE_MOTION << ".\n";
251 
252  assert(mouse_over);
253 
254  owner_.fire(event::MOUSE_MOTION, *mouse_over, coordinate);
255 
256  if(hover_timer_) {
257  if((std::abs(hover_position_.x - coordinate.x) > 5)
258  || (std::abs(hover_position_.y - coordinate.y) > 5)) {
259 
261  start_hover_timer(mouse_over, coordinate);
262  }
263  }
264 }
265 
267 {
268  DBG_GUI_E << LOG_HEADER << "Firing: " << event::SHOW_TOOLTIP << ".\n";
269 
270  if(!hover_widget_) {
271  // See mouse_motion::stop_hover_timer.
272  ERR_GUI_E << LOG_HEADER << event::SHOW_TOOLTIP
273  << " bailing out, no hover widget.\n";
274  return;
275  }
276 
277  /*
278  * Ignore the result of the event, always mark the tooltip as shown. If
279  * there was no handler, there is no reason to assume there will be one
280  * next time.
281  */
283 
284  hover_shown_ = true;
285 
286  hover_timer_ = 0;
287  hover_widget_ = nullptr;
289 }
290 
292 {
293  DBG_GUI_E << LOG_HEADER << "Firing: " << event::MOUSE_LEAVE << ".\n";
294 
295  styled_widget* control = dynamic_cast<styled_widget*>(mouse_focus_);
296  if(!control || control->get_active()) {
297  owner_.fire(event::MOUSE_LEAVE, *mouse_focus_);
298  }
299 
301 
302  mouse_focus_ = nullptr;
303 
305 }
306 
308 {
309  assert(widget);
310 
311 #ifdef __IPHONEOS__
312  // Guessing a crash location in a nasty stack in gui2::execute_timer.
313  // Either this or a long-touch menu.
314  // Remove this when the crash in gui2::execute_timer() and gui2::timer_callback() is gone and try again.
315  return;
316 #endif
317 
319 
320  if(hover_shown_ || !widget->wants_mouse_hover()) {
321  return;
322  }
323 
324  DBG_GUI_E << LOG_HEADER << "Start hover timer for widget '" << widget->id()
325  << "' at address " << widget << ".\n";
326 
328  = add_timer(50, std::bind(&mouse_motion::show_tooltip, this));
329 
330  if(hover_timer_) {
331  hover_widget_ = widget;
333  } else {
334  ERR_GUI_E << LOG_HEADER << "Failed to add hover timer." << std::endl;
335  }
336 }
337 
339 {
340  if(hover_timer_) {
341  assert(hover_widget_);
342  DBG_GUI_E << LOG_HEADER << "Stop hover timer for widget '"
343  << hover_widget_->id() << "' at address " << hover_widget_
344  << ".\n";
345 
346  if(!remove_timer(hover_timer_)) {
347  ERR_GUI_E << LOG_HEADER << "Failed to remove hover timer."
348  << std::endl;
349  }
350 
351  hover_timer_ = 0;
352  hover_widget_ = nullptr;
354  }
355 }
356 
357 /***** ***** ***** ***** mouse_button ***** ***** ***** ***** *****/
358 
359 #undef LOG_HEADER
360 #define LOG_HEADER \
361  "distributor mouse button " << events_.name << " [" << owner_.id() << "]: "
362 
364  const dispatcher::queue_position queue_position)
365  : mouse_motion(owner, queue_position)
366  , last_click_stamp_(0)
367  , last_clicked_widget_(nullptr)
368  , focus_(nullptr)
369  , events_(events)
370  , is_down_(false)
371  , signal_handler_sdl_button_down_entered_(false)
372  , signal_handler_sdl_button_up_entered_(false)
373 {
374  // The connect_signal framework is currently using SFINAE checking to ensure that we only
375  // register mouse button signal handlers for mouse buttons. That causes us to need this
376  // hardcoded (either directly or by making mouse_button a templated class), the manual handling
377  // of the three cases here is the current progress on refactoring.
382  this,
383  std::placeholders::_2,
384  std::placeholders::_3,
385  std::placeholders::_5),
386  queue_position);
389  this,
390  std::placeholders::_2,
391  std::placeholders::_3,
392  std::placeholders::_5),
393  queue_position);
394  break;
395  }
399  this,
400  std::placeholders::_2,
401  std::placeholders::_3,
402  std::placeholders::_5),
403  queue_position);
406  this,
407  std::placeholders::_2,
408  std::placeholders::_3,
409  std::placeholders::_5),
410  queue_position);
411  break;
412  }
416  this,
417  std::placeholders::_2,
418  std::placeholders::_3,
419  std::placeholders::_5),
420  queue_position);
423  this,
424  std::placeholders::_2,
425  std::placeholders::_3,
426  std::placeholders::_5),
427  queue_position);
428  break;
429  }
430  default: {
431  // There's exactly three instances of this class per instance of distributor, so this assert
432  // will be caught during the build-time-tests.
433  assert(!"Hardcoded assumption about button being LEFT / MIDDLE / RIGHT failed");
434  }
435  }
436 }
437 
438 void mouse_button::initialize_state(int32_t button_state)
439 {
440  last_click_stamp_ = 0;
441  last_clicked_widget_ = nullptr;
442  focus_ = 0;
443  is_down_ = button_state & events_.mask;
444 }
445 
447  const point& coordinate)
448 {
450  return;
451  }
453 
454  DBG_GUI_E << LOG_HEADER << event << ".\n";
455 
456  if(is_down_) {
457 #ifdef GUI2_SHOW_UNHANDLED_EVENT_WARNINGS
458  WRN_GUI_E << LOG_HEADER << event
459  << ". The mouse button is already down, "
460  << "we missed an event.\n";
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: " << events_.sdl_button_down_event << ".\n";
470  if(!owner_.fire(events_.sdl_button_down_event, *focus_, coordinate)) {
471  DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_down_event << ".\n";
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.\n";
484 #endif
485  mouse_focus_ = mouse_over;
486  }
487 
488  focus_ = mouse_over;
489  DBG_GUI_E << LOG_HEADER << "Firing: " << events_.sdl_button_down_event << ".\n";
490  if(!owner_.fire(events_.sdl_button_down_event, *focus_, coordinate)) {
491  DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_down_event << ".\n";
493  }
494  }
495  handled = true;
496 }
497 
499  const point& coordinate)
500 {
502  return;
503  }
505 
506  DBG_GUI_E << LOG_HEADER << event << ".\n";
507 
508  if(!is_down_) {
509 #ifdef GUI2_SHOW_UNHANDLED_EVENT_WARNINGS
510  WRN_GUI_E << LOG_HEADER << event
511  << ". The mouse button is already up, we missed an event.\n";
512 #endif
513  return;
514  }
515  is_down_ = false;
516 
517  if(focus_) {
518  DBG_GUI_E << LOG_HEADER << "Firing: " << events_.sdl_button_up_event << ".\n";
519  if(!owner_.fire(events_.sdl_button_up_event, *focus_, coordinate)) {
520  DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_up_event << ".\n";
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
532  | SDL_BUTTON_RMASK;
533 
534  if((SDL_GetMouseState(nullptr, nullptr) & mask) == 0) {
535  mouse_captured_ = false;
536  }
537 
538  if(mouse_focus_ == mouse_over) {
540  } else if(!mouse_captured_) {
541  mouse_leave();
542 
543  if(mouse_over) {
544  mouse_enter(mouse_over);
545  }
546  }
547  } else if(focus_ && focus_ == mouse_over) {
549  }
550 
551  focus_ = nullptr;
552  handled = true;
553 }
554 
556 {
557  uint32_t stamp = SDL_GetTicks();
559  && last_clicked_widget_ == widget) {
560 
561  DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_double_click_event << ".\n";
562 
564  last_click_stamp_ = 0;
565  last_clicked_widget_ = nullptr;
566 
567  } else {
568 
569  DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_click_event << ".\n";
571  last_click_stamp_ = stamp;
572  last_clicked_widget_ = widget;
573  }
574 }
575 
576 /***** ***** ***** ***** distributor ***** ***** ***** ***** *****/
577 
578 #undef LOG_HEADER
579 #define LOG_HEADER "distributor mouse motion [" << owner_.id() << "]: "
580 
581 namespace
582 {
583 
584 const auto mouse_button_left_events = mouse_button_event_types {
591  SDL_BUTTON_LMASK,
592  "left"};
593 
594 const auto mouse_button_middle_events = mouse_button_event_types {
601  SDL_BUTTON_MMASK,
602  "middle"};
603 
604 const auto mouse_button_right_events = mouse_button_event_types {
611  SDL_BUTTON_RMASK,
612  "right"};
613 } // anonymous namespace
614 
615 /**
616  * @todo Test whether the state is properly tracked when an input blocker is
617  * used.
618  */
620  const dispatcher::queue_position queue_position)
621  : mouse_motion(owner, queue_position)
622  , mouse_button_left(mouse_button_left_events, owner, queue_position)
623  , mouse_button_middle(mouse_button_middle_events, owner, queue_position)
624  , mouse_button_right(mouse_button_right_events, owner, queue_position)
625  , keyboard_focus_(nullptr)
626  , keyboard_focus_chain_()
627 {
628  if(SDL_WasInit(SDL_INIT_TIMER) == 0) {
629  if(SDL_InitSubSystem(SDL_INIT_TIMER) == -1) {
630  assert(false);
631  }
632  }
633 
635  &distributor::signal_handler_sdl_key_down, this, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7));
636 
638  &distributor::signal_handler_sdl_text_input, this, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7));
639 
641  &distributor::signal_handler_sdl_text_editing, this, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7));
642 
644  &distributor::signal_handler_notify_removal, this, std::placeholders::_1, std::placeholders::_2));
645 
647 }
648 
650 {
652  &distributor::signal_handler_sdl_key_down, this, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7));
653 
655  &distributor::signal_handler_sdl_text_input, this, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7));
656 
658  &distributor::signal_handler_sdl_text_editing, this, std::placeholders::_5, std::placeholders::_6, std::placeholders::_7));
659 
661  &distributor::signal_handler_notify_removal, this, std::placeholders::_1, std::placeholders::_2));
662 }
663 
665 {
666  const uint32_t button_state = SDL_GetMouseState(nullptr, nullptr);
667 
671 
673 }
674 
676 {
677  return keyboard_focus_;
678 }
679 
681 {
682  if(keyboard_focus_) {
684  << ".\n";
685 
686  owner_.fire(event::LOSE_KEYBOARD_FOCUS, *keyboard_focus_, nullptr);
687  }
688 
689  keyboard_focus_ = widget;
690 
691  if(keyboard_focus_) {
693  << ".\n";
694 
695  owner_.fire(event::RECEIVE_KEYBOARD_FOCUS, *keyboard_focus_, nullptr);
696  }
697 }
698 
700 {
701  assert(widget);
702  assert(std::find(keyboard_focus_chain_.begin(),
703  keyboard_focus_chain_.end(),
704  widget) == keyboard_focus_chain_.end());
705 
706  keyboard_focus_chain_.push_back(widget);
707 }
708 
710 {
711  assert(w);
712  auto itor = std::find(keyboard_focus_chain_.begin(), keyboard_focus_chain_.end(), w);
713 
714  if(itor != keyboard_focus_chain_.end()) {
715  keyboard_focus_chain_.erase(itor);
716  }
717 }
718 
719 template<typename Fcn, typename P1, typename P2, typename P3>
721 {
722  /** @todo Test whether recursion protection is needed. */
723 
724  DBG_GUI_E << LOG_HEADER << evt << ".\n";
725 
726  if(keyboard_focus_) {
727  // Attempt to cast to styled_widget, to avoid sending events if the
728  // widget is disabled. If the cast fails, we assume the widget
729  // is enabled and ready to receive events.
730  styled_widget* control = dynamic_cast<styled_widget*>(keyboard_focus_);
731  if(!control || control->get_active()) {
732  DBG_GUI_E << LOG_HEADER << "Firing: " << evt
733  << ".\n";
734  if(owner_.fire(evt, *keyboard_focus_, p1, p2, p3)) {
735  return;
736  }
737  }
738  if(text_box_base* tb = dynamic_cast<text_box_base*>(keyboard_focus_)) {
739  if(tb->is_composing()) {
740  return; // Skip the keyboard chain if composition is in progress.
741  }
742  }
743  }
744 
745  for(std::vector<widget*>::reverse_iterator ritor
746  = keyboard_focus_chain_.rbegin();
747  ritor != keyboard_focus_chain_.rend();
748  ++ritor) {
749 
750  if(*ritor == keyboard_focus_) {
751  continue;
752  }
753 
754  if(*ritor == &owner_) {
755  /**
756  * @todo Make sure we're not in the event chain.
757  *
758  * No idea why we're here, but needs to be fixed, otherwise we keep
759  * calling this function recursively upon unhandled events...
760  *
761  * Probably added to make sure the window can grab the events and
762  * handle + block them when needed, this is no longer needed with
763  * the chain.
764  */
765  continue;
766  }
767 
768  // Attempt to cast to styled_widget, to avoid sending events if the
769  // widget is disabled. If the cast fails, we assume the widget
770  // is enabled and ready to receive events.
771  styled_widget* control = dynamic_cast<styled_widget*>(keyboard_focus_);
772  if(control != nullptr && !control->get_active()) {
773  continue;
774  }
775 
776  DBG_GUI_E << LOG_HEADER << "Firing: " << evt << ".\n";
777  if(owner_.fire(evt, **ritor, p1, p2, p3)) {
778 
779  return;
780  }
781  }
782 }
783 
784 void distributor::signal_handler_sdl_key_down(const SDL_Keycode key, const SDL_Keymod modifier, const std::string& unicode)
785 {
786  signal_handler_keyboard_internal<signal_keyboard_function>(event::SDL_KEY_DOWN, key, modifier, unicode);
787 }
788 
789 void distributor::signal_handler_sdl_text_input(const std::string& unicode, int32_t start, int32_t end)
790 {
791  signal_handler_keyboard_internal<signal_text_input_function>(event::SDL_TEXT_INPUT, unicode, start, end);
792 }
793 
794 void distributor::signal_handler_sdl_text_editing(const std::string& unicode, int32_t start, int32_t end)
795 {
796  signal_handler_keyboard_internal<signal_text_input_function>(event::SDL_TEXT_EDITING, unicode, start, end);
797 }
798 
800  const ui_event event)
801 {
802  DBG_GUI_E << LOG_HEADER << event << ".\n";
803 
804  /**
805  * @todo Evaluate whether moving the cleanup parts in the subclasses.
806  *
807  * It might be cleaner to do it that way, but creates extra small
808  * functions...
809  */
810 
811  if(hover_widget_ == &w) {
813  }
814 
817  }
818  if(mouse_button_left::focus_ == &w) {
819  mouse_button_left::focus_ = nullptr;
820  }
821 
824  }
825  if(mouse_button_middle::focus_ == &w) {
826  mouse_button_middle::focus_ = nullptr;
827  }
828 
831  }
832  if(mouse_button_right::focus_ == &w) {
833  mouse_button_right::focus_ = nullptr;
834  }
835 
836  if(mouse_focus_ == &w) {
837  mouse_focus_ = nullptr;
838  }
839 
840  if(keyboard_focus_ == &w) {
841  keyboard_focus_ = nullptr;
842  }
843  const auto itor = std::find(keyboard_focus_chain_.begin(), keyboard_focus_chain_.end(), &w);
844  if(itor != keyboard_focus_chain_.end()) {
845  keyboard_focus_chain_.erase(itor);
846  }
847 }
848 
849 } // namespace event
850 
851 } // namespace gui2
Define the common log macros for the gui toolkit.
uint32_t last_click_stamp_
The time of the last click used for double clicking.
#define ERR_GUI_E
Definition: log.hpp:38
Request the widget to show its hover helptip.
Definition: handler.hpp:106
bool hover_shown_
Has the hover been shown for the widget?
Three subclasses of mouse_button, so that the distributor class can inherit from them; C++ doesn&#39;t al...
An SDL text editing (IME) event.
Definition: handler.hpp:86
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.
A left mouse button down event for a widget.
Definition: handler.hpp:61
Widget loses keyboard focus.
Definition: handler.hpp:101
unsigned double_click_time
Definition: settings.cpp:40
An SDL wheel right event.
Definition: handler.hpp:81
Base class for event handling.
Definition: dispatcher.hpp:307
void signal_handler_sdl_wheel(const event::ui_event event, bool &handled, const point &coordinate)
See LEFT_BUTTON_CLICK.
Definition: handler.hpp:77
virtual bool get_active() const =0
Gets the active state of the styled_widget.
An SDL left mouse button down event.
Definition: handler.hpp:59
void keyboard_capture(widget *widget)
Captures the keyboard input.
void initialize_state(int32_t button_state)
Initializes the state of the button.
const std::string & id() const
Definition: widget.cpp:110
This file contains the window object, this object is a top level container which has the event manage...
An SDL key down event.
Definition: handler.hpp:84
Base class for all widgets.
Definition: widget.hpp:49
A mouse leave event for a widget.
Definition: handler.hpp:57
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...
See LEFT_BUTTON_DOUBLE_CLICK.
Definition: handler.hpp:78
See LEFT_BUTTON_CLICK.
Definition: handler.hpp:70
An SDL right mouse button down event.
Definition: handler.hpp:73
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.
std::enable_if_t< is_general_event(E)> disconnect_signal(const signal_function &signal, const queue_position position=back_child)
Disconnect a signal for callback in set_event.
Definition: dispatcher.hpp:523
See LEFT_BUTTON_DOWN.
Definition: handler.hpp:68
bool wants_mouse_hover() const
Contains the event distributor.
An SDL wheel down event.
Definition: handler.hpp:83
See LEFT_BUTTON_UP.
Definition: handler.hpp:76
Widget gains keyboard focus.
Definition: handler.hpp:100
Request the widget to show its hover tooltip.
Definition: handler.hpp:103
widget * last_clicked_widget_
The widget the last click was on, used for double clicking.
void mouse_hover(widget *mouse_over, const point &coordinate)
Called when the mouse moves over a widget.
int x
x coordinate.
Definition: point.hpp:45
void init_mouse_location()
Initializes the location of the mouse.
Definition: handler.cpp:911
Generic file dialog.
Definition: field-fwd.hpp:23
void signal_handler_show_helptip(const event::ui_event event, bool &handled, const point &coordinate)
Request the widget to remove its hover tooltip.
Definition: handler.hpp:104
void keyboard_add_to_chain(widget *widget)
Adds the widget to the keyboard chain.
void signal_handler_sdl_button_down(const event::ui_event event, bool &handled, const point &coordinate)
distributor(widget &owner, const dispatcher::queue_position queue_position)
bool is_down_
Is the button down?
Small helper to keep a resource (boolean) locked.
Definition: distributor.cpp:48
int32_t mask
Bitmask corresponding to this button&#39;s bit in SDL_GetMouseState&#39;s return value.
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 & owner_
The widget that owns us.
Definition: distributor.hpp:84
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
A left mouse button up event for a widget.
Definition: handler.hpp:62
widget * keyboard_focus_
The widget that holds the keyboard focus_.
Sent by a widget to notify others it&#39;s being destroyed.
Definition: handler.hpp:88
widget * parent()
Definition: widget.cpp:160
An SDL middle mouse button down event.
Definition: handler.hpp:66
void start_hover_timer(widget *widget, const point &coordinate)
Starts the hover timer.
virtual bool can_mouse_focus() const
Whether the mouse move/click event go &#39;through&#39; this widget.
Definition: widget.hpp:334
point hover_position_
The anchor point of the hover event.
Definition: distributor.hpp:93
An SDL wheel up event.
Definition: handler.hpp:82
const mouse_button_event_types events_
Which set of SDL events correspond to this button.
An SDL middle mouse button up event.
Definition: handler.hpp:67
void signal_handler_notify_removal(dispatcher &widget, const ui_event event)
void mouse_enter(widget *mouse_over)
Called when the mouse enters a widget.
std::enable_if_t< is_general_event(E)> connect_signal(const signal_function &signal, const queue_position position=back_child)
Connect a signal for callback in set_event.
Definition: dispatcher.hpp:506
#define DBG_GUI_E
Definition: log.hpp:35
void capture_mouse(const bool capture=true)
Captures the mouse input.
An SDL wheel left event.
Definition: handler.hpp:80
widget * mouse_focus_
The widget that currently has the mouse focus_.
Definition: distributor.hpp:78
A mouse motion event for a widget.
Definition: handler.hpp:56
#define WRN_GUI_E
Definition: log.hpp:37
mouse_button(const mouse_button_event_types &events, widget &owner, const dispatcher::queue_position queue_position)
A left mouse button double click event for a widget.
Definition: handler.hpp:64
std::size_t hover_timer_
The timer for the hover event.
Definition: distributor.hpp:87
A mouse enter event for a widget.
Definition: handler.hpp:55
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
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:478
void keyboard_remove_from_chain(widget *widget)
Remove the widget from the keyboard chain.
Handling of system events.
Definition: manager.hpp:43
bool mouse_captured_
Did the current widget capture the focus_?
Definition: distributor.hpp:81
An SDL left mouse button up event.
Definition: handler.hpp:60
point get_mouse_position()
Returns the current mouse position.
Definition: helper.cpp:118
mouse_motion(widget &owner, const dispatcher::queue_position queue_position)
Definition: distributor.cpp:72
void stop_hover_timer()
Stops the current hover timer.
#define LOG_HEADER
void show_tooltip()
Called when the mouse wants the widget to show its tooltip.
An SDL text input (commit) event.
Definition: handler.hpp:85
widget * keyboard_focus() const
Return the widget currently capturing keyboard input.
Small helper metastruct to configure instances of mouse_button.
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:69
widget * hover_widget_
The widget which should get the hover event.
Definition: distributor.hpp:90
See LEFT_BUTTON_DOWN.
Definition: handler.hpp:75
virtual widget * find_at(const point &coordinate, const bool must_be_active)
Returns the widget at the wanted coordinates.
Definition: widget.cpp:573
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
void signal_handler_sdl_button_up(const event::ui_event event, bool &handled, const point &coordinate)
void signal_handler_sdl_text_editing(const std::string &unicode, int32_t start, int32_t len)
An SDL right mouse button up event.
Definition: handler.hpp:74
See LEFT_BUTTON_DOUBLE_CLICK.
Definition: handler.hpp:71
int y
y coordinate.
Definition: point.hpp:48
A left mouse button click event for a widget.
Definition: handler.hpp:63
void mouse_button_click(widget *widget)
void initialize_state()
Initializes the state of the keyboard and mouse.
See LEFT_BUTTON_UP.
Definition: handler.hpp:69
ui_event
The event send to the dispatcher.
Definition: handler.hpp:48
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
An SDL mouse motion event.
Definition: handler.hpp:54