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