The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
dispatcher_private.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2017 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 
18 
19 #include "gui/widgets/widget.hpp"
21 
22 #include <SDL_events.h>
23 
24 #include <boost/mpl/for_each.hpp>
25 #include <boost/range/adaptor/reversed.hpp>
26 
27 namespace gui2
28 {
29 
30 namespace event
31 {
32 
34 {
35 /**
36  * Helper macro to implement the various event_signal functions.
37  *
38  * Implements two helper functions as documented in the macro.
39  *
40  * @param SET The set in which the event type needs to be
41  * eg the @ref gui2::event::set_event or a
42  * similar set defined in that header.
43  * @param FUNCTION The function signature to validate the
44  * implementation function SFINAE against eg the
45  * @ref gui2::event::signal_function or another
46  * one in that header.
47  * @param QUEUE The queue in which the @p event is slotted.
48  */
49 #define IMPLEMENT_EVENT_SIGNAL(SET, FUNCTION, QUEUE) \
50  /** \
51  * Returns the signal structure for a FUNCTION. \
52  * \
53  * There are several functions that only overload the return value, in \
54  * order to do so they use SFINAE. \
55  * \
56  * @tparam F signal_function. \
57  * @param dispatcher The dispatcher whose signal queue is used. \
58  * @param event The event to get the signal for. \
59  * \
60  * @returns The signal of the type \
61  * dispatcher::signal_type<FUNCTION> \
62  */ \
63  template<typename F> \
64  static utils::enable_if_t<std::is_same<F, FUNCTION>::value, dispatcher::signal_type<FUNCTION>>& \
65  event_signal(dispatcher& dispatcher, const ui_event event) \
66  { \
67  return dispatcher.QUEUE.queue[event]; \
68  } \
69  \
70  /** \
71  * Returns the signal structure for a key in SET. \
72  * \
73  * There are several functions that only overload the return value, in \
74  * order to do so they use SFINAE. \
75  * \
76  * @tparam K A key in set_event. \
77  * @param dispatcher The dispatcher whose signal queue is used. \
78  * @param event The event to get the signal for. \
79  * \
80  * @returns The signal of the type \
81  * dispatcher::signal_type<FUNCTION> \
82  */ \
83  template<typename K> \
84  static utils::enable_if_t<boost::mpl::has_key<SET, K>::value, dispatcher::signal_type<FUNCTION>>& \
85  event_signal(dispatcher& dispatcher, const ui_event event) \
86  { \
87  return dispatcher.QUEUE.queue[event]; \
88  }
89 
90 
92 
93 /**
94  * Small helper macro to wrap @ref IMPLEMENT_EVENT_SIGNAL.
95  *
96  * Since the parameters to @ref IMPLEMENT_EVENT_SIGNAL use the same parameters
97  * with a slight difference per type this macro wraps the function by its type.
98  *
99  * @param TYPE The type to wrap for @ref
100  * IMPLEMENT_EVENT_SIGNAL.
101  */
102 #define IMPLEMENT_EVENT_SIGNAL_WRAPPER(TYPE) \
103  IMPLEMENT_EVENT_SIGNAL(set_event_##TYPE, \
104  signal_##TYPE##_function, \
105  signal_##TYPE##_queue_)
106 
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;
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)) {
411  dispatcher_implementation::event_signal<T>(*ritor_widget.first, ritor_widget.second);
412 
413  for(auto& pre_func : signal.pre_child) {
414  pre_func(*dispatcher, ritor_widget.second, handled, halt, std::forward<F>(params)...);
415 
416  if(halt) {
417  assert(handled);
418  break;
419  }
420  }
421 
422  if(handled) {
423  return true;
424  }
425  }
426 
427  /***** ***** ***** Child ***** ***** *****/
428  if(w->has_event(event, dispatcher::child)) {
430  dispatcher_implementation::event_signal<T>(*w, event);
431 
432  for(auto& func : signal.child) {
433  func(*dispatcher, event, handled, halt, std::forward<F>(params)...);
434 
435  if(halt) {
436  assert(handled);
437  break;
438  }
439  }
440 
441  if(handled) {
442  return true;
443  }
444  }
445 
446  /***** ***** ***** Post ***** ***** *****/
447  for(auto& itor_widget : event_chain) {
449  dispatcher_implementation::event_signal<T>(*itor_widget.first, itor_widget.second);
450 
451  for(auto& post_func : signal.post_child) {
452  post_func(*dispatcher, itor_widget.second, handled, halt, std::forward<F>(params)...);
453 
454  if(halt) {
455  assert(handled);
456  break;
457  }
458  }
459 
460  if(handled) {
461  return true;
462  }
463  }
464 
465  /**** ***** ***** Unhandled ***** ***** *****/
466  assert(handled == false);
467  return false;
468 }
469 
470 } // namespace implementation
471 
472 /**
473  * Fires an event.
474  *
475  * A helper to allow the common event firing code to be shared between the
476  * different signal function types.
477  *
478  * @pre d != nullptr
479  * @pre w != nullptr
480  *
481  * @tparam T The signal type of the event to handle.
482  * @tparam F The paramater pack type.
483  *
484  *
485  * @param event The event to fire.
486  * @param d The dispatcher that handles the event.
487  * @param w The widget that should receive the event.
488  * @param params Zero or more additional arguments to pass
489  * to the signal function when it's executed.
490  *
491  * @returns Whether or not the event was handled.
492  */
493 template<typename T, typename... F>
494 inline bool
495 fire_event(const ui_event event, dispatcher* d, widget* w, F&&... params)
496 {
497  assert(d);
498  assert(w);
499 
500  widget* dispatcher_w = dynamic_cast<widget*>(d);
501 
502  std::vector<std::pair<widget*, ui_event>> event_chain =
503  implementation::build_event_chain<T>(event, dispatcher_w, w);
504 
505  return implementation::fire_event<T>(event, event_chain, dispatcher_w, w, std::forward<F>(params)...);
506 }
507 
508 template<ui_event click,
509  ui_event double_click,
510  bool(event_executor::*wants_double_click)() const,
511  typename T,
512  typename... F>
513 inline bool
514 fire_event_double_click(dispatcher* dsp, widget* wgt, F&&... params)
515 {
516  assert(dsp);
517  assert(wgt);
518 
519  std::vector<std::pair<widget*, ui_event>> event_chain;
520  widget* w = wgt;
521  widget* d = dynamic_cast<widget*>(dsp);
522 
523  while(w != d) {
524  w = w->parent();
525  assert(w);
526 
527  if((w->*wants_double_click)()) {
529  event_chain.emplace_back(w, double_click);
530  }
531  } else {
533  event_chain.emplace_back(w, click);
534  }
535  }
536  }
537 
538  if((wgt->*wants_double_click)()) {
539  return implementation::fire_event<T>(
540  double_click, event_chain, d, wgt, std::forward<F>(params)...);
541  } else {
542  return implementation::fire_event<T>(
543  click, event_chain, d, wgt, std::forward<F>(params)...);
544  }
545 }
546 
547 } // namespace event
548 
549 } // namespace gui2
bool fire_event(const ui_event event, dispatcher *d, widget *w, F &&...params)
Fires an event.
bool fire_event(const ui_event event, std::vector< std::pair< widget *, ui_event >> &event_chain, widget *dispatcher, widget *w, F &&...params)
Helper function for fire_event.
#define IMPLEMENT_EVENT_SIGNAL_WRAPPER(TYPE)
Small helper macro to wrap IMPLEMENT_EVENT_SIGNAL.
Base class for event handling.
Definition: dispatcher.hpp:160
#define IMPLEMENT_EVENT_SIGNAL(SET, FUNCTION, QUEUE)
Helper macro to implement the various event_signal functions.
Base class for all widgets.
Definition: widget.hpp:48
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:55
Generic file dialog.
Definition: field-fwd.hpp:22
has_handler(const dispatcher::event_queue_type event_type, dispatcher &dispatcher)
Constructor.
widget * parent()
Definition: widget.cpp:163
bool fire_event_double_click(dispatcher *dsp, widget *wgt, F &&...params)
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:214
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:150
bool oper(ui_event event)
Tests whether a handler for an event is available.
CURSOR_TYPE get()
Definition: cursor.cpp:194
int w
std::function< void(widget &dispatcher, const ui_event event, bool &handled, bool &halt)> signal_function
Callback function signature.
Definition: dispatcher.hpp:44
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.
Helper struct to generate the various signal types.
Definition: dispatcher.hpp:692
static void reverse(lua_State *L, StkId from, StkId to)
Definition: lapi.cpp:193
Contains the implementation details for lexical_cast and shouldn't be used directly.
ui_event
The event send to the dispatcher.
Definition: handler.hpp:55