gui/auxiliary/event/dispatcher_private.hpp

Go to the documentation of this file.
00001 /* $Id: dispatcher_private.hpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2009 - 2012 by Mark de Wever <koraq@xs4all.nl>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 #ifndef GUI_WIDGETS_AUXILIARY_EVENT_DISPATCHER_PRIVATE_HPP_INCLUDED
00017 #define GUI_WIDGETS_AUXILIARY_EVENT_DISPATCHER_PRIVATE_HPP_INCLUDED
00018 
00019 #include "gui/auxiliary/event/dispatcher.hpp"
00020 
00021 #include "gui/widgets/widget.hpp"
00022 
00023 #include <boost/mpl/for_each.hpp>
00024 
00025 namespace gui2 {
00026 
00027 namespace event {
00028 
00029 struct tdispatcher_implementation
00030 {
00031 /**
00032  * Helper macro to implement the various event_signal functions.
00033  *
00034  * Implements two helper functions as documented in the macro.
00035  *
00036  * @param SET                     The set in which the event type needs to be
00037  *                                eg the @ref gui2::event::tset_event or a
00038  *                                similar set defined in that header.
00039  * @param FUNCTION                The function signature to validate the
00040  *                                implementation function SFINAE against eg the
00041  *                                @ref gui2::event::tsignal_function or another
00042  *                                one in that header.
00043  * @param QUEUE                   The queue in which the @p event is slotted.
00044  */
00045 #define IMPLEMENT_EVENT_SIGNAL(SET, FUNCTION, QUEUE)                          \
00046     /**                                                                       \
00047      * Returns the signal structure for a FUNCTION.                           \
00048      *                                                                        \
00049      * There are several functions that only overload the return value, in    \
00050      * order to do so they use SFINAE.                                        \
00051      *                                                                        \
00052      * @tparam F                  tsignal_function.                           \
00053      * @param dispatcher          The dispatcher whose signal queue is used.  \
00054      * @param event               The event to get the signal for.            \
00055      *                                                                        \
00056      * @returns                   The signal of the type                      \
00057      *                            tdispatcher::tsignal<FUNCTION>              \
00058      */                                                                       \
00059     template<class F>                                                         \
00060     static typename boost::enable_if<                                         \
00061               boost::is_same<F, FUNCTION>                                     \
00062             , tdispatcher::tsignal<FUNCTION>                                  \
00063             >::type&                                                          \
00064     event_signal(tdispatcher& dispatcher, const tevent event)                 \
00065     {                                                                         \
00066         return dispatcher.QUEUE.queue[event];                                 \
00067     }                                                                         \
00068                                                                               \
00069     /**                                                                       \
00070      * Returns the signal structure for a key in SET.                         \
00071      *                                                                        \
00072      * There are several functions that only overload the return value, in    \
00073      * order to do so they use SFINAE.                                        \
00074      *                                                                        \
00075      * @tparam K                  A key in tset_event.                        \
00076      * @param dispatcher          The dispatcher whose signal queue is used.  \
00077      * @param event               The event to get the signal for.            \
00078      *                                                                        \
00079      * @returns                   The signal of the type                      \
00080      *                            tdispatcher::tsignal<FUNCTION>              \
00081      */                                                                       \
00082     template<class K>                                                         \
00083     static typename boost::enable_if<                                         \
00084               boost::mpl::has_key<SET, K>                                     \
00085             , tdispatcher::tsignal<FUNCTION>                                  \
00086             >::type&                                                          \
00087     event_signal(tdispatcher& dispatcher, const tevent event)                 \
00088     {                                                                         \
00089         return dispatcher.QUEUE.queue[event];                                 \
00090     }                                                                         \
00091 
00092 
00093     IMPLEMENT_EVENT_SIGNAL(tset_event, tsignal_function, signal_queue_)
00094 
00095 /**
00096  * Small helper macro to wrap @ref IMPLEMENT_EVENT_SIGNAL.
00097  *
00098  * Since the parameters to @ref IMPLEMENT_EVENT_SIGNAL use the same parameters
00099  * with a slight difference per type this macro wraps the function by its type.
00100  *
00101  * @param TYPE                    The type to wrap for @ref
00102  *                                IMPLEMENT_EVENT_SIGNAL.
00103  */
00104 #define IMPLEMENT_EVENT_SIGNAL_WRAPPER(TYPE)                                  \
00105     IMPLEMENT_EVENT_SIGNAL(tset_event_##TYPE                                  \
00106             , tsignal_##TYPE##_function                                       \
00107             , signal_##TYPE##_queue_)                                         \
00108 
00109     IMPLEMENT_EVENT_SIGNAL_WRAPPER(mouse)
00110     IMPLEMENT_EVENT_SIGNAL_WRAPPER(keyboard)
00111     IMPLEMENT_EVENT_SIGNAL_WRAPPER(notification)
00112     IMPLEMENT_EVENT_SIGNAL_WRAPPER(message)
00113 
00114 #undef IMPLEMENT_EVENT_SIGNAL_WRAPPER
00115 #undef IMPLEMENT_EVENT_SIGNAL
00116 
00117     /**
00118      * A helper class to find out whether dispatcher has an handler for a
00119      * certain event.
00120      */
00121     class thas_handler
00122     {
00123     public:
00124         /**
00125          * Constructor.
00126          *
00127          * @param event_type      The type of event to look for.
00128         * @param dispatcher      The dispatcher whose signal queue is used.
00129          */
00130         thas_handler(const tdispatcher::tevent_type event_type
00131                 , tdispatcher& dispatcher)
00132             : event_type_(event_type)
00133             , dispatcher_(dispatcher)
00134         {}
00135 
00136         /**
00137          * Tests whether a handler for an event is available.
00138          *
00139          * It tests for both the event and the event_type send in the
00140          * constructor.
00141          *
00142          * @tparam T              A key from an event set used to instanciate
00143          *                        the proper @p event_signal function.
00144         * @param event           The event to get the signal for.
00145          *
00146          * @returns               Whether or not the handler is found.
00147          */
00148         // not called operator() to work around a problem in MSVC 2008.
00149         template<class T>
00150         bool oper(tevent event)
00151         {
00152             if((event_type_ & tdispatcher::pre)
00153                     && !event_signal<T>(dispatcher_, event).pre_child.empty()) {
00154                 return true;
00155             }
00156             if((event_type_ & tdispatcher::child)
00157                     && !event_signal<T>(dispatcher_, event).child.empty()) {
00158                 return true;
00159             }
00160             if((event_type_ & tdispatcher::post)
00161                     && !event_signal<T>(dispatcher_, event).post_child.empty()){
00162                 return true;
00163             }
00164             return false;
00165         }
00166 
00167     private:
00168         tdispatcher::tevent_type event_type_;
00169         tdispatcher& dispatcher_;
00170     };
00171 };
00172 
00173 /** Contains the implementation details of the find function. */
00174 namespace implementation {
00175 
00176 /** Specialized class when itor == end */
00177 template<bool done = true>
00178 struct find
00179 {
00180     template<
00181           typename itor
00182         , typename end
00183         , typename E
00184         , typename F
00185         >
00186     static bool execute(
00187           itor*
00188         , end*
00189         , E
00190         , F
00191         )
00192     {
00193         return false;
00194     }
00195 };
00196 
00197 /** Specialized class when itor != end */
00198 template<>
00199 struct find<false>
00200 {
00201     template<
00202           typename itor
00203         , typename end
00204         , typename E
00205         , typename F
00206         >
00207     static bool execute(
00208           itor*
00209         , end*
00210         , E event
00211         , F functor
00212         )
00213     {
00214         typedef typename boost::mpl::deref<itor>::type item;
00215         typedef typename
00216                 boost::mpl::apply1<boost::mpl::identity<>, item>::type arg;
00217 
00218         boost::value_initialized<arg> x;
00219 
00220         if(boost::get(x) == event) {
00221             // MSVC 2008 doesn't like operator() here so changed the name.
00222             return functor.template oper<item>(event);
00223         } else {
00224             typedef typename boost::mpl::next<itor>::type titor;
00225             return find<boost::is_same<titor, end>::value>::execute(
00226                       static_cast<titor*>(NULL)
00227                     , static_cast<end*>(NULL)
00228                     , event
00229                     , functor);
00230         }
00231     }
00232 };
00233 
00234 } // namespace implementation
00235 
00236 /**
00237  * Tests whether an event handler is available.
00238  *
00239  * The code is based on boost::mpl_for_each, which doesn't allow to call a
00240  * template function with the dereferred iterator as template parameter.
00241  *
00242  * The function first tries to match whether the value in the sequence matches
00243  * event, once that matched it will execute the functor with the key found as
00244  * template parameter and the event as parameter.
00245  *
00246  * @tparam sequence               The sequence to test upon.
00247  * @tparam E                      The value type of the item in the sequence
00248  * @tparam F                      Type of the functor.
00249  *
00250  * @param event                   The event to look for.
00251  * @param functor                 The predicate which should is executed if the
00252  *                                event is matched.
00253  *
00254  * @returns                       Whether or not the function found a result.
00255  */
00256 template<
00257       typename sequence
00258     , typename E
00259     , typename F
00260     >
00261 inline bool find(E event, F functor)
00262 {
00263     typedef typename boost::mpl::begin<sequence>::type begin;
00264     typedef typename boost::mpl::end<sequence>::type end;
00265 
00266     return implementation::find<boost::is_same<begin, end>::value>::execute(
00267               static_cast<begin*>(NULL)
00268             , static_cast<end*>(NULL)
00269             , event
00270             , functor);
00271 }
00272 
00273 namespace implementation {
00274 
00275 /*
00276  * Small sample to illustrate the effects of the various build_event_chain
00277  * functions. Assume the widgets are in an window with the following widgets:
00278  *
00279  *  -----------------------
00280  *  | dispatcher          |
00281  *  | ------------------- |
00282  *  | | container 1     | |
00283  *  | | --------------- | |
00284  *  | | | container 2 | | |
00285  *  | | | ----------- | | |
00286  *  | | | | widget  | | | |
00287  *  | | | ----------- | | |
00288  *  | | --------------- | |
00289  *  | ------------------- |
00290  *  -----------------------
00291  *
00292  * Note that the firing routine fires the events from:
00293  * - pre child for chain.end() - > chain.begin()
00294  * - child for widget
00295  * - post child for chain.begin() -> chain.end()
00296  */
00297 
00298 /**
00299  * Build the event chain.
00300  *
00301  * The event chain is a chain of events starting from the first parent of the
00302  * widget until (and including) the wanted parent. For all these widgets it
00303  * will be tested whether they have either a pre or post handler for the event.
00304  * This ways there will be list of widgets to try to send the events to.
00305  * If there's no line from widget to parent the result is undefined.
00306  * (If widget == dispatcher the result will always be empty.)
00307  *
00308  * @pre                           dispatcher != NULL
00309  * @pre                           widget != NULL
00310  *
00311  * @param event                   The event to test.
00312  * @param dispatcher              The final widget to test, this is also the
00313  *                                dispatcher the sends the event.
00314  * @param widget                  The widget should parent(s) to check.
00315  *
00316  * @returns                       The list of widgets with a handler.
00317  *                                The order will be (assuming all have a
00318  *                                handler):
00319  *                                * container 2
00320  *                                * container 1
00321  *                                * dispatcher
00322  */
00323 template<class T>
00324 inline std::vector<std::pair<twidget*, tevent> > build_event_chain(
00325           const tevent event
00326         , twidget* dispatcher
00327         , twidget* widget)
00328 {
00329     assert(dispatcher);
00330     assert(widget);
00331 
00332     std::vector<std::pair<twidget*, tevent> > result;
00333 
00334     while(widget != dispatcher) {
00335         widget = widget->parent();
00336         assert(widget);
00337 
00338         if(widget->has_event(event, tdispatcher::tevent_type(
00339                 tdispatcher::pre | tdispatcher::post))) {
00340 
00341             result.push_back(std::make_pair(widget, event));
00342         }
00343     }
00344 
00345     return result;
00346 }
00347 
00348 /**
00349  * Build the event chain for tsignal_notification_function.
00350  *
00351  * The notification is only send to the receiver it returns an empty chain.
00352  * Since the pre and post queues are unused, it validates whether they are
00353  * empty (using asserts).
00354  *
00355  * @returns                       An empty vector.
00356  */
00357 template<>
00358 inline std::vector<std::pair<twidget*, tevent> >
00359 build_event_chain<tsignal_notification_function>(
00360           const tevent event
00361         , twidget* dispatcher
00362         , twidget* widget)
00363 {
00364     assert(dispatcher);
00365     assert(widget);
00366 
00367     assert(!widget->has_event(
00368               event
00369             , tdispatcher::tevent_type(
00370                       tdispatcher::pre
00371                     | tdispatcher::post)));
00372 
00373     return std::vector<std::pair<twidget*, tevent> >();
00374 }
00375 
00376 #ifdef _MSC_VER
00377 #pragma warning (push)
00378 #pragma warning (disable: 4706)
00379 #endif
00380 /**
00381  * Build the event chain for tsignal_message_function.
00382  *
00383  * This function expects that the widget sending it is also the receiver. This
00384  * assumption might change, but is valid for now. The function doesn't build an
00385  * event chain from @p dispatcher to @p widget but from @p widget to its
00386  * toplevel item (the first one without a parent) which we call @p window.
00387  *
00388  * @pre                           dispatcher == widget
00389  *
00390  * @returns                       The list of widgets with a handler.
00391  *                                The order will be (assuming all have a
00392  *                                handler):
00393  *                                * window
00394  *                                * container 1
00395  *                                * container 2
00396  */
00397 template<>
00398 inline std::vector<std::pair<twidget*, tevent> >
00399 build_event_chain<tsignal_message_function>(
00400           const tevent event
00401         , twidget* dispatcher
00402         , twidget* widget)
00403 {
00404     assert(dispatcher);
00405     assert(widget);
00406     assert(widget == dispatcher);
00407 
00408     std::vector<std::pair<twidget*, tevent> > result;
00409 
00410     /* We only should add the parents of the widget to the chain. */
00411     while((widget = widget->parent())) {
00412         assert(widget);
00413 
00414         if(widget->has_event(event, tdispatcher::tevent_type(
00415                 tdispatcher::pre | tdispatcher::post))) {
00416 
00417             result.insert(result.begin(), std::make_pair(widget, event));
00418         }
00419     }
00420 
00421     return result;
00422 }
00423 #ifdef _MSC_VER
00424 #pragma warning (pop)
00425 #endif
00426 
00427 /**
00428  * Helper function for fire_event.
00429  *
00430  * This is called with the same parameters as fire_event except for the
00431  * event_chain, which contains the widgets with the events to call for them.
00432  */
00433 template<class T, class F>
00434 inline bool fire_event(const tevent event
00435         , std::vector<std::pair<twidget*, tevent> >& event_chain
00436         , twidget* dispatcher
00437         , twidget* widget
00438         , F functor)
00439 {
00440     bool handled = false;
00441     bool halt = false;
00442 
00443     /***** ***** ***** Pre ***** ***** *****/
00444     for(std::vector<std::pair<twidget*, tevent> >
00445                 ::reverse_iterator ritor_widget = event_chain.rbegin();
00446             ritor_widget != event_chain.rend();
00447             ++ritor_widget) {
00448 
00449         tdispatcher::tsignal<T>& signal = tdispatcher_implementation
00450                 ::event_signal<T>(*ritor_widget->first, ritor_widget->second);
00451 
00452         for(typename std::vector<T>::iterator itor = signal.pre_child.begin();
00453                 itor != signal.pre_child.end();
00454                 ++itor) {
00455 
00456             functor(*itor, *dispatcher, ritor_widget->second, handled, halt);
00457             if(halt) {
00458                 assert(handled);
00459                 break;
00460             }
00461         }
00462 
00463         if(handled) {
00464             return true;
00465         }
00466     }
00467 
00468     /***** ***** ***** Child ***** ***** *****/
00469     if(widget->has_event(event, tdispatcher::child)) {
00470 
00471         tdispatcher::tsignal<T>& signal = tdispatcher_implementation
00472                 ::event_signal<T>(*widget, event);
00473 
00474         for(typename std::vector<T>::iterator itor = signal.child.begin();
00475                 itor != signal.child.end();
00476                 ++itor) {
00477 
00478             functor(*itor, *dispatcher, event, handled, halt);
00479 
00480             if(halt) {
00481                 assert(handled);
00482                 break;
00483             }
00484         }
00485 
00486         if(handled) {
00487             return true;
00488         }
00489     }
00490 
00491     /***** ***** ***** Post ***** ***** *****/
00492     for(std::vector<std::pair<twidget*, tevent> >
00493                 ::iterator itor_widget = event_chain.begin();
00494             itor_widget != event_chain.end();
00495             ++itor_widget) {
00496 
00497         tdispatcher::tsignal<T>& signal = tdispatcher_implementation
00498                 ::event_signal<T>(*itor_widget->first, itor_widget->second);
00499 
00500         for(typename std::vector<T>::iterator itor = signal.post_child.begin();
00501                 itor != signal.post_child.end();
00502                 ++itor) {
00503 
00504             functor(*itor, *dispatcher, itor_widget->second, handled, halt);
00505             if(halt) {
00506                 assert(handled);
00507                 break;
00508             }
00509         }
00510 
00511         if(handled) {
00512             return true;
00513         }
00514     }
00515 
00516     /**** ***** ***** Unhandled ***** ***** *****/
00517     assert(handled == false);
00518     return false;
00519 }
00520 
00521 } // namespace implementation
00522 
00523 /**
00524  * Fires an event.
00525  *
00526  * A helper to allow the common event firing code to be shared between the
00527  * different signal function types.
00528  *
00529  * @pre                           dispatcher != NULL
00530  * @pre                           widget != NULL
00531  *
00532  * @tparam T                      The signal type of the event to handle.
00533  * @tparam F                      The type of the functor.
00534  *
00535  *
00536  * @param event                   The event to fire.
00537  * @param dispatcher              The dispatcher that handles the event.
00538  * @param widget                  The widget that should receive the event.
00539  * @param functor                 The functor to execute the actual event.
00540  *                                Since some functions need different
00541  *                                parameters this functor stores them before
00542  *                                firing the event.
00543  *
00544  * @returns                       Whether or not the event was handled.
00545  */
00546 template<class T, class F>
00547 inline bool fire_event(const tevent event
00548         , twidget* dispatcher
00549         , twidget* widget
00550         , F functor)
00551 {
00552     assert(dispatcher);
00553     assert(widget);
00554 
00555     std::vector<std::pair<twidget*, tevent> > event_chain =
00556             implementation::build_event_chain<T>(event, dispatcher, widget);
00557 
00558     return implementation::fire_event<T>(event
00559             , event_chain
00560             , dispatcher
00561             , widget
00562             , functor);
00563 }
00564 
00565 template<
00566       tevent click
00567     , tevent double_click
00568     , bool(tevent_executor::*wants_double_click) () const
00569     , class T
00570     , class F
00571     >
00572 inline bool fire_event_double_click(
00573           twidget* dispatcher
00574         , twidget* widget
00575         , F functor)
00576 {
00577     assert(dispatcher);
00578     assert(widget);
00579 
00580     std::vector<std::pair<twidget*, tevent> > event_chain;
00581     twidget* w = widget;
00582     while(w!= dispatcher) {
00583         w = w->parent();
00584         assert(w);
00585 
00586         if((w->*wants_double_click)()) {
00587 
00588             if(w->has_event(double_click, tdispatcher::tevent_type(
00589                     tdispatcher::pre | tdispatcher::post))) {
00590 
00591                 event_chain.push_back(std::make_pair(w, double_click));
00592             }
00593         } else {
00594             if(w->has_event(click, tdispatcher::tevent_type(
00595                     tdispatcher::pre | tdispatcher::post))) {
00596 
00597                 event_chain.push_back(std::make_pair(w, click));
00598             }
00599         }
00600     }
00601 
00602     if((widget->*wants_double_click)()) {
00603         return implementation::fire_event<T>(double_click
00604                 , event_chain
00605                 , dispatcher
00606                 , widget
00607                 , functor);
00608     } else {
00609         return implementation::fire_event<T>(click
00610                 , event_chain
00611                 , dispatcher
00612                 , widget
00613                 , functor);
00614     }
00615 }
00616 
00617 } // namespace event
00618 
00619 } // namespace gui2
00620 
00621 #endif
00622 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Thu May 24 2012 01:02:39 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs