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