The Battle for Wesnoth  1.15.0-dev
dispatcher.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2018 by Mark de Wever <koraq@xs4all.nl>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
19 #include "utils/functional.hpp"
20 
21 #include <SDL_events.h>
22 
23 #include <list>
24 #include <map>
25 #include <type_traits>
26 
27 struct point;
28 
29 namespace gui2
30 {
31 class widget;
32 
33 namespace event
34 {
35 /**
36  * Helper for catching use error of @ref dispatcher::connect_signal.
37  *
38  * This helper is needed as a user can't supply the wrong kind of callback
39  * functions to dispatcher::connect_signal. If a wrong callback would be send
40  * it will never get called.
41  *
42  * This version is for callbacks without extra parameters.
43  * NOTE some mouse functions like MOUSE_ENTER don't send the mouse coordinates
44  * to the callback function so they are also in this category.
45  */
46 constexpr bool is_general_event(const ui_event event)
47 {
48  return event == DRAW
49  || event == CLOSE_WINDOW
50  || event == MOUSE_ENTER
51  || event == MOUSE_LEAVE
52  || event == LEFT_BUTTON_DOWN
53  || event == LEFT_BUTTON_UP
54  || event == LEFT_BUTTON_CLICK
55  || event == LEFT_BUTTON_DOUBLE_CLICK
56  || event == MIDDLE_BUTTON_DOWN
57  || event == MIDDLE_BUTTON_UP
58  || event == MIDDLE_BUTTON_CLICK
59  || event == MIDDLE_BUTTON_DOUBLE_CLICK
60  || event == RIGHT_BUTTON_DOWN
61  || event == RIGHT_BUTTON_UP
62  || event == RIGHT_BUTTON_CLICK
63  || event == RIGHT_BUTTON_DOUBLE_CLICK;
64 }
65 
66 /**
67  * Helper for catching use error of @ref dispatcher::connect_signal.
68  *
69  * This version is for callbacks with a coordinate as extra parameter.
70  */
71 constexpr bool is_mouse_event(const ui_event event)
72 {
73  return event == SDL_VIDEO_RESIZE
74  || event == SDL_MOUSE_MOTION
75  || event == MOUSE_MOTION
76  || event == SDL_LEFT_BUTTON_DOWN
77  || event == SDL_LEFT_BUTTON_UP
78  || event == SDL_MIDDLE_BUTTON_DOWN
79  || event == SDL_MIDDLE_BUTTON_UP
80  || event == SDL_RIGHT_BUTTON_DOWN
81  || event == SDL_RIGHT_BUTTON_UP
82  || event == SHOW_TOOLTIP
83  || event == SHOW_HELPTIP
84  || event == SDL_WHEEL_UP
85  || event == SDL_WHEEL_DOWN
86  || event == SDL_WHEEL_LEFT
87  || event == SDL_WHEEL_RIGHT;
88 }
89 
90 /**
91  * Helper for catching use error of @ref dispatcher::connect_signal.
92  *
93  * This version is for callbacks with the keyboard values (these haven't been
94  * determined yet).
95  */
96 constexpr bool is_keyboard_event(const ui_event event)
97 {
98  return event == SDL_KEY_DOWN;
99 }
100 
101 /**
102  * Helper for catching use error of @ref dispatcher::connect_signal.
103  *
104  * This version is for callbacks of touch events.
105  */
106 constexpr bool is_touch_event(const ui_event event)
107 {
108  return event == SDL_TOUCH_MOTION
109  || event == SDL_TOUCH_UP
110  || event == SDL_TOUCH_DOWN;
111 }
112 
113 /**
114  * Helper for catching use error of @ref dispatcher::connect_signal.
115  *
116  * This version is for callbacks with a sender aka notification messages. Like the
117  * ones in set_event it has no extra parameters, but this version is only
118  * send to the target and not using the pre and post queue.
119  */
120 constexpr bool is_notification_event(const ui_event event)
121 {
122  return event == NOTIFY_REMOVAL
123  || event == NOTIFY_MODIFIED
124  || event == RECEIVE_KEYBOARD_FOCUS
125  || event == LOSE_KEYBOARD_FOCUS
126  || event == NOTIFY_REMOVE_TOOLTIP
127  || event == SDL_ACTIVATE;
128 }
129 
130 /**
131  * Helper for catching use error of @ref dispatcher::connect_signal.
132  *
133  * This version is for callbacks with a sender aka notification messages.
134  * Unlike the notifications this message is send through the chain. The event
135  * is send from a widget all the way up to the window, who always is the
136  * receiver of the message (unless somebody grabbed it before).
137  */
138 constexpr bool is_message_event(const ui_event event)
139 {
140  return event == MESSAGE_SHOW_TOOLTIP
141  || event == MESSAGE_SHOW_HELPTIP
142  || event == REQUEST_PLACEMENT;
143 }
144 
145 /**
146  * Helper for catching use error of @ref dispatcher::connect_signal.
147  *
148  * This version is for callbacks of raw events.
149  */
150 constexpr bool is_raw_event_event(const ui_event event)
151 {
152  return event == SDL_RAW_EVENT;
153 }
154 
155 /**
156  * Helper for catching use error of @ref dispatcher::connect_signal.
157  *
158  * This version is for callbacks of text input events.
159  */
160 constexpr bool is_text_input_event(const ui_event event)
161 {
162  return event == SDL_TEXT_INPUT || event == SDL_TEXT_EDITING;
163 }
164 
165 struct message;
166 
167 /**
168  * Callback function signature alias template.
169  *
170  * All callbacks take these four arguments in addition to any arguments
171  * specified by the parameter pack.
172  *
173  * Parameters:
174  * 1. The widget handling this event.
175  * 2. The event type.
176  * 3. Reference to the flag controlling whether this event has been handled.
177  * 4. Reference to the flag controlling whether to halt execution of this event.
178  */
179 template<typename... T>
180 using dispatcher_callback_func = std::function<void(widget&, const ui_event, bool&, bool&, T...)>;
181 
182 /**
183  * Callback function signature.
184  *
185  * This is used for events matching @ref is_general_event.
186  */
188 
189 /**
190  * Callback function signature.
191  *
192  * This is used for events matching @ref is_mouse_event.
193  *
194  * Extra parameters:
195  * 5. The x,y coordinate of the mouse when this event is fired.
196  */
198 
199 /**
200  * Callback function signature.
201  *
202  * This is used for events matching @ref is_keyboard_event.
203  *
204  * Extra parameters:
205  * 5. The keycode of the key that triggered this event.
206  * 6. Any applicable active modifer key.
207  * 7. Any applicable text associated with the key.
208  */
211 
212 /**
213  * Callback function signature.
214  *
215  * This is used for events matching @ref is_touch_event.
216  *
217  * Extra parameters:
218  * 5. Origin of the touch event, in x,y format.
219  * 6. Number of pixels dragged, in x,y format.
220  */
222 
223 /**
224  * Callback function signature.
225  *
226  * This is used for events matching @ref is_notification_event.
227  *
228  * Extra parameters:
229  * 5. A dummy void* parameter which will always be nullptr, used to differentiate
230  * this function from signal_function.
231  */
233 
234 /**
235  * Callback function signature.
236  *
237  * This is used for events matching @ref is_message_event.
238  *
239  * Extra parameters:
240  * 5. The applicable data this event requires.
241  */
243 
244 /**
245  * Raw event callback function signature.
246  *
247  * This is used for events matching @ref is_raw_event_event.
248  *
249  * Extra parameters:
250  * 5. The raw SDL_Event.
251  */
253 
254 /**
255  * Callback function signature.
256  *
257  * This is used for events matching @ref is_text_input_event.
258  *
259  * Extra parameters:
260  * 5. The text entered.
261  * 6. The current input position.
262  * 7. The current text selection length.
263  */
265 
266 /** Hotkey function handler signature. */
267 using hotkey_function = std::function<void(widget& dispatcher, hotkey::HOTKEY_COMMAND id)>;
268 
269 /**
270  * Base class for event handling.
271  *
272  * A dispatcher has slots for events, when an event arrives it looks for the
273  * functions that registered themselves for that event and calls their
274  * callbacks.
275  *
276  * This class is a base class for all widgets[1], what a widget does on a
277  * callback can differ greatly, an image might ignore all events a window can
278  * track the mouse location and fire MOUSE_ENTER and MOUSE_LEAVE events to the
279  * widgets involved.
280  *
281  * [1] Not really sure whether it will be a base class for a widget or
282  * styled_widget yet.
283  */
285 {
287 
288 public:
289  dispatcher();
290  virtual ~dispatcher();
291 
292  /**
293  * Connects the dispatcher to the event handler.
294  *
295  * When a dispatcher is connected to the event handler it will get the
296  * events directly from the event handler. This is wanted for top level
297  * items like windows but not for most other widgets.
298  *
299  * So a window can call connect to register itself, it will automatically
300  * disconnect upon destruction.
301  */
302  void connect();
303 
304  /**
305  * Determines whether the location is inside an active widget.
306  *
307  * This is used to see whether a mouse event is inside the widget.
308  *
309  * @param coordinate The coordinate to test whether inside the
310  * widget.
311  *
312  * @result True if inside an active widget, false
313  * otherwise.
314  */
315  virtual bool is_at(const point& coordinate) const = 0;
316 
318  pre = 1,
319  child = 2,
320  post = 4
321  };
322 
323  bool has_event(const ui_event event, const event_queue_type event_type);
324 
325  /** Fires an event which has no extra parameters. */
326  bool fire(const ui_event event, widget& target);
327 
328  /**
329  * Fires an event which takes a coordinate parameter.
330  *
331  * @param event The event to fire.
332  * @param target The widget that should receive the event.
333  * @param coordinate The mouse position for the event.
334  */
335  bool fire(const ui_event event,
336  widget& target,
337  const point& coordinate);
338 
339  /**
340  * Fires an event which takes keyboard parameters.
341  *
342  * @param event The event to fire.
343  * @param target The widget that should receive the event.
344  * @param key The SDL key code of the key pressed.
345  * @param modifier The SDL key modifiers used.
346  * @param unicode The unicode value for the key pressed.
347  */
348  bool fire(const ui_event event,
349  widget& target,
350  const SDL_Keycode key,
351  const SDL_Keymod modifier,
352  const std::string& unicode);
353 
354  /**
355  * Fires an event which takes touch parameters.
356  *
357  * @param event The event to fire.
358  * @param target The widget that should receive the event.
359  * @param pos The location touched.
360  * @param distance The distance moved.
361  */
362  bool fire(const ui_event event,
363  widget& target,
364  const point& pos,
365  const point& distance);
366 
367  /**
368  * Fires an event which takes notification parameters.
369  *
370  * @note the void* parameter is a dummy needed for SFINAE.
371  *
372  * @param event The event to fire.
373  * @param target The widget that should receive the event.
374  */
375  bool fire(const ui_event event,
376  widget& target,
377  void*);
378 
379  /**
380  * Fires an event which takes message parameters.
381  *
382  * @param event The event to fire.
383  * @param target The widget that should receive the event.
384  * Normally this is the window holding the
385  * widget.
386  * @param msg The extra information needed for a window
387  * (or another widget in the chain) to handle
388  * the message.
389  */
390  bool fire(const ui_event event,
391  widget& target,
392  const message& msg);
393 
394  /**
395  * Fires an event that's a raw SDL event
396  * @param event The event to fire.
397  * @param target The widget that should receive the event.
398  * Normally this is the window holding the
399  * widget.
400  * @param sdlevent The raw SDL event
401  */
402  bool fire(const ui_event event,
403  widget& target,
404  const SDL_Event& sdlevent);
405 
406  /**
407  * Fires an event which takes text input parameters
408  * @param event The event to fire.
409  * @param target The widget that should receive the event.
410  * Normally this is the window holding the
411  * widget.
412  * @param text The text involved in the event
413  * @param start The start point for IME editing
414  * @param len The selection length for IME editing
415  */
416  bool fire(const ui_event event,
417  widget& target,
418  const std::string& text,
419  int32_t start,
420  int32_t len);
421 
422  /**
423  * The position where to add a new callback in the signal handler.
424  *
425  * The signal handler has three callback queues:
426  * * pre_child These callbacks are called before a container widget sends it
427  * to the child items. Widgets without children should also use this
428  * queue.
429  * * child The callbacks for the proper child widget(s) are called.
430  * * post_child The callbacks for the parent container to be called after
431  * the child.
432  *
433  * For every queue it's possible to add a new event in the front or in the
434  * back.
435  *
436  * Whether all three queues are executed depend on the whether the
437  * callbacks modify the handled and halt flag.
438  * * When the halt flag is set execution of the current queue stops, when
439  * doing so the handled flag must be set as well.
440  * * When the handled flag is set the events in that queue are executed and
441  * no more queues afterwards.
442  *
443  * Here are some use case examples.
444  * A button that plays a sound and executes an optional user callback:
445  * * The buttons internal click handler is invoked and sets the handled
446  * flag
447  * * The callback installed by the user is in the same queue and gets
448  * executed afterwards.
449  *
450  * A toggle button may or may not be toggled:
451  * * The user inserts a callback, that validates whether the action is
452  * allowed, if not allowed it sets the halt flag (and handled), else
453  * leaves the flags untouched.
454  * * The normal buttons toggle function then might get invoked and if so
455  * sets the handled flag.
456  * * Optionally there is another user callback invoked at this point.
457  */
465  };
466 
467  /**
468  * Connect a signal for callback in set_event.
469  *
470  * The function uses some enable_if magic to avoid registering the wrong
471  * function, but the common way to use this function is:
472  * widget->connect_signal<EVENT_ID>(
473  * std::bind(&tmy_dialog::my_member, this));
474  * This allows simply adding a member of a dialog to be used as a callback
475  * for widget without a lot of magic. Note most widgets probably will get a
476  * callback like
477  * connect_signal_mouse_left_click(const signal_function& callback)
478  * which hides this function for the average use.
479  *
480  * @tparam E The event the callback needs to react to.
481  * @param signal The callback function.
482  * @param position The position to place the callback.
483  */
484  template<ui_event E>
485  std::enable_if_t<is_general_event(E)>
486  connect_signal(const signal_function& signal, const queue_position position = back_child)
487  {
488  signal_queue_.connect_signal(E, position, signal);
489  }
490 
491  /**
492  * Disconnect a signal for callback in set_event.
493  *
494  * @tparam E The event the callback was used for.
495  * @param signal The callback function.
496  * @param position The place where the function was added.
497  * Needed remove the event from the right
498  * place. (The function doesn't care whether
499  * was added in front or back.)
500  */
501  template<ui_event E>
502  std::enable_if_t<is_general_event(E)>
504  {
505  signal_queue_.disconnect_signal(E, position, signal);
506  }
507 
508  /**
509  * Connect a signal for callback in set_event_mouse.
510  *
511  * @tparam E The event the callback needs to react to.
512  * @param signal The callback function.
513  * @param position The position to place the callback.
514  */
515  template<ui_event E>
516  std::enable_if_t<is_mouse_event(E)>
518  {
519  signal_mouse_queue_.connect_signal(E, position, signal);
520  }
521 
522  /**
523  * Disconnect a signal for callback in set_event_mouse.
524  *
525  * @tparam E The event the callback was used for.
526  * @param signal The callback function.
527  * @param position The place where the function was added.
528  * Needed remove the event from the right
529  * place. (The function doesn't care whether
530  * was added in front or back.)
531  */
532  template<ui_event E>
533  std::enable_if_t<is_mouse_event(E)>
535  {
536  signal_mouse_queue_.disconnect_signal(E, position, signal);
537  }
538 
539  /**
540  * Connect a signal for callback in set_event_keyboard.
541  *
542  * @tparam E The event the callback needs to react to.
543  * @param signal The callback function.
544  * @param position The position to place the callback.
545  */
546  template<ui_event E>
547  std::enable_if_t<is_keyboard_event(E)>
549  {
550  signal_keyboard_queue_.connect_signal(E, position, signal);
551  }
552 
553  /**
554  * Disconnect a signal for callback in set_event_keyboard.
555  *
556  * @tparam E The event the callback was used for.
557  * @param signal The callback function.
558  * @param position The place where the function was added.
559  * Needed remove the event from the right
560  * place. (The function doesn't care whether
561  * was added in front or back.)
562  */
563  template<ui_event E>
564  std::enable_if_t<is_keyboard_event(E)>
566  {
567  signal_keyboard_queue_.disconnect_signal(E, position, signal);
568  }
569 
570  /**
571  * Connect a signal for callback in set_event_touch.
572  *
573  * @tparam E The event the callback needs to react to.
574  * @param signal The callback function.
575  * @param position The position to place the callback.
576  */
577  template<ui_event E>
578  std::enable_if_t<is_touch_event(E)>
580  {
581  signal_touch_queue_.connect_signal(E, position, signal);
582  }
583 
584  /**
585  * Disconnect a signal for callback in set_event_touch.
586  *
587  * @tparam E The event the callback was used for.
588  * @param signal The callback function.
589  * @param position The place where the function was added.
590  * Needed remove the event from the right
591  * place. (The function doesn't care whether
592  * was added in front or back.)
593  */
594  template<ui_event E>
595  std::enable_if_t<is_touch_event(E)>
597  {
598  signal_touch_queue_.disconnect_signal(E, position, signal);
599  }
600 
601  /**
602  * Connect a signal for callback in set_event_notification.
603  *
604  * @tparam E The event the callback needs to react to.
605  * @param signal The callback function.
606  * @param position The position to place the callback. Since
607  * the message is send to a widget directly
608  * the pre and post positions make no sense
609  * and shouldn't be used.
610  */
611  template<ui_event E>
612  std::enable_if_t<is_notification_event(E)>
614  {
615  signal_notification_queue_.connect_signal(E, position, signal);
616  }
617 
618  /**
619  * Disconnect a signal for callback in set_event_notification.
620  *
621  * @tparam E The event the callback was used for.
622  * @param signal The callback function.
623  * @param position The place where the function was added.
624  * Needed remove the event from the right
625  * place. (The function doesn't care whether
626  * was added in front or back, but it needs
627  * to know the proper queue so it's save to
628  * add with front_child and remove with
629  * back_child. But it's not save to add with
630  * front_child and remove with
631  * front_pre_child)
632  */
633  template<ui_event E>
634  std::enable_if_t<is_notification_event(E)>
636  {
637  signal_notification_queue_.disconnect_signal(E, position, signal);
638  }
639 
640  /**
641  * Connect a signal for callback in set_event_message.
642  *
643  * @tparam E The event the callback needs to react to.
644  * @param signal The callback function.
645  * @param position The position to place the callback. Since
646  * the message is send to a widget directly
647  * the pre and post positions make no sense
648  * and shouldn't be used.
649  */
650  template<ui_event E>
651  std::enable_if_t<is_message_event(E)>
653  {
654  signal_message_queue_.connect_signal(E, position, signal);
655  }
656 
657  /**
658  * Disconnect a signal for callback in set_event_message.
659  *
660  * @tparam E The event the callback was used for.
661  * @param signal The callback function.
662  * @param position The place where the function was added.
663  * Needed remove the event from the right
664  * place. (The function doesn't care whether
665  * was added in front or back, but it needs
666  * to know the proper queue so it's save to
667  * add with front_child and remove with
668  * back_child. But it's not save to add with
669  * front_child and remove with
670  * front_pre_child)
671  */
672  template<ui_event E>
673  std::enable_if_t<is_message_event(E)>
675  {
676  signal_message_queue_.disconnect_signal(E, position, signal);
677  }
678 
679  /**
680  * Connect a signal for callback in set_raw_event.
681  *
682  * @tparam E The event the callback needs to react to.
683  * @param signal The callback function.
684  * @param position The position to place the callback.
685  */
686  template<ui_event E>
687  std::enable_if_t<is_raw_event_event(E)>
689  {
690  signal_raw_event_queue_.connect_signal(E, position, signal);
691  }
692 
693  /**
694  * Disconnect a signal for callback in set_raw_event.
695  *
696  * @tparam E The event the callback was used for.
697  * @param signal The callback function.
698  * @param position The place where the function was added.
699  * Needed remove the event from the right
700  * place. (The function doesn't care whether
701  * was added in front or back.)
702  */
703  template<ui_event E>
704  std::enable_if_t<is_raw_event_event(E)>
706  {
707  signal_raw_event_queue_.disconnect_signal(E, position, signal);
708  }
709 
710  /**
711  * Connect a signal for callback in set_text_input.
712  *
713  * @tparam E The event the callback needs to react to.
714  * @param signal The callback function.
715  * @param position The position to place the callback.
716  */
717  template<ui_event E>
718  std::enable_if_t<is_text_input_event(E)>
720  {
721  signal_text_input_queue_.connect_signal(E, position, signal);
722  }
723 
724  /**
725  * Disconnect a signal for callback in set_text_input.
726  *
727  * @tparam E The event the callback was used for.
728  * @param signal The callback function.
729  * @param position The place where the function was added.
730  * Needed remove the event from the right
731  * place. (The function doesn't care whether
732  * was added in front or back.)
733  */
734  template<ui_event E>
735  std::enable_if_t<is_text_input_event(E)>
737  {
738  signal_text_input_queue_.disconnect_signal(E, position, signal);
739  }
740 
741  /**
742  * The behavior of the mouse events.
743  *
744  * Normally for mouse events there's first checked whether a dispatcher has
745  * captured the mouse if so it gets the event.
746  * If not the dispatcher is searched from the back to the front in the
747  * layers and its behavior is checked.
748  * * none The event is never send to the layer and goes on the the next
749  * layer. This is used for tooltips who might cover a button but a click
750  * on the tooltips should still click the button.
751  * * all The event is always send to this layer and stops the search for a
752  * next layer.
753  * * hit If the mouse is inside the dispatcher area the event is send and
754  * no longer searched further. If not inside tests the last layer.
755  *
756  * If after these tests no dispatcher is found the event is ignored.
757  */
762  };
763 
764  /** Captures the mouse. */
766  {
768  }
769 
770  /** Releases the mouse capture. */
772  {
774  }
775 
776  /***** ***** ***** setters/getters ***** ***** *****/
777 
779  {
781  }
782 
784  {
785  return mouse_behavior_;
786  }
787 
788  void set_want_keyboard_input(const bool want_keyboard_input)
789  {
790  want_keyboard_input_ = want_keyboard_input;
791  }
792 
794  {
795  return want_keyboard_input_;
796  }
797 
798  /** Helper struct to generate the various signal types. */
799  template<class T>
800  struct signal_type
801  {
803  {
804  }
805 
806  std::list<T> pre_child;
807  std::list<T> child;
808  std::list<T> post_child;
809 
810  /**
811  * Checks whether the queue of a given type is empty.
812  *
813  * @param queue_type The queue to check. This may be one or more types
814  * OR'd together (event_queue_type is bit-unique).
815  *
816  * @returns True if ALL the matching queues are empty, or false
817  * if any of the matching queues is NOT empty.
818  */
819  bool empty(const dispatcher::event_queue_type queue_type) const
820  {
821  if((queue_type & dispatcher::pre) && !pre_child.empty()) {
822  return false;
823  }
824 
825  if((queue_type & dispatcher::child) && !child.empty()) {
826  return false;
827  }
828 
829  if((queue_type & dispatcher::post) && !post_child.empty()) {
830  return false;
831  }
832 
833  return true;
834  }
835  };
836 
837  /** Helper struct to generate the various event queues. */
838  template<class T>
840  {
841  signal_queue() : queue()
842  {
843  }
844 
845  std::map<ui_event, signal_type<T>> queue;
846 
847  void connect_signal(const ui_event event,
848  const queue_position position,
849  const T& signal)
850  {
851  switch(position) {
852  case front_pre_child:
853  queue[event].pre_child.push_front(signal);
854  break;
855  case back_pre_child:
856  queue[event].pre_child.push_back(signal);
857  break;
858 
859  case front_child:
860  queue[event].child.push_front(signal);
861  break;
862  case back_child:
863  queue[event].child.push_back(signal);
864  break;
865 
866  case front_post_child:
867  queue[event].post_child.push_front(signal);
868  break;
869  case back_post_child:
870  queue[event].post_child.push_back(signal);
871  break;
872  }
873  }
874 
875  void disconnect_signal(const ui_event event,
876  const queue_position position,
877  const T& signal)
878  {
879  signal_type<T>& signal_queue = queue[event];
880 
881  /* The function doesn't differentiate between front and back position so fall
882  * down from front to back.
883  *
884  * NOTE: This used to only remove the first signal of matching target type.
885  * That behavior could be restored in the future if needed.
886  * - vultraz, 2017-05-02
887  */
888  switch(position) {
889  case front_pre_child:
890  case back_pre_child: {
891  signal_queue.pre_child.remove_if(
892  [&signal](T& element) { return signal.target_type() == element.target_type(); }
893  );
894  } break;
895 
896  case front_child:
897  case back_child: {
898  signal_queue.child.remove_if(
899  [&signal](T& element) { return signal.target_type() == element.target_type(); }
900  );
901  } break;
902 
903  case front_post_child:
904  case back_post_child: {
905  signal_queue.post_child.remove_if(
906  [&signal](T& element) { return signal.target_type() == element.target_type(); }
907  );
908  } break;
909  }
910  }
911  };
912 
913  /**
914  * Registers a hotkey.
915  *
916  * @todo add a static function register_global_hotkey.
917  *
918  * Once that's done execute_hotkey will first try to execute a global
919  * hotkey and if that fails tries the hotkeys in this dispatcher.
920  *
921  * @param id The hotkey to register.
922  * @param function The callback function to call.
923  */
925  const hotkey_function& function);
926 
927  /**
928  * Executes a hotkey.
929  *
930  * @param id The hotkey to execute.
931  *
932  * @returns true if the hotkey is handled, false
933  * otherwise.
934  */
935  bool execute_hotkey(const hotkey::HOTKEY_COMMAND id);
936 
937 private:
938  /** The mouse behavior for the dispatcher. */
940 
941  /**
942  * Does the dispatcher want to receive keyboard input.
943  *
944  * @todo The entire mouse and keyboard handling can use a code review to
945  * seen whether it might be combined in one flag field. At the moment the
946  * keyboard doesn't look whether a dialog has the mouse focus before
947  * sending the event, so maybe we should add an active dispatcher to keep
948  * track of it. But since at the moment there are only non-modal windows
949  * and tooltips it's not a problem.
950  */
952 
953  /** Signal queue for callbacks in set_event. */
955 
956  /** Signal queue for callbacks in set_event_mouse. */
958 
959  /** Signal queue for callbacks in set_event_keyboard. */
961 
962  /** Signal queue for callbacks in set_event_touch. */
964 
965  /** Signal queue for callbacks in set_event_notification. */
967 
968  /** Signal queue for callbacks in set_event_message. */
970 
971  /** Signal queue for callbacks in set_raw_event. */
973 
974  /** Signal queue for callbacks in set_event_text_input. */
976 
977  /** Are we connected to the event handler. */
979 
980  /** The registered hotkeys for this dispatcher. */
981  std::map<hotkey::HOTKEY_COMMAND, hotkey_function> hotkeys_;
982 };
983 
984 /***** ***** ***** ***** ***** Common helpers ***** ***** ***** ***** *****/
985 
986 /*
987  * These helpers can be used to easily add callbacks to a dispatcher (widget).
988  * This is just a list of common ones all others can be used as well.
989  */
990 
991 /**
992  * Connects the signal for 'snooping' on the keypress.
993  *
994  * This callback is called before the widget itself allowing you to either
995  * snoop on the input or filter it.
996  */
998 
999 /** Connects a signal handler for a left mouse button click. */
1001 
1002 /** Disconnects a signal handler for a left mouse button click. */
1004 
1005 /**
1006  * Connects a signal handler for a left mouse button double click.
1007  *
1008  * I'm not exactly sure why this works in this queue position with toggle
1009  * panels, but it does. Will revisit if it becomes an issue later (ie, if
1010  * this is used with other widgets and doesn't work).
1011  *
1012  * - vultraz, 2017-08-23
1013  */
1015 
1016 /** Connects a signal handler for getting a notification upon modification. */
1018 
1019 /** Connects a signal handler for a callback when the widget is drawn. */
1021 
1022 } // namespace event
1023 
1024 } // namespace gui2
mouse_behavior get_mouse_behavior() const
Definition: dispatcher.hpp:783
Request the widget to show its hover helptip.
Definition: handler.hpp:105
std::enable_if_t< is_text_input_event(E)> connect_signal(const signal_text_input_function &signal, const queue_position position=back_child)
Connect a signal for callback in set_text_input.
Definition: dispatcher.hpp:719
An SDL text editing (IME) event.
Definition: handler.hpp:85
A left mouse button down event for a widget.
Definition: handler.hpp:60
std::enable_if_t< is_notification_event(E)> disconnect_signal(const signal_notification_function &signal, const queue_position position=back_child)
Disconnect a signal for callback in set_event_notification.
Definition: dispatcher.hpp:635
Widget loses keyboard focus.
Definition: handler.hpp:100
std::enable_if_t< is_message_event(E)> connect_signal(const signal_message_function &signal, const queue_position position=back_child)
Connect a signal for callback in set_event_message.
Definition: dispatcher.hpp:652
signal_queue< signal_text_input_function > signal_text_input_queue_
Signal queue for callbacks in set_event_text_input.
Definition: dispatcher.hpp:975
An SDL wheel right event.
Definition: handler.hpp:80
dispatcher_callback_func< const SDL_Keycode, const SDL_Keymod, const std::string & > signal_keyboard_function
Callback function signature.
Definition: dispatcher.hpp:210
Base class for event handling.
Definition: dispatcher.hpp:284
constexpr bool is_message_event(const ui_event event)
Helper for catching use error of dispatcher::connect_signal.
Definition: dispatcher.hpp:138
void register_hotkey(const hotkey::HOTKEY_COMMAND id, const hotkey_function &function)
Registers a hotkey.
Definition: dispatcher.cpp:133
std::enable_if_t< is_keyboard_event(E)> disconnect_signal(const signal_keyboard_function &signal, const queue_position position=back_child)
Disconnect a signal for callback in set_event_keyboard.
Definition: dispatcher.hpp:565
See LEFT_BUTTON_CLICK.
Definition: handler.hpp:76
An SDL left mouse button down event.
Definition: handler.hpp:58
An SDL resize request, coordinate is the new window size.
Definition: handler.hpp:51
dispatcher_callback_func< const std::string &, int32_t, int32_t > signal_text_input_function
Callback function signature.
Definition: dispatcher.hpp:264
An SDL key down event.
Definition: handler.hpp:83
dispatcher_callback_func< void * > signal_notification_function
Callback function signature.
Definition: dispatcher.hpp:232
Base class for all widgets.
Definition: widget.hpp:48
A mouse leave event for a widget.
Definition: handler.hpp:56
See LEFT_BUTTON_DOUBLE_CLICK.
Definition: handler.hpp:77
See LEFT_BUTTON_CLICK.
Definition: handler.hpp:69
constexpr bool is_general_event(const ui_event event)
Helper for catching use error of dispatcher::connect_signal.
Definition: dispatcher.hpp:46
void capture_mouse(dispatcher *dispatcher)
Captures the mouse.
Definition: handler.cpp:788
An SDL right mouse button down event.
Definition: handler.hpp:72
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:503
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:108
void connect_signal(const ui_event event, const queue_position position, const T &signal)
Definition: dispatcher.hpp:847
See LEFT_BUTTON_DOWN.
Definition: handler.hpp:67
Request to show a helptip based on the data sent.
Definition: handler.hpp:106
std::enable_if_t< is_mouse_event(E)> disconnect_signal(const signal_mouse_function &signal, const queue_position position=back_child)
Disconnect a signal for callback in set_event_mouse.
Definition: dispatcher.hpp:534
dispatcher_callback_func<> signal_function
Callback function signature.
Definition: dispatcher.hpp:187
dispatcher_callback_func< const SDL_Event & > signal_raw_event_function
Raw event callback function signature.
Definition: dispatcher.hpp:252
An SDL wheel down event.
Definition: handler.hpp:82
See LEFT_BUTTON_UP.
Definition: handler.hpp:75
Widget gains keyboard focus.
Definition: handler.hpp:99
Request the widget to show its hover tooltip.
Definition: handler.hpp:102
bool has_event(const ui_event event, const event_queue_type event_type)
Definition: dispatcher.cpp:55
std::enable_if_t< is_raw_event_event(E)> connect_signal(const signal_raw_event_function &signal, const queue_position position=back_child)
Connect a signal for callback in set_raw_event.
Definition: dispatcher.hpp:688
Generic file dialog.
Definition: field-fwd.hpp:22
Sent by a widget to notify others its contents or state are modified.
Definition: handler.hpp:88
dispatcher_callback_func< const message & > signal_message_function
Callback function signature.
Definition: dispatcher.hpp:242
The message callbacks hold a reference to a message.
Definition: message.hpp:46
Request the widget to remove its hover tooltip.
Definition: handler.hpp:103
void capture_mouse()
Captures the mouse.
Definition: dispatcher.hpp:765
bool get_want_keyboard_input() const
Definition: dispatcher.hpp:793
std::function< void(widget &dispatcher, hotkey::HOTKEY_COMMAND id)> hotkey_function
Hotkey function handler signature.
Definition: dispatcher.hpp:267
dispatcher_callback_func< const point &, const point & > signal_touch_function
Callback function signature.
Definition: dispatcher.hpp:221
std::enable_if_t< is_keyboard_event(E)> connect_signal(const signal_keyboard_function &signal, const queue_position position=back_child)
Connect a signal for callback in set_event_keyboard.
Definition: dispatcher.hpp:548
void connect()
Connects the dispatcher to the event handler.
Definition: dispatcher.cpp:48
constexpr bool is_keyboard_event(const ui_event event)
Helper for catching use error of dispatcher::connect_signal.
Definition: dispatcher.hpp:96
Request to place the widget.
Definition: handler.hpp:94
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification_function &signal)
Connects a signal handler for getting a notification upon modification.
Definition: dispatcher.cpp:178
std::enable_if_t< is_notification_event(E)> connect_signal(const signal_notification_function &signal, const queue_position position=back_child)
Connect a signal for callback in set_event_notification.
Definition: dispatcher.hpp:613
signal_queue< signal_mouse_function > signal_mouse_queue_
Signal queue for callbacks in set_event_mouse.
Definition: dispatcher.hpp:957
std::enable_if_t< is_raw_event_event(E)> disconnect_signal(const signal_raw_event_function &signal, const queue_position position=back_child)
Disconnect a signal for callback in set_raw_event.
Definition: dispatcher.hpp:705
virtual bool is_at(const point &coordinate) const =0
Determines whether the location is inside an active widget.
A left mouse button up event for a widget.
Definition: handler.hpp:61
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal_function &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:163
Periodic redraw request.
Definition: handler.hpp:49
Sent by a widget to notify others it&#39;s being destroyed.
Definition: handler.hpp:87
bool execute_hotkey(const hotkey::HOTKEY_COMMAND id)
Executes a hotkey.
Definition: dispatcher.cpp:138
dispatcher_callback_func< const point & > signal_mouse_function
Callback function signature.
Definition: dispatcher.hpp:197
constexpr bool is_mouse_event(const ui_event event)
Helper for catching use error of dispatcher::connect_signal.
Definition: dispatcher.hpp:71
std::enable_if_t< is_message_event(E)> disconnect_signal(const signal_message_function &signal, const queue_position position=back_child)
Disconnect a signal for callback in set_event_message.
Definition: dispatcher.hpp:674
An SDL middle mouse button down event.
Definition: handler.hpp:65
std::enable_if_t< is_mouse_event(E)> connect_signal(const signal_mouse_function &signal, const queue_position position=back_child)
Connect a signal for callback in set_event_mouse.
Definition: dispatcher.hpp:517
signal_queue< signal_function > signal_queue_
Signal queue for callbacks in set_event.
Definition: dispatcher.hpp:954
signal_queue< signal_message_function > signal_message_queue_
Signal queue for callbacks in set_event_message.
Definition: dispatcher.hpp:969
Helper struct to generate the various event queues.
Definition: dispatcher.hpp:839
void set_mouse_behavior(const mouse_behavior mouse_behavior)
Definition: dispatcher.hpp:778
constexpr bool is_touch_event(const ui_event event)
Helper for catching use error of dispatcher::connect_signal.
Definition: dispatcher.hpp:106
void connect_signal_mouse_left_double_click(dispatcher &dispatcher, const signal_function &signal)
Connects a signal handler for a left mouse button double click.
Definition: dispatcher.cpp:173
An SDL wheel up event.
Definition: handler.hpp:81
An SDL middle mouse button up event.
Definition: handler.hpp:66
signal_queue< signal_touch_function > signal_touch_queue_
Signal queue for callbacks in set_event_touch.
Definition: dispatcher.hpp:963
std::map< ui_event, signal_type< T > > queue
Definition: dispatcher.hpp:845
std::map< hotkey::HOTKEY_COMMAND, hotkey_function > hotkeys_
The registered hotkeys for this dispatcher.
Definition: dispatcher.hpp:981
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:486
An SDL wheel left event.
Definition: handler.hpp:79
bool want_keyboard_input_
Does the dispatcher want to receive keyboard input.
Definition: dispatcher.hpp:951
A mouse motion event for a widget.
Definition: handler.hpp:55
bool connected_
Are we connected to the event handler.
Definition: dispatcher.hpp:978
A left mouse button double click event for a widget.
Definition: handler.hpp:63
A mouse enter event for a widget.
Definition: handler.hpp:54
bool empty(const dispatcher::event_queue_type queue_type) const
Checks whether the queue of a given type is empty.
Definition: dispatcher.hpp:819
Holds a 2D point.
Definition: point.hpp:23
Request to show a tooltip based on the data sent.
Definition: handler.hpp:104
signal_queue< signal_raw_event_function > signal_raw_event_queue_
Signal queue for callbacks in set_raw_event.
Definition: dispatcher.hpp:972
The main application window is activated.
Definition: handler.hpp:48
queue_position
The position where to add a new callback in the signal handler.
Definition: dispatcher.hpp:458
signal_queue< signal_notification_function > signal_notification_queue_
Signal queue for callbacks in set_event_notification.
Definition: dispatcher.hpp:966
An SDL left mouse button up event.
Definition: handler.hpp:59
void connect_signal_pre_key_press(dispatcher &dispatcher, const signal_keyboard_function &signal)
Connects the signal for &#39;snooping&#39; on the keypress.
Definition: dispatcher.cpp:158
std::enable_if_t< is_touch_event(E)> connect_signal(const signal_touch_function &signal, const queue_position position=back_child)
Connect a signal for callback in set_event_touch.
Definition: dispatcher.hpp:579
mouse_behavior
The behavior of the mouse events.
Definition: dispatcher.hpp:758
signal_queue< signal_keyboard_function > signal_keyboard_queue_
Signal queue for callbacks in set_event_keyboard.
Definition: dispatcher.hpp:960
Helper struct to generate the various signal types.
Definition: dispatcher.hpp:800
void disconnect_signal_mouse_left_click(dispatcher &dispatcher, const signal_function &signal)
Disconnects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:168
An SDL text input (commit) event.
Definition: handler.hpp:84
void release_mouse(dispatcher *dispatcher)
Releases a captured mouse.
Definition: handler.cpp:795
constexpr bool is_raw_event_event(const ui_event event)
Helper for catching use error of dispatcher::connect_signal.
Definition: dispatcher.hpp:150
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
Definition: dispatcher.cpp:66
constexpr bool is_notification_event(const ui_event event)
Helper for catching use error of dispatcher::connect_signal.
Definition: dispatcher.hpp:120
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:28
std::function< void(widget &, const ui_event, bool &, bool &, T...)> dispatcher_callback_func
Callback function signature alias template.
Definition: dispatcher.hpp:180
std::enable_if_t< is_touch_event(E)> disconnect_signal(const signal_touch_function &signal, const queue_position position=back_child)
Disconnect a signal for callback in set_event_touch.
Definition: dispatcher.hpp:596
See LEFT_BUTTON_DOWN.
Definition: handler.hpp:74
void release_mouse()
Releases the mouse capture.
Definition: dispatcher.hpp:771
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
A request to close the current window.
Definition: handler.hpp:50
void set_want_keyboard_input(const bool want_keyboard_input)
Definition: dispatcher.hpp:788
An SDL right mouse button up event.
Definition: handler.hpp:73
constexpr bool is_text_input_event(const ui_event event)
Helper for catching use error of dispatcher::connect_signal.
Definition: dispatcher.hpp:160
See LEFT_BUTTON_DOUBLE_CLICK.
Definition: handler.hpp:70
mouse_behavior mouse_behavior_
The mouse behavior for the dispatcher.
Definition: dispatcher.hpp:939
void disconnect_signal(const ui_event event, const queue_position position, const T &signal)
Definition: dispatcher.hpp:875
A left mouse button click event for a widget.
Definition: handler.hpp:62
See LEFT_BUTTON_UP.
Definition: handler.hpp:68
ui_event
The event send to the dispatcher.
Definition: handler.hpp:47
void connect_signal_on_draw(dispatcher &dispatcher, const signal_function &signal)
Connects a signal handler for a callback when the widget is drawn.
Definition: dispatcher.cpp:183
An SDL mouse motion event.
Definition: handler.hpp:53
std::enable_if_t< is_text_input_event(E)> disconnect_signal(const signal_text_input_function &signal, const queue_position position=back_child)
Disconnect a signal for callback in set_text_input.
Definition: dispatcher.hpp:736