The Battle for Wesnoth  1.13.4+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 - 2016 by Mark de Wever <[email protected]>
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 #ifndef GUI_WIDGETS_AUXILIARY_EVENT_DISPATCHER_PRIVATE_HPP_INCLUDED
16 #define GUI_WIDGETS_AUXILIARY_EVENT_DISPATCHER_PRIVATE_HPP_INCLUDED
17 
19 
20 #include "gui/widgets/widget.hpp"
21 
22 #include <SDL_events.h>
23 
24 #include <boost/mpl/for_each.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::tset_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::tsignal_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 tsignal_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  * tdispatcher::tsignal<FUNCTION> \
61  */ \
62  template <class F> \
63  static typename boost::enable_if<boost::is_same<F, FUNCTION>, \
64  tdispatcher::tsignal<FUNCTION> >::type& \
65  event_signal(tdispatcher& dispatcher, const tevent 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 tset_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  * tdispatcher::tsignal<FUNCTION> \
82  */ \
83  template <class K> \
84  static typename boost::enable_if<boost::mpl::has_key<SET, K>, \
85  tdispatcher::tsignal<FUNCTION> >::type& \
86  event_signal(tdispatcher& dispatcher, const tevent event) \
87  { \
88  return dispatcher.QUEUE.queue[event]; \
89  }
90 
91 
93 
94 /**
95  * Small helper macro to wrap @ref IMPLEMENT_EVENT_SIGNAL.
96  *
97  * Since the parameters to @ref IMPLEMENT_EVENT_SIGNAL use the same parameters
98  * with a slight difference per type this macro wraps the function by its type.
99  *
100  * @param TYPE The type to wrap for @ref
101  * IMPLEMENT_EVENT_SIGNAL.
102  */
103 #define IMPLEMENT_EVENT_SIGNAL_WRAPPER(TYPE) \
104  IMPLEMENT_EVENT_SIGNAL(tset_event_##TYPE, \
105  tsignal_##TYPE##_function, \
106  signal_##TYPE##_queue_)
107 
110  IMPLEMENT_EVENT_SIGNAL_WRAPPER(notification)
112 
113 #undef IMPLEMENT_EVENT_SIGNAL_WRAPPER
114 #undef IMPLEMENT_EVENT_SIGNAL
115 
116  /**
117  * A helper class to find out whether dispatcher has an handler for a
118  * certain event.
119  */
121  {
122  public:
123  /**
124  * Constructor.
125  *
126  * @param event_type The type of event to look for.
127  * @param dispatcher The dispatcher whose signal queue is used.
128  */
130  tdispatcher& dispatcher)
131  : event_type_(event_type), dispatcher_(dispatcher)
132  {
133  }
134 
135  /**
136  * Tests whether a handler for an event is available.
137  *
138  * It tests for both the event and the event_type send in the
139  * constructor.
140  *
141  * @tparam T A key from an event set used to instantiate
142  * the proper @p event_signal function.
143  * @param event The event to get the signal for.
144  *
145  * @returns Whether or not the handler is found.
146  */
147  // not called operator() to work around a problem in MSVC 2008.
148  template <class T>
150  {
152  && !event_signal<T>(dispatcher_, event).pre_child.empty()) {
153  return true;
154  }
156  && !event_signal<T>(dispatcher_, event).child.empty()) {
157  return true;
158  }
160  && !event_signal<T>(dispatcher_, event).post_child.empty()) {
161  return true;
162  }
163  return false;
164  }
165 
166  private:
169  };
170 };
171 
172 /** Contains the implementation details of the find function. */
173 namespace implementation
174 {
175 
176 /** Specialized class when itor == end */
177 template <bool done = true>
178 struct find
179 {
180  template <typename itor, typename end, typename E, typename F>
181  static bool execute(itor*, end*, E, F)
182  {
183  return false;
184  }
185 };
186 
187 /** Specialized class when itor != end */
188 template <>
189 struct find<false>
190 {
191  template <typename itor, typename end, typename E, typename F>
192  static bool execute(itor*, end*, E event, F functor)
193  {
194  typedef typename boost::mpl::deref<itor>::type item;
195  typedef typename boost::mpl::apply1<boost::mpl::identity<>, item>::type
196  arg;
197 
198  boost::value_initialized<arg> x;
199 
200  if(boost::get(x) == event) {
201  // MSVC 2008 doesn't like operator() here so changed the name.
202  return functor.template oper<item>(event);
203  } else {
204  typedef typename boost::mpl::next<itor>::type titor;
206  static_cast<titor*>(nullptr),
207  static_cast<end*>(nullptr),
208  event,
209  functor);
210  }
211  }
212 };
213 
214 } // namespace implementation
215 
216 /**
217  * Tests whether an event handler is available.
218  *
219  * The code is based on boost::mpl_for_each, which doesn't allow to call a
220  * template function with the dereferred iterator as template parameter.
221  *
222  * The function first tries to match whether the value in the sequence matches
223  * event, once that matched it will execute the functor with the key found as
224  * template parameter and the event as parameter.
225  *
226  * @tparam sequence The sequence to test upon.
227  * @tparam E The value type of the item in the sequence
228  * @tparam F Type of the functor.
229  *
230  * @param event The event to look for.
231  * @param functor The predicate which should is executed if the
232  * event is matched.
233  *
234  * @returns Whether or not the function found a result.
235  */
236 template <typename sequence, typename E, typename F>
237 inline bool find(E event, F functor)
238 {
239  typedef typename boost::mpl::begin<sequence>::type begin;
240  typedef typename boost::mpl::end<sequence>::type end;
241 
243  static_cast<begin*>(nullptr), static_cast<end*>(nullptr), event, functor);
244 }
245 
246 namespace implementation
247 {
248 
249 /*
250  * Small sample to illustrate the effects of the various build_event_chain
251  * functions. Assume the widgets are in an window with the following widgets:
252  *
253  * -----------------------
254  * | dispatcher |
255  * | ------------------- |
256  * | | container 1 | |
257  * | | --------------- | |
258  * | | | container 2 | | |
259  * | | | ----------- | | |
260  * | | | | widget | | | |
261  * | | | ----------- | | |
262  * | | --------------- | |
263  * | ------------------- |
264  * -----------------------
265  *
266  * Note that the firing routine fires the events from:
267  * - pre child for chain.end() - > chain.begin()
268  * - child for widget
269  * - post child for chain.begin() -> chain.end()
270  */
271 
272 /**
273  * Build the event chain.
274  *
275  * The event chain is a chain of events starting from the first parent of the
276  * widget until (and including) the wanted parent. For all these widgets it
277  * will be tested whether they have either a pre or post handler for the event.
278  * This ways there will be list of widgets to try to send the events to.
279  * If there's no line from widget to parent the result is undefined.
280  * (If widget == dispatcher the result will always be empty.)
281  *
282  * @pre dispatcher != nullptr
283  * @pre widget != nullptr
284  *
285  * @param event The event to test.
286  * @param dispatcher The final widget to test, this is also the
287  * dispatcher the sends the event.
288  * @param widget The widget should parent(s) to check.
289  *
290  * @returns The list of widgets with a handler.
291  * The order will be (assuming all have a
292  * handler):
293  * * container 2
294  * * container 1
295  * * dispatcher
296  */
297 template <class T>
298 inline std::vector<std::pair<twidget*, tevent> >
299 build_event_chain(const tevent event, twidget* dispatcher, twidget* widget)
300 {
301  assert(dispatcher);
302  assert(widget);
303 
304  std::vector<std::pair<twidget*, tevent> > result;
305 
306  while(widget != dispatcher) {
307  widget = widget->parent();
308  assert(widget);
309 
310  if(widget->has_event(event,
312  | tdispatcher::post))) {
313 
314  result.push_back(std::make_pair(widget, event));
315  }
316  }
317 
318  return result;
319 }
320 
321 /**
322  * Build the event chain for tsignal_notification_function.
323  *
324  * The notification is only send to the receiver it returns an empty chain.
325  * Since the pre and post queues are unused, it validates whether they are
326  * empty (using asserts).
327  *
328  * @returns An empty vector.
329  */
330 template <>
331 inline std::vector<std::pair<twidget*, tevent> >
333  twidget* dispatcher,
334  twidget* widget)
335 {
336  assert(dispatcher);
337  assert(widget);
338 
339  assert(!widget->has_event(event,
341  | tdispatcher::post)));
342 
343  return std::vector<std::pair<twidget*, tevent> >();
344 }
345 
346 #ifdef _MSC_VER
347 #pragma warning(push)
348 #pragma warning(disable : 4706)
349 #endif
350 /**
351  * Build the event chain for tsignal_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<twidget*, tevent> >
370  twidget* dispatcher,
371  twidget* widget)
372 {
373  assert(dispatcher);
374  assert(widget);
375  assert(widget == dispatcher);
376 
377  std::vector<std::pair<twidget*, tevent> > result;
378 
379  /* We only should add the parents of the widget to the chain. */
380  while((widget = widget->parent())) {
381  assert(widget);
382 
383  if(widget->has_event(event,
385  | tdispatcher::post))) {
386 
387  result.insert(result.begin(), std::make_pair(widget, event));
388  }
389  }
390 
391  return result;
392 }
393 #ifdef _MSC_VER
394 #pragma warning(pop)
395 #endif
396 
397 /**
398  * Helper function for fire_event.
399  *
400  * This is called with the same parameters as fire_event except for the
401  * event_chain, which contains the widgets with the events to call for them.
402  */
403 template <class T, class F>
404 inline bool fire_event(const tevent event,
405  std::vector<std::pair<twidget*, tevent> >& event_chain,
406  twidget* dispatcher,
407  twidget* widget,
408  F functor)
409 {
410  bool handled = false;
411  bool halt = false;
412 
413  /***** ***** ***** Pre ***** ***** *****/
414  for(std::vector<std::pair<twidget*, tevent> >::reverse_iterator ritor_widget
415  = event_chain.rbegin();
416  ritor_widget != event_chain.rend();
417  ++ritor_widget) {
418 
420  = tdispatcher_implementation::event_signal<T>(
421  *ritor_widget->first, ritor_widget->second);
422 
423  for(typename std::vector<T>::iterator itor = signal.pre_child.begin();
424  itor != signal.pre_child.end();
425  ++itor) {
426 
427  functor(*itor, *dispatcher, ritor_widget->second, handled, halt);
428  if(halt) {
429  assert(handled);
430  break;
431  }
432  }
433 
434  if(handled) {
435  return true;
436  }
437  }
438 
439  /***** ***** ***** Child ***** ***** *****/
440  if(widget->has_event(event, tdispatcher::child)) {
441 
443  = tdispatcher_implementation::event_signal<T>(*widget, event);
444 
445  for(typename std::vector<T>::iterator itor = signal.child.begin();
446  itor != signal.child.end();
447  ++itor) {
448 
449  functor(*itor, *dispatcher, event, handled, halt);
450 
451  if(halt) {
452  assert(handled);
453  break;
454  }
455  }
456 
457  if(handled) {
458  return true;
459  }
460  }
461 
462  /***** ***** ***** Post ***** ***** *****/
463  for(std::vector<std::pair<twidget*, tevent> >::iterator itor_widget
464  = event_chain.begin();
465  itor_widget != event_chain.end();
466  ++itor_widget) {
467 
469  = tdispatcher_implementation::event_signal<T>(
470  *itor_widget->first, itor_widget->second);
471 
472  for(typename std::vector<T>::iterator itor = signal.post_child.begin();
473  itor != signal.post_child.end();
474  ++itor) {
475 
476  functor(*itor, *dispatcher, itor_widget->second, handled, halt);
477  if(halt) {
478  assert(handled);
479  break;
480  }
481  }
482 
483  if(handled) {
484  return true;
485  }
486  }
487 
488  /**** ***** ***** Unhandled ***** ***** *****/
489  assert(handled == false);
490  return false;
491 }
492 
493 } // namespace implementation
494 
495 /**
496  * Fires an event.
497  *
498  * A helper to allow the common event firing code to be shared between the
499  * different signal function types.
500  *
501  * @pre dispatcher != nullptr
502  * @pre widget != nullptr
503  *
504  * @tparam T The signal type of the event to handle.
505  * @tparam F The type of the functor.
506  *
507  *
508  * @param event The event to fire.
509  * @param dispatcher The dispatcher that handles the event.
510  * @param widget The widget that should receive the event.
511  * @param functor The functor to execute the actual event.
512  * Since some functions need different
513  * parameters this functor stores them before
514  * firing the event.
515  *
516  * @returns Whether or not the event was handled.
517  */
518 template <class T, class F>
519 inline bool
520 fire_event(const tevent event, twidget* dispatcher, twidget* widget, F functor)
521 {
522  assert(dispatcher);
523  assert(widget);
524 
525  std::vector<std::pair<twidget*, tevent> > event_chain
526  = implementation::build_event_chain<T>(event, dispatcher, widget);
527 
528  return implementation::fire_event<T>(
529  event, event_chain, dispatcher, widget, functor);
530 }
531 
532 template <tevent click,
533  tevent double_click,
534  bool (tevent_executor::*wants_double_click)() const,
535  class T,
536  class F>
537 inline bool
539 {
540  assert(dispatcher);
541  assert(widget);
542 
543  std::vector<std::pair<twidget*, tevent> > event_chain;
544  twidget* w = widget;
545  while(w != dispatcher) {
546  w = w->parent();
547  assert(w);
548 
549  if((w->*wants_double_click)()) {
550 
551  if(w->has_event(double_click,
553  | tdispatcher::post))) {
554 
555  event_chain.push_back(std::make_pair(w, double_click));
556  }
557  } else {
558  if(w->has_event(click,
560  | tdispatcher::post))) {
561 
562  event_chain.push_back(std::make_pair(w, click));
563  }
564  }
565  }
566 
567  if((widget->*wants_double_click)()) {
568  return implementation::fire_event<T>(
569  double_click, event_chain, dispatcher, widget, functor);
570  } else {
571  return implementation::fire_event<T>(
572  click, event_chain, dispatcher, widget, functor);
573  }
574 }
575 
576 } // namespace event
577 
578 } // namespace gui2
579 
580 #endif
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 > > tset_event
Helper for catching use error of tdispatcher::connect_signal.
Definition: handler.hpp:209
#define IMPLEMENT_EVENT_SIGNAL_WRAPPER(TYPE)
Small helper macro to wrap IMPLEMENT_EVENT_SIGNAL.
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
itor second functor(surf, f[1])
#define IMPLEMENT_EVENT_SIGNAL(SET, FUNCTION, QUEUE)
Helper macro to implement the various event_signal functions.
static bool execute(itor *, end *, E event, F functor)
Event execution calls.
Specialized class when itor == end.
std::vector< std::pair< twidget *, tevent > > build_event_chain< tsignal_message_function >(const tevent event, twidget *dispatcher, twidget *widget)
Build the event chain for tsignal_message_function.
Base class for event handling.
Definition: dispatcher.hpp:122
A class inherited from ttext_box that displays its input as stars.
Definition: field-fwd.hpp:23
twidget * parent()
Definition: widget.cpp:155
GLuint GLuint end
Definition: glew.h:1221
GLuint64EXT * result
Definition: glew.h:10727
GLubyte GLubyte GLubyte GLubyte w
Definition: glew.h:1858
thas_handler(const tdispatcher::tevent_type event_type, tdispatcher &dispatcher)
Constructor.
std::function< void(tdispatcher &dispatcher, const tevent event, bool &handled, bool &halt)> tsignal_function
Callback function signature.
Definition: dispatcher.hpp:40
bool fire_event_double_click(twidget *dispatcher, twidget *widget, F functor)
tevent
The event send to the dispatcher.
Definition: handler.hpp:54
Helper struct to generate the various signal types.
Definition: dispatcher.hpp:518
bool click(int mousex, int mousey)
Definition: tooltips.cpp:216
std::vector< std::pair< twidget *, tevent > > build_event_chain(const tevent event, twidget *dispatcher, twidget *widget)
Build the event chain.
A helper class to find out whether dispatcher has an handler for a certain event. ...
std::map< std::string, tfilter >::iterator itor
Definition: filter.cpp:199
CURSOR_TYPE get()
Definition: cursor.cpp:194
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
bool fire_event(const tevent event, std::vector< std::pair< twidget *, tevent > > &event_chain, twidget *dispatcher, twidget *widget, F functor)
Helper function for fire_event.
bool fire_event(const tevent event, twidget *dispatcher, twidget *widget, F functor)
Fires an event.
std::vector< std::pair< twidget *, tevent > > build_event_chain< tsignal_notification_function >(const tevent event, twidget *dispatcher, twidget *widget)
Build the event chain for tsignal_notification_function.
static bool execute(itor *, end *, E, F)
bool has_event(const tevent event, const tevent_type event_type)
Definition: dispatcher.cpp:56
bool find(E event, F functor)
Tests whether an event handler is available.
cl_event event
Definition: glew.h:3070
Base class for all widgets.
Definition: widget.hpp:49
bool oper(tevent event)
Tests whether a handler for an event is available.
GLsizei GLenum GLuint GLuint GLsizei char * message
Definition: glew.h:2499
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
Contains the implementation details for lexical_cast and shouldn't be used directly.