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