gui/auxiliary/event/dispatcher.cpp

Go to the documentation of this file.
00001 /* $Id: dispatcher.cpp 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 #define GETTEXT_DOMAIN "wesnoth-lib"
00017 
00018 #include "gui/auxiliary/event/dispatcher_private.hpp"
00019 
00020 #include "foreach.hpp"
00021 #include "gui/auxiliary/log.hpp"
00022 
00023 namespace gui2 {
00024 
00025 namespace event {
00026 
00027 /***** tdispatcher class. *****/
00028 
00029 tdispatcher::tdispatcher()
00030     : mouse_behaviour_(all)
00031     , want_keyboard_input_(true)
00032     , signal_queue_()
00033     , signal_mouse_queue_()
00034     , signal_keyboard_queue_()
00035     , signal_notification_queue_()
00036     , signal_message_queue_()
00037     , connected_(false)
00038     , hotkeys_()
00039 {
00040 }
00041 
00042 tdispatcher::~tdispatcher()
00043 {
00044     if(connected_) {
00045         disconnect_dispatcher(this);
00046     }
00047 }
00048 
00049 void tdispatcher::connect()
00050 {
00051     assert(!connected_);
00052     connected_ = true;
00053     connect_dispatcher(this);
00054 }
00055 
00056 bool tdispatcher::has_event(const tevent event
00057         , const tevent_type event_type
00058         )
00059 {
00060 #if 0
00061     // Debug code to test whether the event is in the right queue.
00062     std::cerr << "Event '" << event
00063             << "' event "
00064             << find<tset_event>(event, tdispatcher_implementation
00065 				::thas_handler(event_type, *this))
00066             << " mouse "
00067             << find<tset_event_mouse>(event, tdispatcher_implementation
00068                 ::thas_handler(event_type, *this))
00069             << " keyboard "
00070             << find<tset_event_keyboard>(event, tdispatcher_implementation
00071                 ::thas_handler(event_type, *this))
00072             << " notification "
00073             << find<tset_event_notification>(event, tdispatcher_implementation
00074                 ::thas_handler(event_type, *this))
00075             << " message "
00076             << find<tset_event_message>(event, tdispatcher_implementation
00077                 ::thas_handler(event_type, *this))
00078             << ".\n";
00079 #endif
00080 
00081     return find<tset_event>(event, tdispatcher_implementation
00082 					::thas_handler(event_type, *this))
00083             || find<tset_event_mouse>(event, tdispatcher_implementation
00084                     ::thas_handler(event_type, *this))
00085             || find<tset_event_keyboard>(event, tdispatcher_implementation
00086                     ::thas_handler(event_type, *this))
00087             || find<tset_event_notification>(event, tdispatcher_implementation
00088                     ::thas_handler(event_type, *this))
00089             || find<tset_event_message>(event, tdispatcher_implementation
00090                     ::thas_handler(event_type, *this))
00091             ;
00092 }
00093 
00094 /**
00095  * Helper class to do a runtime test whether an event is in a set.
00096  *
00097  * The class is supposed to be used in combination with find function. This
00098  * function is used in the fire functions to make sure an event is send to the
00099  * proper handler. If not there will be a run-time assertion failure. This
00100  * makes developing and testing the code easier, a wrong handler terminates
00101  * Wesnoth instead of silently not working.
00102  */
00103 class tevent_in_set
00104 {
00105 public:
00106 
00107     /**
00108      * If found we get executed to set the result.
00109      *
00110      * Since we need to return true if found we always return true.
00111      */
00112     template<class T>
00113     bool oper(tevent)
00114     {
00115         return true;
00116     }
00117 };
00118 
00119 /**
00120  * Helper struct to wrap the functor call.
00121  *
00122  * The template function @ref fire_event needs to call a functor with extra
00123  * parameter. In order to facilitate this we send the parameter in the
00124  * constructor of the class and let operator() call the functor with the
00125  * default parameters and the stored parameters. This allows the core part of
00126  * @ref tdispatcher::fire to be generic.
00127  */
00128 class ttrigger
00129 {
00130 public:
00131     void operator()(tsignal_function functor
00132             , tdispatcher& dispatcher
00133             , const tevent event
00134             , bool& handled
00135             , bool& halt)
00136     {
00137         functor(dispatcher, event, handled, halt);
00138     }
00139 };
00140 
00141 bool tdispatcher::fire(const tevent event, twidget& target)
00142 {
00143     assert(find<tset_event>(event, tevent_in_set()));
00144     switch(event) {
00145         case LEFT_BUTTON_DOUBLE_CLICK :
00146             return fire_event_double_click<
00147                       LEFT_BUTTON_CLICK
00148                     , LEFT_BUTTON_DOUBLE_CLICK
00149                     , &tevent_executor::wants_mouse_left_double_click
00150                     , tsignal_function
00151                     >(
00152                       dynamic_cast<twidget*>(this)
00153                     , &target
00154                     , ttrigger());
00155 
00156         case MIDDLE_BUTTON_DOUBLE_CLICK :
00157             return fire_event_double_click<
00158                       MIDDLE_BUTTON_CLICK
00159                     , MIDDLE_BUTTON_DOUBLE_CLICK
00160                     , &tevent_executor::wants_mouse_middle_double_click
00161                     , tsignal_function
00162                     >(
00163                       dynamic_cast<twidget*>(this)
00164                     , &target
00165                     , ttrigger());
00166 
00167         case RIGHT_BUTTON_DOUBLE_CLICK :
00168             return fire_event_double_click<
00169                       RIGHT_BUTTON_CLICK
00170                     , RIGHT_BUTTON_DOUBLE_CLICK
00171                     , &tevent_executor::wants_mouse_right_double_click
00172                     , tsignal_function
00173                     >(
00174                       dynamic_cast<twidget*>(this)
00175                     , &target
00176                     , ttrigger());
00177 
00178         default :
00179             return fire_event<tsignal_function>(event
00180                 , dynamic_cast<twidget*>(this)
00181                 , &target
00182                 , ttrigger());
00183     }
00184 }
00185 
00186 /** Helper struct to wrap the functor call. */
00187 class ttrigger_mouse
00188 {
00189 public:
00190     ttrigger_mouse(const tpoint& coordinate)
00191         : coordinate_(coordinate)
00192     {
00193 
00194     }
00195 
00196     void operator()(tsignal_mouse_function functor
00197             , tdispatcher& dispatcher
00198             , const tevent event
00199             , bool& handled
00200             , bool& halt)
00201     {
00202         functor(dispatcher, event, handled, halt, coordinate_);
00203     }
00204 
00205 private:
00206     tpoint coordinate_;
00207 };
00208 
00209 bool tdispatcher::fire(const tevent event
00210         , twidget& target
00211         , const tpoint& coordinate)
00212 {
00213     assert(find<tset_event_mouse>(event, tevent_in_set()));
00214     return fire_event<tsignal_mouse_function>(event
00215             , dynamic_cast<twidget*>(this)
00216             , &target
00217             , ttrigger_mouse(coordinate));
00218 }
00219 
00220 /** Helper struct to wrap the functor call. */
00221 class ttrigger_keyboard
00222 {
00223 public:
00224     ttrigger_keyboard(const SDLKey key
00225             , const SDLMod modifier
00226             , const Uint16 unicode)
00227         : key_(key)
00228         , modifier_(modifier)
00229         , unicode_(unicode)
00230     {
00231     }
00232 
00233     void operator()(tsignal_keyboard_function functor
00234             , tdispatcher& dispatcher
00235             , const tevent event
00236             , bool& handled
00237             , bool& halt)
00238     {
00239         functor(dispatcher, event, handled, halt, key_, modifier_, unicode_);
00240     }
00241 
00242 private:
00243     SDLKey key_;
00244     SDLMod modifier_;
00245     Uint16 unicode_;
00246 };
00247 
00248 bool tdispatcher::fire(const tevent event
00249         , twidget& target
00250         , const SDLKey key
00251         , const SDLMod modifier
00252         , const Uint16 unicode)
00253 {
00254     assert(find<tset_event_keyboard>(event, tevent_in_set()));
00255     return fire_event<tsignal_keyboard_function>(event
00256             , dynamic_cast<twidget*>(this)
00257             , &target
00258             , ttrigger_keyboard(key, modifier, unicode));
00259 }
00260 
00261 /** Helper struct to wrap the functor call. */
00262 class ttrigger_notification
00263 {
00264 public:
00265 
00266     void operator()(tsignal_notification_function functor
00267             , tdispatcher& dispatcher
00268             , const tevent event
00269             , bool& handled
00270             , bool& halt)
00271     {
00272         functor(dispatcher, event, handled, halt, NULL);
00273     }
00274 };
00275 
00276 bool tdispatcher::fire(const tevent event
00277         , twidget& target
00278         , void*)
00279 {
00280     assert(find<tset_event_notification>(event, tevent_in_set()));
00281     return fire_event<tsignal_notification_function>(event
00282             , dynamic_cast<twidget*>(this)
00283             , &target
00284             , ttrigger_notification());
00285 }
00286 
00287 /** Helper struct to wrap the functor call. */
00288 class ttrigger_message
00289 {
00290 public:
00291     ttrigger_message(tmessage& message)
00292         : message_(message)
00293     {
00294     }
00295 
00296     void operator()(tsignal_message_function functor
00297             , tdispatcher& dispatcher
00298             , const tevent event
00299             , bool& handled
00300             , bool& halt)
00301     {
00302         functor(dispatcher, event, handled, halt, message_);
00303     }
00304 
00305 private:
00306     tmessage& message_;
00307 };
00308 
00309 bool tdispatcher::fire(const tevent event, twidget& target, tmessage& message)
00310 {
00311     assert(find<tset_event_message>(event, tevent_in_set()));
00312     return fire_event<tsignal_message_function>(event
00313             , dynamic_cast<twidget*>(this)
00314             , &target
00315             , ttrigger_message(message));
00316 }
00317 
00318 void tdispatcher::register_hotkey(const hotkey::HOTKEY_COMMAND id
00319         , const thotkey_function& function)
00320 {
00321     hotkeys_[id] = function;
00322 }
00323 
00324 bool tdispatcher::execute_hotkey(const hotkey::HOTKEY_COMMAND id)
00325 {
00326     std::map<hotkey::HOTKEY_COMMAND, thotkey_function>::iterator
00327             itor = hotkeys_.find(id);
00328 
00329     if(itor == hotkeys_.end()) {
00330         return false;
00331     }
00332 
00333     return itor->second(*this, id);
00334 }
00335 
00336 } // namespace event
00337 
00338 } // namespace gui2
00339 
00340 /**
00341  * @page event_dispatching Event dispatching.
00342  *
00343  * @section introduction Introduction
00344  *
00345  * This page describes how the new event handling system works, since the
00346  * system is still work in progress it might be out of date with the actual
00347  * code. It also contains some ideas that might change later on. Some parts are
00348  * explained in the interface and will be integrated in this document later.
00349  *
00350  * Since the event handling code hasn't been cast in stone yet some scenarios
00351  * for solving the problem are discussed first and then the solution that is
00352  * chosen in more detail.
00353  *
00354  * After SDL has generated and event it needs to be turned into an event which
00355  * the widgets can use.
00356  *
00357  * @section handling_solution The implementation solutions.
00358  *
00359  * For the event handling we use a few use case scenarios and show the possible
00360  * solutions.
00361  *
00362  * @subsection sample The sample window
00363  *
00364  * In our samples we use this sample window with the following components:
00365  * - a window W
00366  * - a container C
00367  * - a button B
00368  *
00369  * These are arranged accordingly:
00370  * @code
00371  *
00372  *   ---------------------
00373  *  |W                     |
00374  *  |                      |
00375  *  |  -----------------   |
00376  *  | |C              |^|  |
00377  *  | |               |-|  |
00378  *  | |  ----------   |#|  |
00379  *  | | |B         |  | |  |
00380  *  | |  ----------   | |  |
00381  *  | |               |-|  |
00382  *  | |               |v|  |
00383  *  |  -----------------   |
00384  *  |                      |
00385  *   ---------------------
00386  *
00387  * @endcode
00388  *
00389  * @subsection scenarios Possible scenarios
00390  *
00391  * The scenarios are:
00392  * - An event that is wanted by none.
00393  * - A mouse down event that should focus C and set the pressed state in B.
00394  * - A mouse wheel event, which first should be offered to B and if not handled
00395  *   by B should be handled by C.
00396  *
00397  * @subsection all_queues Pass the event through all queues
00398  *
00399  * In this solution the event will be passed through all possible queues and
00400  * tries sees where the event sticks. This following sections describe how the
00401  * events are tried for this usage scenario.
00402  *
00403  * @subsubsection unhandled Unhandled event
00404  *
00405  * - W pre child
00406  * - C pre child
00407  * - B pre child
00408  * - W child
00409  * - C child
00410  * - B child
00411  * - W post child
00412  * - C post child
00413  * - B post child
00414  *
00415  * @subsubsection mouse_down Mouse down
00416  *
00417  * - W pre child
00418  * - C pre child -> set focus -> !handled
00419  * - B pre child -> set pressed state -> handled
00420  *
00421  * @subsubsection mouse_wheel Mouse wheel
00422  *
00423  * - W pre child
00424  * - C pre child
00425  * - B pre child -> We can't scroll so ignore
00426  * - W child
00427  * - C child
00428  * - B child
00429  * - W post child
00430  * - C post child -> Scroll -> handled
00431  *
00432  * @subsection chain Pass the events in a chain like fashion
00433  *
00434  * In this solution the events are send to the pre- and post queue of all but
00435  * the last possible widget and to the child of the last widget. The pre queue
00436  * will be send from top to bottom, the post queue from bottom to top.
00437  *
00438  * @subsubsection unhandled Unhandled event
00439  *
00440  * - W pre child
00441  * - C pre child
00442  * - B child
00443  * - C post child
00444  * - W post child
00445  *
00446  * @subsubsection mouse_down Mouse down
00447  *
00448  * - W pre child
00449  * - C pre child -> set focus -> !handled
00450  * - B child -> set pressed state -> handled
00451  *
00452  * @subsubsection mouse_wheel Mouse wheel
00453  *
00454  * - W pre child
00455  * - C pre child
00456  * - B child -> We can't scroll so ignore
00457  * - C post child -> Scroll -> handled
00458  *
00459  * @subsection evaluation Evaluation
00460  *
00461  * When using the first solution it's possible to drop the child queue since
00462  * everything falls in pre or post. But there is a scenario that's a bit ugly
00463  * to solve with the first solution:
00464  *
00465  * Assume there is a listbox with toggle panels and on the panel there are a
00466  * few buttons, the wanted behaviour is:
00467  * - if clicked on the panel it should toggle, which may or may not be allowed.
00468  * - if clicked on a button in the panel, we want to make sure the panel is
00469  *   selected, which again may or may not be allowed.
00470  *
00471  * With solution 2 it's rather easy:
00472  *
00473  * Click on panel:
00474  * - W pre child
00475  * - C child -> Test whether we can toggle -> handled, halt = !toggled
00476  *
00477  * Click on button in panel:
00478  * - W pre child
00479  * - C pre child -> Test whether we can select -> handled = halt = !selected
00480  * - B child -> do button stuff -> handled
00481  *
00482  * Since for the different clicks, different queues are triggered it's easy to
00483  * add a different handler there.
00484  *
00485  * With solution 1:
00486  *
00487  * Click on panel:
00488  * - W pre child
00489  * - C pre child -> handler 1 -> if last in queue -> solution 2 C child
00490  *
00491  * Click on button in panel:
00492  * - W pre child
00493  * - C pre child -> handler 2 -> if !last in queue -> solution 2 C pre child
00494  * - B pre child -> do button stuff -> handled
00495  *
00496  * Not that different from solution 2, the two handlers are installed in the C
00497  * pre event. But we need to manually check whether we're really the last,
00498  * which means the code to check whether there are more handlers at a lower
00499  * level is needed for both solutions. In solution 1 this test needs to be done
00500  * twice versus once in solution 2. Also the fact that the queues for the
00501  * events are processed in reverse order on the way back sounds more
00502  * initiative.
00503  *
00504  * @section processing_raw_events Processing the raw events.
00505  *
00506  * This section describes how the events generated by SDL are send as our own
00507  * events to the various widgets. The first step in sending an event is to
00508  * decode it and send it to a registered dispatcher.
00509  *
00510  * - gui2::event::thandler handles the SDL events.
00511  * - gui2::event::tdispatcher has the registered dispatchers.
00512  *
00513  * In general a dispatcher is a window which then needs to send this event to
00514  * the widgets. The dispatcher is just a simple part which fires events and
00515  * finds a handler for the event. This is not to the liking of most widgets,
00516  * they don't want to handle raw events but get a polished and clean event. No
00517  * button up and down and then try to figure out whether it needs to act as if
00518  * it was clicked upon, no simply op and down to change the appearance and a
00519  * click event to do the clicking actions. And don't even try to convince a
00520  * widget to determine whether this up event was a single or double click.
00521  * Widgets like to sleep with nice dreams and not having nightmares where SDL
00522  * events haunt them.
00523  *
00524  * In order to remedy that problem there's the gui2::event::tdistributor
00525  * class, it's the class to do the dirty job of converting the raw event into
00526  * these nice polished events. The distributor is in general linked to a window,
00527  * but a widget can install it's own distributor if it needs to know more of the
00528  * raw events as still left in the polished events. At the time of this writing
00529  * no widget needs this feature, but the toggle panel might need it.
00530  *
00531  * After the distributor has polished the event and send it on its way to the
00532  * widget the dispatcher needs to make sure the event is properly dispatched to
00533  * the widget in question and also notify its parents by means of the previously
00534  * described event chain.
00535  *
00536  * @subsection sdl_event Get the SDL events
00537  *
00538  * The first step in event handling is getting the events in the first place.
00539  * Events are generated by SDL and placed in a queue. The Wesnoth code processes
00540  * this queue and thus handles the events. The part which does the first
00541  * handling isn't described here since it's (secretly) intended to be replaced
00542  * by the @ref gui2::event::thandler class. Instead we directly jump to this
00543  * class and explain what it does.
00544  *
00545  * The main handling function is @ref gui2::event::thandler::handle_event which
00546  * as no real surprise handles the events. The function is a simple multiplexer
00547  * which lets other subfunctions to the handling of specific events.
00548  *
00549  * @todo Describe drawing and resizing once the code is stable and working as
00550  * wanted in these areas.
00551  *
00552  * @subsubsection thandler_mouse Mouse motion events
00553  *
00554  * If a dispatcher has captured the mouse it gets the event, no questions asked.
00555  * If not it goes through all dispatchers and finds the first one willing to
00556  * accept the mouse event.
00557  *
00558  * This means a mouse event is send to one dispatcher.
00559  *
00560  * @subsubsection thandler_mouse_button_down Mouse button down events
00561  *
00562  * Turning the mouse wheel on a mouse generates both an down and up event. It
00563  * has been decided to handle the wheel event in the button up code so wheel
00564  * events are here directly dropped on the floor and forgotten.
00565  *
00566  * The other buttons are handled as if they're normal mouse events but are
00567  * decoded per button so instead of a button_down(id) you get button_down_id.
00568  *
00569  * @subsubsection thandler_mouse_button_up Mouse button up events
00570  *
00571  * The mouse wheel event is handled as if it's a keyboard event and like the
00572  * button_down they are send as wheel_id events.
00573  *
00574  * The other mouse buttons are handled the same as the down buttons.
00575  *
00576  * @subsubsection thandler_keyboard Keyboard events
00577  *
00578  * There are three types of keyboard events, the already mentioned mouse wheel
00579  * events, the key down and key up event. When a key is pressed for a longer
00580  * time several key down events are generated and only one key up, this means
00581  * the key up is rather useless. Guess what, the multiplexer already drops that
00582  * event so we never get it.
00583  *
00584  * If the keyboard event is a mouse wheel event it's directly send to the
00585  * dispachting queue; either the dispatcher that captured the keyboard or the
00586  * last dispatcher in the queue.
00587  *
00588  * If the event is a real keyboard action it's first tried as hotkey. In order
00589  * to do so the target dispatcher is first determined, either the dispatcher
00590  * that captured the keyboard or the last dispatcher in the queue. Then it's
00591  * tried whether a hotkey and whether the hotkey can be processed. If the
00592  * hotkey isn't processed the keyboard event is send to the dispatcher as
00593  * normal keyboard event.
00594  *
00595  * The hotkey processing will have several queues (to be implemented in 1.9):
00596  * - global hotkeys that always work eg toggling fullscreen mode.
00597  * - main screen hotkeys, these work when one of the dialogs is shown without
00598  *   other dialogs on top of them. These hotkeys are for example
00599  *   preferences. The main screens are:
00600  *   - title screen
00601  *   - game
00602  *   - editor
00603  *   - mp lobby
00604  * - map screen hotkeys, these work when a map is shown eg toggle grid. The
00605  *   screens are:
00606  *   - game
00607  *   - editor
00608  * - local hotkeys, these are hotkeys that only work in a specific dialog eg
00609  *   recruit unit only works in the game screen.
00610  *
00611  * The queues are processed in from bottom to top in the list above, this
00612  * allows an item to use a hotkey but have another handler function. Eg
00613  * preferences in the editor might open another preferences dialog.
00614  *
00615  * @todo The hotkeys need to be implemented like above in 1.9.
00616  *
00617  * @todo This might change in the near future.
00618  *
00619  * @subsection tdistributor Event polishing and distribution
00620  *
00621  * The event distributor has the job to find the widget that should receive the
00622  * event and which event(s) to send from a single event. In general an event is
00623  * first send to the widget as-is, sending the raw events allows other
00624  * distributors to be nested between this distributor and the intended target
00625  * widget. Or the intended widget might not really be the intended widget but
00626  * another distributor that wants to dispatch the event internally.
00627  *
00628  * However in the common cases this raw event isn't handled and the distributor
00629  * needs to send the polished events. In the following sections the details of
00630  * the conversion from raw to polished is described, it intentionally lacks the
00631  * part of sending the raw events as well since it adds no value.
00632  *
00633  * A widget can capture the mouse, which means all mouse events are send to this
00634  * widget, regardless where the mouse is. This is normally done in a mouse down
00635  * event (for a button) so all events following it are send to that widget.
00636  *
00637  * @subsection mouse_motion Mouse motion
00638  *
00639  * This section describes the conversion from a raw mouse motion to the polished
00640  * events it can generate:
00641  * - @ref gui2::event::MOUSE_ENTER "MOUSE_ENTER"
00642  * - @ref gui2::event::MOUSE_LEAVE "MOUSE_LEAVE"
00643  * - @ref gui2::event::MOUSE_MOTION "MOUSE_MOTION"
00644  *
00645  * When the mouse is captured that widget will only receive motion events.
00646  *
00647  * If not captured the code checks whether the widget underneath the mouse is
00648  * the same widget as at the last motion if event. If so that widget gets a
00649  * motion event.
00650  * If not the widget that before was underneath the mouse pointer (if any) gets
00651  * a leave event and the widget newly underneath the mouse pointer (if any) gets
00652  * an enter event.
00653  *
00654  * @subsection mouse_button Mouse buttons
00655  *
00656  * The mouse button code is a bit more complex and is separated in the various
00657  * events to be send.
00658  *
00659  * @subsubsection mouse_button_down Mouse button down
00660  *
00661  * Some things start simple, so does the event of pressing down a mouse button.
00662  * All it does is send the event to the widget as one of the following events:
00663  * - @ref gui2::event::LEFT_BUTTON_DOWN "LEFT_BUTTON_DOWN"
00664  * - @ref gui2::event::MIDDLE_BUTTON_DOWN "MIDDLE_BUTTON_DOWN"
00665  * - @ref gui2::event::RIGHT_BUTTON_DOWN "RIGHT_BUTTON_DOWN"
00666  *
00667  * @todo Validate the code it seems a down event with a captured mouse doesn't
00668  * really work as wanted. (Rare case but should work properly.) In general the
00669  * mouse event handling needs testing to see whether the proper events are send
00670  * all the time.
00671  *
00672  * @subsubsection mouse_button_up Mouse button up
00673  *
00674  * Simplicity ends here.
00675  *
00676  * @todo Document further.
00677  *
00678  * @subsubsection mouse_click Mouse click
00679  *
00680  * So the button up event has asked for mouse click, now we need to test whether
00681  * the click will be a click or a double click. A double click is generated when
00682  * the same widget is clicked twice in a short time and causes the following
00683  * events:
00684  * - @ref gui2::event::LEFT_BUTTON_DOUBLE_CLICK "LEFT_BUTTON_DOUBLE_CLICK"
00685  * - @ref gui2::event::MIDDLE_BUTTON_DOUBLE_CLICK "MIDDLE_BUTTON_DOUBLE_CLICK"
00686  * - @ref gui2::event::RIGHT_BUTTON_DOUBLE_CLICK "RIGHT_BUTTON_DOUBLE_CLICK"
00687  *
00688  * Otherwise one of the following single clicks is generated:
00689  * - @ref gui2::event::LEFT_BUTTON_CLICK "LEFT_BUTTON_CLICK"
00690  * - @ref gui2::event::MIDDLE_BUTTON_CLICK "MIDDLE_BUTTON_CLICK"
00691  * - @ref gui2::event::RIGHT_BUTTON_CLICK "RIGHT_BUTTON_CLICK"
00692  *
00693  * @subsubsection double_click To double click or not to double click
00694  *
00695  * Wait a second, a widget has a field whether or not it wants a double click
00696  * for a certain mouse button and now I see that it's bluntly ignored by the
00697  * distributor. Indeed the distributor doesn't care about what the widget wants,
00698  * it does what it wants and leaves the sorting out what's wanted to the
00699  * dispatcher.
00700  *
00701  * The problem is that in the chain events are send to one widget that may not
00702  * be interested in a double click, but another widget in the chain is. There
00703  * are several solutions to this problem:
00704  * -# Sending a click followed by a double click.
00705  * -# Sending a click with a tag field that it actually is a double click.
00706  * -# Send a double click and turn it into a click if the double click is
00707  *    unwanted.
00708  *
00709  * The first solution has the disadvantage that a toggle panel likes a click and
00710  * double click, the first click selects the second deselects and now the
00711  * deselected panel gets a double click. When the panel now checks whether it's
00712  * selected it's not and might take the wrong action upon it.
00713  *
00714  * The second option is possible but would be rather intrusive in the code,
00715  * since it would generate another event signature. Adding a signature just for
00716  * this special case seemed a bit too much effort vs. gain. Also the widget
00717  * needs to check whether a click is a click or a double click and choose a
00718  * different code path for it. This in turn would mean a signal handler
00719  * secretly might handle two events and lowers the transparency of the code.
00720  *
00721  * The third option also adds some special case handling but the scope is
00722  * limited and only one part knows about the tricks done.
00723  *
00724  * The last option has been chosen and the dispatcher build the event chain and
00725  * while building the chain it looks whether the widget wants the double click
00726  * or not. It does this test by looking at the wants double click function and
00727  * not test for a handler. The double click test function is made for this
00728  * purpose and depending on the handler might again do the wrong thing.
00729  * (A certain toggle panel might not want to do something on a double click but
00730  * also not being deselected upon a double click. The latter to keep the UI
00731  * consistent, a double click on a toggle panel might execute a special function
00732  * or not, but always keep the panel selected. (That is if the panel can be
00733  * selected.))
00734  */
00735 
 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