The Battle for Wesnoth  1.15.0-dev
dispatcher_private.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2018 by Mark de Wever <koraq@xs4all.nl>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
18 
19 #include "gui/widgets/widget.hpp"
20 
21 #include <SDL_events.h>
22 
23 #include <boost/mpl/for_each.hpp>
24 #include <boost/range/adaptor/reversed.hpp>
25 
26 namespace gui2
27 {
28 
29 namespace event
30 {
31 
33 {
34 /**
35  * Helper macro to implement the various event_signal functions.
36  *
37  * Implements two helper functions as documented in the macro.
38  *
39  * @param SET The set in which the event type needs to be
40  * eg the @ref gui2::event::set_event or a
41  * similar set defined in that header.
42  * @param FUNCTION The function signature to validate the
43  * implementation function SFINAE against eg the
44  * @ref gui2::event::signal_function or another
45  * one in that header.
46  * @param QUEUE The queue in which the @p event is slotted.
47  */
48 #define IMPLEMENT_EVENT_SIGNAL(SET, FUNCTION, QUEUE) \
49  /** \
50  * Returns the signal structure for a FUNCTION. \
51  * \
52  * There are several functions that only overload the return value, in \
53  * order to do so they use SFINAE. \
54  * \
55  * @tparam F signal_function. \
56  * @param dispatcher The dispatcher whose signal queue is used. \
57  * @param event The event to get the signal for. \
58  * \
59  * @returns The signal of the type \
60  * dispatcher::signal_type<FUNCTION> \
61  */ \
62  template<typename F> \
63  static std::enable_if_t<std::is_same<F, FUNCTION>::value, dispatcher::signal_type<FUNCTION>>& \
64  event_signal(dispatcher& dispatcher, const ui_event event) \
65  { \
66  return dispatcher.QUEUE.queue[event]; \
67  } \
68  \
69  /** \
70  * Returns the signal structure for a key in SET. \
71  * \
72  * There are several functions that only overload the return value, in \
73  * order to do so they use SFINAE. \
74  * \
75  * @tparam K A key in set_event. \
76  * @param dispatcher The dispatcher whose signal queue is used. \
77  * @param event The event to get the signal for. \
78  * \
79  * @returns The signal of the type \
80  * dispatcher::signal_type<FUNCTION> \
81  */ \
82  template<typename K> \
83  static std::enable_if_t<boost::mpl::has_key<SET, K>::value, dispatcher::signal_type<FUNCTION>>& \
84  event_signal(dispatcher& dispatcher, const ui_event event) \
85  { \
86  return dispatcher.QUEUE.queue[event]; \
87  }
88 
89 
91 
92 /**
93  * Small helper macro to wrap @ref IMPLEMENT_EVENT_SIGNAL.
94  *
95  * Since the parameters to @ref IMPLEMENT_EVENT_SIGNAL use the same parameters
96  * with a slight difference per type this macro wraps the function by its type.
97  *
98  * @param TYPE The type to wrap for @ref
99  * IMPLEMENT_EVENT_SIGNAL.
100  */
101 #define IMPLEMENT_EVENT_SIGNAL_WRAPPER(TYPE) \
102  IMPLEMENT_EVENT_SIGNAL(set_event_##TYPE, \
103  signal_##TYPE##_function, \
104  signal_##TYPE##_queue_)
105 
108  IMPLEMENT_EVENT_SIGNAL_WRAPPER(touch_motion)
109  IMPLEMENT_EVENT_SIGNAL_WRAPPER(touch_gesture)
110  IMPLEMENT_EVENT_SIGNAL_WRAPPER(notification)
114 
115 #undef IMPLEMENT_EVENT_SIGNAL_WRAPPER
116 #undef IMPLEMENT_EVENT_SIGNAL
117 
118  /**
119  * A helper class to find out whether dispatcher has an handler for a
120  * certain event.
121  */
123  {
124  public:
125  /**
126  * Constructor.
127  *
128  * @param event_type The type of event to look for.
129  * @param dispatcher The dispatcher whose signal queue is used.
130  */
132  : event_type_(event_type), dispatcher_(dispatcher)
133  {
134  }
135 
136  /**
137  * Tests whether a handler for an event is available.
138  *
139  * It tests for both the event and the event_type send in the
140  * constructor.
141  *
142  * @tparam T A key from an event set used to instantiate
143  * the proper @p event_signal function.
144  * @param event The event to get the signal for.
145  *
146  * @returns Whether or not the handler is found.
147  */
148  // not called operator() to work around a problem in MSVC
149  // (known to affect all versions up to 2015)
150  template<typename T>
151  bool oper(ui_event event)
152  {
154  && !event_signal<T>(dispatcher_, event).pre_child.empty()) {
155  return true;
156  }
157 
159  && !event_signal<T>(dispatcher_, event).child.empty()) {
160  return true;
161  }
162 
164  && !event_signal<T>(dispatcher_, event).post_child.empty()) {
165  return true;
166  }
167 
168  return false;
169  }
170 
171  private:
174  };
175 };
176 
177 /** Contains the implementation details of the find function. */
178 namespace implementation
179 {
180 
181 /** Specialized class when itor == end */
182 template<bool done = true>
183 struct find
184 {
185  template<typename itor, typename end, typename E, typename F>
186  static bool execute(itor*, end*, E, F)
187  {
188  return false;
189  }
190 };
191 
192 /** Specialized class when itor != end */
193 template<>
194 struct find<false>
195 {
196  template<typename itor, typename end, typename E, typename F>
197  static bool execute(itor*, end*, E event, F functor)
198  {
199  typedef typename boost::mpl::deref<itor>::type item;
200  typedef typename boost::mpl::apply1<boost::mpl::identity<>, item>::type arg;
201 
202  boost::value_initialized<arg> x;
203 
204  if(boost::get(x) == event) {
205  return functor.template oper<item>(event);
206  } else {
207  typedef typename boost::mpl::next<itor>::type itor_t;
208  return find<std::is_same<itor_t, end>::value>::execute(
209  static_cast<itor_t*>(nullptr),
210  static_cast<end*>(nullptr),
211  event,
212  functor);
213  }
214  }
215 };
216 
217 } // namespace implementation
218 
219 /**
220  * Tests whether an event handler is available.
221  *
222  * The code is based on boost::mpl_for_each, which doesn't allow to call a
223  * template function with the dereferred iterator as template parameter.
224  *
225  * The function first tries to match whether the value in the sequence matches
226  * event, once that matched it will execute the functor with the key found as
227  * template parameter and the event as parameter.
228  *
229  * @tparam sequence The sequence to test upon.
230  * @tparam E The value type of the item in the sequence
231  * @tparam F Type of the functor.
232  *
233  * @param event The event to look for.
234  * @param functor The predicate which should is executed if the
235  * event is matched.
236  *
237  * @returns Whether or not the function found a result.
238  */
239 template<typename sequence, typename E, typename F>
240 inline bool find(E event, F functor)
241 {
242  typedef typename boost::mpl::begin<sequence>::type begin;
243  typedef typename boost::mpl::end<sequence>::type end;
244 
246  static_cast<begin*>(nullptr), static_cast<end*>(nullptr), event, functor);
247 }
248 
249 namespace implementation
250 {
251 
252 /*
253  * Small sample to illustrate the effects of the various build_event_chain
254  * functions. Assume the widgets are in an window with the following widgets:
255  *
256  * -----------------------
257  * | dispatcher |
258  * | ------------------- |
259  * | | container 1 | |
260  * | | --------------- | |
261  * | | | container 2 | | |
262  * | | | ----------- | | |
263  * | | | | widget | | | |
264  * | | | ----------- | | |
265  * | | --------------- | |
266  * | ------------------- |
267  * -----------------------
268  *
269  * Note that the firing routine fires the events from:
270  * - pre child for chain.end() - > chain.begin()
271  * - child for widget
272  * - post child for chain.begin() -> chain.end()
273  */
274 
275 /**
276  * Build the event chain.
277  *
278  * The event chain is a chain of events starting from the first parent of the
279  * widget until (and including) the wanted parent. For all these widgets it
280  * will be tested whether they have either a pre or post handler for the event.
281  * This ways there will be list of widgets to try to send the events to.
282  * If there's no line from widget to parent the result is undefined.
283  * (If widget == dispatcher the result will always be empty.)
284  *
285  * @pre dispatcher != nullptr
286  * @pre widget != nullptr
287  *
288  * @param event The event to test.
289  * @param dispatcher The final widget to test, this is also the
290  * dispatcher the sends the event.
291  * @param w The widget should parent(s) to check.
292  *
293  * @returns The list of widgets with a handler.
294  * The order will be (assuming all have a
295  * handler):
296  * * container 2
297  * * container 1
298  * * dispatcher
299  */
300 template<typename T>
301 inline std::vector<std::pair<widget*, ui_event>>
303 {
304  assert(dispatcher);
305  assert(w);
306 
307  std::vector<std::pair<widget*, ui_event>> result;
308 
309  while(true) {
311  result.emplace_back(w, event);
312  }
313 
314  if(w == dispatcher) {
315  break;
316  }
317 
318  w = w->parent();
319  assert(w);
320  }
321 
322  return result;
323 }
324 
325 /**
326  * Build the event chain for signal_notification_function.
327  *
328  * The notification is only send to the receiver it returns an empty chain.
329  * Since the pre and post queues are unused, it validates whether they are
330  * empty (using asserts).
331  *
332  * @returns An empty vector.
333  */
334 template<>
335 inline std::vector<std::pair<widget*, ui_event>>
337 {
338  assert(dispatcher);
339  assert(w);
340 
341  assert(!w->has_event(event, dispatcher::event_queue_type(dispatcher::pre | dispatcher::post)));
342 
343  return std::vector<std::pair<widget*, ui_event>>();
344 }
345 
346 #ifdef _MSC_VER
347 #pragma warning(push)
348 #pragma warning(disable : 4706)
349 #endif
350 /**
351  * Build the event chain for signal_message_function.
352  *
353  * This function expects that the widget sending it is also the receiver. This
354  * assumption might change, but is valid for now. The function doesn't build an
355  * event chain from @p dispatcher to @p widget but from @p widget to its
356  * toplevel item (the first one without a parent) which we call @p window.
357  *
358  * @pre dispatcher == widget
359  *
360  * @returns The list of widgets with a handler.
361  * The order will be (assuming all have a
362  * handler):
363  * * window
364  * * container 1
365  * * container 2
366  */
367 template<>
368 inline std::vector<std::pair<widget*, ui_event>>
370 {
371  assert(dispatcher);
372  assert(w);
373  assert(w == dispatcher);
374 
375  std::vector<std::pair<widget*, ui_event>> result;
376 
377  /* We only should add the parents of the widget to the chain. */
378  while((w = w->parent())) {
379  assert(w);
380 
382  result.emplace(result.begin(), w, event);
383  }
384  }
385 
386  return result;
387 }
388 #ifdef _MSC_VER
389 #pragma warning(pop)
390 #endif
391 
392 /**
393  * Helper function for fire_event.
394  *
395  * This is called with the same parameters as fire_event except for the
396  * event_chain, which contains the widgets with the events to call for them.
397  */
398 template<typename T, typename... F>
399 inline bool fire_event(const ui_event event,
400  std::vector<std::pair<widget*, ui_event>>& event_chain,
401  widget* dispatcher,
402  widget* w,
403  F&&... params)
404 {
405  bool handled = false;
406  bool halt = false;
407 
408  /***** ***** ***** Pre ***** ***** *****/
409  for(auto& ritor_widget : boost::adaptors::reverse(event_chain)) {
410  auto& signal = dispatcher_implementation::event_signal<T>(*ritor_widget.first, ritor_widget.second);
411 
412  for(auto& pre_func : signal.pre_child) {
413  pre_func(*dispatcher, ritor_widget.second, handled, halt, std::forward<F>(params)...);
414 
415  if(halt) {
416  assert(handled);
417  break;
418  }
419  }
420 
421  if(handled) {
422  return true;
423  }
424  }
425 
426  /***** ***** ***** Child ***** ***** *****/
427  if(w->has_event(event, dispatcher::child)) {
428  auto& signal = dispatcher_implementation::event_signal<T>(*w, event);
429 
430  for(auto& func : signal.child) {
431  func(*dispatcher, event, handled, halt, std::forward<F>(params)...);
432 
433  if(halt) {
434  assert(handled);
435  break;
436  }
437  }
438 
439  if(handled) {
440  return true;
441  }
442  }
443 
444  /***** ***** ***** Post ***** ***** *****/
445  for(auto& itor_widget : event_chain) {
446  auto& signal = dispatcher_implementation::event_signal<T>(*itor_widget.first, itor_widget.second);
447 
448  for(auto& post_func : signal.post_child) {
449  post_func(*dispatcher, itor_widget.second, handled, halt, std::forward<F>(params)...);
450 
451  if(halt) {
452  assert(handled);
453  break;
454  }
455  }
456 
457  if(handled) {
458  return true;
459  }
460  }
461 
462  /**** ***** ***** Unhandled ***** ***** *****/
463  assert(handled == false);
464  return false;
465 }
466 
467 } // namespace implementation
468 
469 /**
470  * Fires an event.
471  *
472  * A helper to allow the common event firing code to be shared between the
473  * different signal function types.
474  *
475  * @pre d != nullptr
476  * @pre w != nullptr
477  *
478  * @tparam T The signal type of the event to handle.
479  * @tparam F The parameter pack type.
480  *
481  *
482  * @param event The event to fire.
483  * @param d The dispatcher that handles the event.
484  * @param w The widget that should receive the event.
485  * @param params Zero or more additional arguments to pass
486  * to the signal function when it's executed.
487  *
488  * @returns Whether or not the event was handled.
489  */
490 template<typename T, typename... F>
491 inline bool
492 fire_event(const ui_event event, dispatcher* d, widget* w, F&&... params)
493 {
494  assert(d);
495  assert(w);
496 
497  widget* dispatcher_w = dynamic_cast<widget*>(d);
498 
499  std::vector<std::pair<widget*, ui_event>> event_chain =
500  implementation::build_event_chain<T>(event, dispatcher_w, w);
501 
502  return implementation::fire_event<T>(event, event_chain, dispatcher_w, w, std::forward<F>(params)...);
503 }
504 
505 template<ui_event click,
506  ui_event double_click,
507  bool(event_executor::*wants_double_click)() const,
508  typename T,
509  typename... F>
510 inline bool
511 fire_event_double_click(dispatcher* dsp, widget* wgt, F&&... params)
512 {
513  assert(dsp);
514  assert(wgt);
515 
516  std::vector<std::pair<widget*, ui_event>> event_chain;
517  widget* w = wgt;
518  widget* d = dynamic_cast<widget*>(dsp);
519 
520  while(w != d) {
521  w = w->parent();
522  assert(w);
523 
524  if((w->*wants_double_click)()) {
526  event_chain.emplace_back(w, double_click);
527  }
528  } else {
530  event_chain.emplace_back(w, click);
531  }
532  }
533  }
534 
535  if((wgt->*wants_double_click)()) {
536  return implementation::fire_event<T>(
537  double_click, event_chain, d, wgt, std::forward<F>(params)...);
538  } else {
539  return implementation::fire_event<T>(
540  click, event_chain, d, wgt, std::forward<F>(params)...);
541  }
542 }
543 
544 } // namespace event
545 
546 } // namespace gui2
#define IMPLEMENT_EVENT_SIGNAL_WRAPPER(TYPE)
Small helper macro to wrap IMPLEMENT_EVENT_SIGNAL.
Base class for event handling.
Definition: dispatcher.hpp:172
bool fire_event_double_click(dispatcher *dsp, widget *wgt, F &&... params)
#define IMPLEMENT_EVENT_SIGNAL(SET, FUNCTION, QUEUE)
Helper macro to implement the various event_signal functions.
Base class for all widgets.
Definition: widget.hpp:47
std::vector< std::pair< widget *, ui_event > > build_event_chain(const ui_event event, widget *dispatcher, widget *w)
Build the event chain.
static bool execute(itor *, end *, E event, F functor)
#define d
Specialized class when itor == end.
bool has_event(const ui_event event, const event_queue_type event_type)
Definition: dispatcher.cpp:57
Generic file dialog.
Definition: field-fwd.hpp:22
bool fire_event(const ui_event event, dispatcher *d, widget *w, F &&... params)
Fires an event.
has_handler(const dispatcher::event_queue_type event_type, dispatcher &dispatcher)
Constructor.
widget * parent()
Definition: widget.cpp:157
Event execution calls.
std::vector< std::pair< widget *, ui_event > > build_event_chain< signal_notification_function >(const ui_event event, widget *dispatcher, widget *w)
Build the event chain for signal_notification_function.
bool click(int mousex, int mousey)
Definition: tooltips.cpp:211
std::vector< std::pair< widget *, ui_event > > build_event_chain< signal_message_function >(const ui_event event, widget *dispatcher, widget *w)
Build the event chain for signal_message_function.
boost::mpl::set< boost::mpl::int_< DRAW >, boost::mpl::int_< CLOSE_WINDOW >, boost::mpl::int_< MOUSE_ENTER >, boost::mpl::int_< MOUSE_LEAVE >, boost::mpl::int_< LEFT_BUTTON_DOWN >, boost::mpl::int_< LEFT_BUTTON_UP >, boost::mpl::int_< LEFT_BUTTON_CLICK >, boost::mpl::int_< LEFT_BUTTON_DOUBLE_CLICK >, boost::mpl::int_< MIDDLE_BUTTON_DOWN >, boost::mpl::int_< MIDDLE_BUTTON_UP >, boost::mpl::int_< MIDDLE_BUTTON_CLICK >, boost::mpl::int_< MIDDLE_BUTTON_DOUBLE_CLICK >, boost::mpl::int_< RIGHT_BUTTON_DOWN >, boost::mpl::int_< RIGHT_BUTTON_UP >, boost::mpl::int_< RIGHT_BUTTON_CLICK >, boost::mpl::int_< RIGHT_BUTTON_DOUBLE_CLICK > > set_event
Helper for catching use error of dispatcher::connect_signal.
Definition: handler.hpp:151
bool oper(ui_event event)
Tests whether a handler for an event is available.
CURSOR_TYPE get()
Definition: cursor.cpp:213
int w
std::function< void(widget &dispatcher, const ui_event event, bool &handled, bool &halt)> signal_function
Callback function signature.
Definition: dispatcher.hpp:42
A helper class to find out whether dispatcher has an handler for a certain event. ...
static bool execute(itor *, end *, E, F)
bool find(E event, F functor)
Tests whether an event handler is available.
static void reverse(lua_State *L, StkId from, StkId to)
Definition: lapi.cpp:193
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
ui_event
The event send to the dispatcher.
Definition: handler.hpp:55