gui/auxiliary/event/distributor.cpp

Go to the documentation of this file.
00001 /* $Id: distributor.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/distributor.hpp"
00019 
00020 #include "events.hpp"
00021 #include "gui/auxiliary/log.hpp"
00022 #include "gui/auxiliary/timer.hpp"
00023 #include "gui/widgets/settings.hpp"
00024 #include "gui/widgets/widget.hpp"
00025 #include "gui/widgets/window.hpp"
00026 
00027 #include <boost/bind.hpp>
00028 
00029 namespace gui2{
00030 
00031 namespace event {
00032 
00033 /**
00034  * SDL_AddTimer() callback for the hover event.
00035  *
00036  * When this callback is called it pushes a new hover event in the event queue.
00037  *
00038  * @param interval                The time parameter of SDL_AddTimer.
00039  * @param param                   Pointer to a widget that's able to show the
00040  *                                tooltip (will be used as a dispatcher).
00041  *
00042  * @returns                       The new timer interval, 0 to stop.
00043  */
00044 
00045 #if 0
00046 /**
00047  * SDL_AddTimer() callback for the popup event.
00048  *
00049  * This event makes sure the popup is removed again.
00050  *
00051  * @param interval                The time parameter of SDL_AddTimer.
00052  * @param param                   Pointer to parameter structure.
00053  *
00054  * @returns                       The new timer interval, 0 to stop.
00055  */
00056 static Uint32 popup_callback(Uint32 /*interval*/, void* /*param*/)
00057 {
00058     DBG_GUI_E << "Pushing popup removal event in queue.\n";
00059 
00060     SDL_Event event;
00061     SDL_UserEvent data;
00062 
00063     data.type = HOVER_REMOVE_POPUP_EVENT;
00064     data.code = 0;
00065     data.data1 = 0;
00066     data.data2 = 0;
00067 
00068     event.type = HOVER_REMOVE_POPUP_EVENT;
00069     event.user = data;
00070 
00071     SDL_PushEvent(&event);
00072     return 0;
00073 }
00074 #endif
00075 
00076 /**
00077  * Small helper to keep a resource (boolean) locked.
00078  *
00079  * Some of the event handling routines can't be called recursively, this due to
00080  * the fact that they are attached to the pre queue and when the forward an
00081  * event the pre queue event gets triggered recursively causing infinite
00082  * recursion.
00083  *
00084  * To prevent that those functions check the lock and exit when the lock is
00085  * held otherwise grab the lock here.
00086  */
00087 class tlock
00088 {
00089 public:
00090     tlock(bool& locked)
00091         : locked_(locked)
00092     {
00093         assert(!locked_);
00094         locked_ = true;
00095     }
00096 
00097     ~tlock()
00098     {
00099         assert(locked_);
00100         locked_ = false;
00101     }
00102 private:
00103     bool& locked_;
00104 };
00105 
00106 
00107 /***** ***** ***** ***** tmouse_motion ***** ***** ***** ***** *****/
00108 
00109 #define LOG_HEADER "distributor mouse motion [" << owner_.id() << "]: "
00110 
00111 tmouse_motion::tmouse_motion(twidget& owner
00112         , const tdispatcher::tposition queue_position)
00113     : mouse_focus_(NULL)
00114     , mouse_captured_(false)
00115     , owner_(owner)
00116     , hover_timer_(0)
00117     , hover_widget_(NULL)
00118     , hover_position_(0, 0)
00119     , hover_shown_(true)
00120     , signal_handler_sdl_mouse_motion_entered_(false)
00121 {
00122     owner.connect_signal<event::SDL_MOUSE_MOTION>(
00123           boost::bind(&tmouse_motion::signal_handler_sdl_mouse_motion
00124               , this, _2, _3, _5)
00125         , queue_position);
00126 
00127     owner_.connect_signal<event::SDL_WHEEL_UP>(
00128             boost::bind(
00129                   &tmouse_motion::signal_handler_sdl_wheel
00130                 , this, _2, _3, _5));
00131     owner_.connect_signal<event::SDL_WHEEL_DOWN>(
00132             boost::bind(
00133                   &tmouse_motion::signal_handler_sdl_wheel
00134                 , this, _2, _3, _5));
00135     owner_.connect_signal<event::SDL_WHEEL_LEFT>(
00136             boost::bind(
00137                   &tmouse_motion::signal_handler_sdl_wheel
00138                 , this, _2, _3, _5));
00139     owner_.connect_signal<event::SDL_WHEEL_RIGHT>(
00140             boost::bind(
00141                   &tmouse_motion::signal_handler_sdl_wheel
00142                 , this, _2, _3, _5));
00143 
00144     owner.connect_signal<event::SHOW_HELPTIP>(
00145           boost::bind(&tmouse_motion::signal_handler_show_helptip
00146               , this, _2, _3, _5)
00147         , queue_position);
00148 }
00149 
00150 tmouse_motion::~tmouse_motion()
00151 {
00152     stop_hover_timer();
00153 }
00154 
00155 void tmouse_motion::capture_mouse(//twidget* widget)
00156             const bool capture)
00157 {
00158     assert(mouse_focus_);
00159     mouse_captured_ = capture;
00160 }
00161 
00162 void tmouse_motion::signal_handler_sdl_mouse_motion(
00163           const event::tevent event
00164         , bool& handled
00165         , const tpoint& coordinate)
00166 {
00167     if(signal_handler_sdl_mouse_motion_entered_) {
00168         return;
00169     }
00170     tlock lock(signal_handler_sdl_mouse_motion_entered_);
00171 
00172     DBG_GUI_E << LOG_HEADER << event << ".\n";
00173 
00174     if(mouse_captured_) {
00175         assert(mouse_focus_);
00176         if(!owner_.fire(event, *mouse_focus_, coordinate)) {
00177             mouse_motion(mouse_focus_, coordinate);
00178         }
00179     } else {
00180         twidget* mouse_over = owner_.find_at(coordinate, true);
00181         if(mouse_over) {
00182             DBG_GUI_E << LOG_HEADER << "Firing: " << event << ".\n";
00183             if(owner_.fire(event, *mouse_over, coordinate)) {
00184                 return;
00185             }
00186         }
00187 
00188         if(!mouse_focus_ && mouse_over) {
00189             mouse_enter(mouse_over);
00190         } else if (mouse_focus_ && !mouse_over) {
00191             mouse_leave();
00192         } else if(mouse_focus_ && mouse_focus_ == mouse_over) {
00193             mouse_motion(mouse_over, coordinate);
00194         } else if(mouse_focus_ && mouse_over) {
00195             // moved from one widget to the next
00196             mouse_leave();
00197             mouse_enter(mouse_over);
00198         } else {
00199             assert(!mouse_focus_ && !mouse_over);
00200         }
00201     }
00202     handled = true;
00203 }
00204 
00205 void tmouse_motion::signal_handler_sdl_wheel(
00206           const event::tevent event
00207         , bool& handled
00208         , const tpoint& coordinate)
00209 {
00210     DBG_GUI_E << LOG_HEADER << event << ".\n";
00211 
00212     if(mouse_captured_) {
00213         assert(mouse_focus_);
00214         owner_.fire(event, *mouse_focus_, coordinate);
00215     } else {
00216         twidget* mouse_over = owner_.find_at(coordinate, true);
00217         if(mouse_over) {
00218             owner_.fire(event, *mouse_over, coordinate);
00219         }
00220     }
00221     handled = true;
00222 }
00223 
00224 void tmouse_motion::signal_handler_show_helptip(
00225           const event::tevent event
00226         , bool& handled
00227         , const tpoint& coordinate)
00228 {
00229     DBG_GUI_E << LOG_HEADER << event << ".\n";
00230 
00231     if(mouse_captured_) {
00232         assert(mouse_focus_);
00233         if(owner_.fire(event, *mouse_focus_, coordinate)) {
00234             stop_hover_timer();
00235         }
00236     } else {
00237         twidget* mouse_over = owner_.find_at(coordinate, true);
00238         if(mouse_over) {
00239             DBG_GUI_E << LOG_HEADER << "Firing: " << event << ".\n";
00240             if(owner_.fire(event, *mouse_over, coordinate)) {
00241                 stop_hover_timer();
00242             }
00243 
00244         }
00245     }
00246 
00247     handled = true;
00248 }
00249 
00250 void tmouse_motion::mouse_enter(twidget* mouse_over)
00251 {
00252     DBG_GUI_E << LOG_HEADER << "Firing: " << event::MOUSE_ENTER << ".\n";
00253 
00254     assert(mouse_over);
00255 
00256     mouse_focus_ = mouse_over;
00257     owner_.fire(event::MOUSE_ENTER, *mouse_over);
00258 
00259     hover_shown_ = false;
00260     start_hover_timer(mouse_over, get_mouse_position());
00261 }
00262 
00263 void tmouse_motion::mouse_motion(twidget* mouse_over, const tpoint& coordinate)
00264 {
00265     DBG_GUI_E << LOG_HEADER << "Firing: " << event::MOUSE_MOTION << ".\n";
00266 
00267     assert(mouse_over);
00268 
00269     owner_.fire(event::MOUSE_MOTION, *mouse_over, coordinate);
00270 
00271     if(hover_timer_) {
00272         if((abs(hover_position_.x - coordinate.x) > 5)
00273                 || (abs(hover_position_.y - coordinate.y) > 5)) {
00274 
00275             stop_hover_timer();
00276             start_hover_timer(mouse_over, coordinate);
00277         }
00278     }
00279 }
00280 
00281 void tmouse_motion::show_tooltip()
00282 {
00283     DBG_GUI_E << LOG_HEADER << "Firing: " << event::SHOW_TOOLTIP << ".\n";
00284 
00285     if(!hover_widget_) {
00286         // See tmouse_motion::stop_hover_timer.
00287         ERR_GUI_E << LOG_HEADER
00288                 << event::SHOW_TOOLTIP << " bailing out, no hover widget.\n";
00289         return;
00290     }
00291 
00292     /*
00293      * Ignore the result of the event, always mark the tooltip as shown. If
00294      * there was no handler, there is no reason to assume there will be one
00295      * next time.
00296      */
00297     owner_.fire(SHOW_TOOLTIP, *hover_widget_, hover_position_);
00298 
00299     hover_shown_ = true;
00300 
00301     hover_timer_ = 0;
00302     hover_widget_ = NULL;
00303     hover_position_ = tpoint(0, 0);
00304 }
00305 
00306 void tmouse_motion::mouse_leave()
00307 {
00308     DBG_GUI_E << LOG_HEADER << "Firing: " << event::MOUSE_LEAVE << ".\n";
00309 
00310     tcontrol* control = dynamic_cast<tcontrol*>(mouse_focus_);
00311     if(!control || control->get_active()) {
00312         owner_.fire(event::MOUSE_LEAVE, *mouse_focus_);
00313     }
00314 
00315     owner_.fire(NOTIFY_REMOVE_TOOLTIP, *mouse_focus_, NULL);
00316 
00317     mouse_focus_ = NULL;
00318 
00319     stop_hover_timer();
00320 }
00321 
00322 void tmouse_motion::start_hover_timer(twidget* widget, const tpoint& coordinate)
00323 {
00324     assert(widget);
00325     stop_hover_timer();
00326 
00327     if(hover_shown_ || !widget->wants_mouse_hover()) {
00328         return;
00329     }
00330 
00331     DBG_GUI_E << LOG_HEADER << "Start hover timer for widget '"
00332             << widget->id() << "' at address " << widget << ".\n";
00333 
00334     hover_timer_ = add_timer(
00335               50
00336             , boost::bind(&tmouse_motion::show_tooltip, this));
00337 
00338     if(hover_timer_) {
00339         hover_widget_ = widget;
00340         hover_position_ = coordinate;
00341     } else {
00342         ERR_GUI_E << LOG_HEADER << "Failed to add hover timer.\n";
00343     }
00344 }
00345 
00346 void tmouse_motion::stop_hover_timer()
00347 {
00348     if(hover_timer_) {
00349         assert(hover_widget_);
00350         DBG_GUI_E << LOG_HEADER << "Stop hover timer for widget '"
00351                 << hover_widget_->id() << "' at address "
00352                 << hover_widget_ << ".\n";
00353 
00354         if(!remove_timer(hover_timer_)) {
00355             ERR_GUI_E << LOG_HEADER << "Failed to remove hover timer.\n";
00356         }
00357 
00358         hover_timer_ = 0;
00359         hover_widget_ = NULL;
00360         hover_position_ = tpoint(0, 0);
00361     }
00362 }
00363 
00364 /***** ***** ***** ***** tmouse_button ***** ***** ***** ***** *****/
00365 
00366 #undef LOG_HEADER
00367 #define LOG_HEADER "distributor mouse button " \
00368         << name_ << " [" << owner_.id() << "]: "
00369 
00370 template<
00371           tevent sdl_button_down
00372         , tevent sdl_button_up
00373         , tevent button_down
00374         , tevent button_up
00375         , tevent button_click
00376         , tevent button_double_click
00377 > tmouse_button<
00378           sdl_button_down
00379         , sdl_button_up
00380         , button_down
00381         , button_up
00382         , button_click
00383         , button_double_click
00384 >::tmouse_button(
00385               const std::string& name_
00386             , twidget& owner
00387             , const tdispatcher::tposition queue_position)
00388     : tmouse_motion(owner, queue_position)
00389     , last_click_stamp_(0)
00390     , last_clicked_widget_(NULL)
00391     , focus_(0)
00392     , name_(name_)
00393     , is_down_(false)
00394     , signal_handler_sdl_button_down_entered_(false)
00395     , signal_handler_sdl_button_up_entered_(false)
00396 {
00397     owner_.connect_signal<sdl_button_down>(
00398               boost::bind(&tmouse_button<
00399                   sdl_button_down
00400                 , sdl_button_up
00401                 , button_down
00402                 , button_up
00403                 , button_click
00404                 , button_double_click
00405                 >::signal_handler_sdl_button_down, this, _2, _3, _5)
00406             , queue_position);
00407     owner_.connect_signal<sdl_button_up>(
00408               boost::bind(&tmouse_button<
00409                   sdl_button_down
00410                 , sdl_button_up
00411                 , button_down
00412                 , button_up
00413                 , button_click
00414                 , button_double_click
00415                 >::signal_handler_sdl_button_up, this, _2, _3, _5)
00416             , queue_position);
00417 }
00418 
00419 template<
00420           tevent sdl_button_down
00421         , tevent sdl_button_up
00422         , tevent button_down
00423         , tevent button_up
00424         , tevent button_click
00425         , tevent button_double_click
00426 > void tmouse_button<
00427           sdl_button_down
00428         , sdl_button_up
00429         , button_down
00430         , button_up
00431         , button_click
00432         , button_double_click
00433 >::initialize_state(const bool is_down)
00434 {
00435     last_click_stamp_ = 0;
00436     last_clicked_widget_ = NULL;
00437     focus_ = 0;
00438     is_down_ = is_down;
00439 }
00440 
00441 template<
00442           tevent sdl_button_down
00443         , tevent sdl_button_up
00444         , tevent button_down
00445         , tevent button_up
00446         , tevent button_click
00447         , tevent button_double_click
00448 > void tmouse_button<
00449           sdl_button_down
00450         , sdl_button_up
00451         , button_down
00452         , button_up
00453         , button_click
00454         , button_double_click
00455 >::signal_handler_sdl_button_down(
00456           const event::tevent event
00457         , bool& handled
00458         , const tpoint& coordinate)
00459 {
00460     if(signal_handler_sdl_button_down_entered_) {
00461         return;
00462     }
00463     tlock lock(signal_handler_sdl_button_down_entered_);
00464 
00465     DBG_GUI_E << LOG_HEADER << event << ".\n";
00466 
00467     if(is_down_) {
00468         WRN_GUI_E << LOG_HEADER << event
00469                 << ". The mouse button is already down, "
00470                 << "we missed an event.\n";
00471         return;
00472     }
00473     is_down_ = true;
00474 
00475     if(mouse_captured_) {
00476         assert(mouse_focus_);
00477         focus_ = mouse_focus_;
00478         DBG_GUI_E << LOG_HEADER << "Firing: " << sdl_button_down << ".\n";
00479         if(!owner_.fire(sdl_button_down, *focus_, coordinate)) {
00480             DBG_GUI_E << LOG_HEADER << "Firing: " << button_down << ".\n";
00481             owner_.fire(button_down, *mouse_focus_);
00482         }
00483     } else {
00484         twidget* mouse_over = owner_.find_at(coordinate, true);
00485         if(!mouse_over) {
00486             return;
00487         }
00488 
00489         if(mouse_over != mouse_focus_) {
00490             WRN_GUI_E << LOG_HEADER
00491                     << ". Mouse down on non focussed widget "
00492                     << "and mouse not captured, we missed events.\n";
00493             mouse_focus_ = mouse_over;
00494         }
00495 
00496         focus_ = mouse_over;
00497         DBG_GUI_E << LOG_HEADER << "Firing: " << sdl_button_down << ".\n";
00498         if(!owner_.fire(sdl_button_down, *focus_, coordinate)) {
00499             DBG_GUI_E << LOG_HEADER << "Firing: " << button_down << ".\n";
00500             owner_.fire(button_down, *focus_);
00501         }
00502     }
00503     handled = true;
00504 }
00505 
00506 template<
00507           tevent sdl_button_down
00508         , tevent sdl_button_up
00509         , tevent button_down
00510         , tevent button_up
00511         , tevent button_click
00512         , tevent button_double_click
00513 > void tmouse_button<
00514           sdl_button_down
00515         , sdl_button_up
00516         , button_down
00517         , button_up
00518         , button_click
00519         , button_double_click
00520 >::signal_handler_sdl_button_up(
00521           const event::tevent event
00522         , bool& handled
00523         , const tpoint& coordinate)
00524 {
00525     if(signal_handler_sdl_button_up_entered_) {
00526         return;
00527     }
00528     tlock lock(signal_handler_sdl_button_up_entered_);
00529 
00530     DBG_GUI_E << LOG_HEADER << event << ".\n";
00531 
00532     if(!is_down_) {
00533         WRN_GUI_E << LOG_HEADER << event
00534                 << ". The mouse button is already up, we missed an event.\n";
00535         return;
00536     }
00537     is_down_ = false;
00538 
00539     if(focus_) {
00540         DBG_GUI_E << LOG_HEADER << "Firing: " << sdl_button_up << ".\n";
00541         if(!owner_.fire(sdl_button_up, *focus_, coordinate)) {
00542             DBG_GUI_E << LOG_HEADER << "Firing: " << button_up << ".\n";
00543             owner_.fire(button_up, *focus_);
00544         }
00545     }
00546 
00547     twidget* mouse_over = owner_.find_at(coordinate, true);
00548     if(mouse_captured_) {
00549         const unsigned mask =
00550                 SDL_BUTTON_LMASK | SDL_BUTTON_MMASK | SDL_BUTTON_RMASK;
00551 
00552         if((SDL_GetMouseState(NULL, NULL) & mask ) == 0) {
00553             mouse_captured_ = false;
00554         }
00555 
00556         if(mouse_focus_ == mouse_over) {
00557             mouse_button_click(mouse_focus_);
00558         } else if(!mouse_captured_) {
00559             mouse_leave();
00560 
00561             if(mouse_over) {
00562                 mouse_enter(mouse_over);
00563             }
00564         }
00565     } else if(focus_ && focus_ == mouse_over) {
00566         mouse_button_click(focus_);
00567     }
00568 
00569     focus_ = NULL;
00570     handled = true;
00571 }
00572 
00573 template<
00574           tevent sdl_button_down
00575         , tevent sdl_button_up
00576         , tevent button_down
00577         , tevent button_up
00578         , tevent button_click
00579         , tevent button_double_click
00580 > void tmouse_button<
00581           sdl_button_down
00582         , sdl_button_up
00583         , button_down
00584         , button_up
00585         , button_click
00586         , button_double_click
00587 >::mouse_button_click(twidget* widget)
00588 {
00589     Uint32 stamp = SDL_GetTicks();
00590     if(last_click_stamp_ + settings::double_click_time >= stamp
00591             && last_clicked_widget_ == widget) {
00592 
00593         DBG_GUI_E << LOG_HEADER << "Firing: "
00594                 << button_double_click << ".\n";
00595 
00596         owner_.fire(button_double_click, *widget);
00597         last_click_stamp_ = 0;
00598         last_clicked_widget_ = NULL;
00599 
00600     } else {
00601 
00602         DBG_GUI_E << LOG_HEADER << "Firing: " << button_click << ".\n";
00603         owner_.fire(button_click, *widget);
00604         last_click_stamp_ = stamp;
00605         last_clicked_widget_ = widget;
00606     }
00607 }
00608 
00609 /***** ***** ***** ***** tdistributor ***** ***** ***** ***** *****/
00610 
00611 #undef LOG_HEADER
00612 #define LOG_HEADER "distributor mouse motion [" << owner_.id() << "]: "
00613 
00614 /**
00615  * @todo Test wehether the state is properly tracked when an input blocker is
00616  * used.
00617  */
00618 tdistributor::tdistributor(twidget& owner
00619         , const tdispatcher::tposition queue_position)
00620     : tmouse_motion(owner, queue_position)
00621     , tmouse_button_left("left"
00622             , owner
00623             , queue_position)
00624     , tmouse_button_middle("middle"
00625             , owner
00626             , queue_position)
00627     , tmouse_button_right("right"
00628             , owner
00629             , queue_position)
00630     , hover_pending_(false)
00631     , hover_id_(0)
00632     , hover_box_()
00633     , had_hover_(false)
00634     , tooltip_(0)
00635     , help_popup_(0)
00636     , keyboard_focus_(0)
00637     , keyboard_focus_chain_()
00638 {
00639     if(SDL_WasInit(SDL_INIT_TIMER) == 0) {
00640         if(SDL_InitSubSystem(SDL_INIT_TIMER) == -1) {
00641             assert(false);
00642         }
00643     }
00644 
00645     owner_.connect_signal<event::SDL_KEY_DOWN>(
00646             boost::bind(&tdistributor::signal_handler_sdl_key_down
00647                 , this, _5, _6, _7));
00648 
00649     owner_.connect_signal<event::NOTIFY_REMOVAL>(
00650             boost::bind(
00651                   &tdistributor::signal_handler_notify_removal
00652                 , this
00653                 , _1
00654                 , _2));
00655 
00656     initialize_state();
00657 }
00658 
00659 tdistributor::~tdistributor()
00660 {
00661     owner_.disconnect_signal<event::SDL_KEY_DOWN>(
00662             boost::bind(&tdistributor::signal_handler_sdl_key_down
00663                 , this, _5, _6, _7));
00664 
00665     owner_.disconnect_signal<event::NOTIFY_REMOVAL>(
00666             boost::bind(
00667                   &tdistributor::signal_handler_notify_removal
00668                 , this
00669                 , _1
00670                 , _2));
00671 }
00672 
00673 void tdistributor::initialize_state()
00674 {
00675     const Uint8 button_state = SDL_GetMouseState(NULL, NULL);
00676 
00677     tmouse_button_left::initialize_state(button_state & SDL_BUTTON(1));
00678     tmouse_button_middle::initialize_state(button_state & SDL_BUTTON(2));
00679     tmouse_button_right::initialize_state(button_state & SDL_BUTTON(3));
00680 
00681     init_mouse_location();
00682 }
00683 
00684 void tdistributor::keyboard_capture(twidget* widget)
00685 {
00686     if(keyboard_focus_) {
00687         DBG_GUI_E << LOG_HEADER << "Firing: "
00688                 << event::LOSE_KEYBOARD_FOCUS << ".\n";
00689 
00690         owner_.fire(event::LOSE_KEYBOARD_FOCUS, *keyboard_focus_, NULL);
00691     }
00692 
00693     keyboard_focus_ = widget;
00694 
00695     if(keyboard_focus_) {
00696         DBG_GUI_E << LOG_HEADER << "Firing: "
00697                 << event::RECEIVE_KEYBOARD_FOCUS << ".\n";
00698 
00699         owner_.fire(event::RECEIVE_KEYBOARD_FOCUS, *keyboard_focus_, NULL);
00700     }
00701 }
00702 
00703 void tdistributor::keyboard_add_to_chain(twidget* widget)
00704 {
00705     assert(widget);
00706     assert(std::find(keyboard_focus_chain_.begin()
00707                 , keyboard_focus_chain_.end()
00708                 , widget)
00709             == keyboard_focus_chain_.end());
00710 
00711     keyboard_focus_chain_.push_back(widget);
00712 }
00713 
00714 void tdistributor::keyboard_remove_from_chain(twidget* widget)
00715 {
00716     assert(widget);
00717     std::vector<twidget*>::iterator itor = std::find(
00718         keyboard_focus_chain_.begin(), keyboard_focus_chain_.end(), widget);
00719 
00720     if(itor != keyboard_focus_chain_.end()) {
00721         keyboard_focus_chain_.erase(itor);
00722     }
00723 }
00724 
00725 void tdistributor::signal_handler_sdl_key_down(const SDLKey key
00726         , const SDLMod modifier
00727         , const Uint16 unicode)
00728 {
00729     /** @todo Test whether recursion protection is needed. */
00730 
00731     DBG_GUI_E << LOG_HEADER << event::SDL_KEY_DOWN << ".\n";
00732 
00733     if(keyboard_focus_) {
00734         // Attempt to cast to control, to avoid sending events if the
00735         // widget is disabled. If the cast fails, we assume the widget
00736         // is enabled and ready to receive events.
00737         tcontrol* control = dynamic_cast<tcontrol*>(keyboard_focus_);
00738         if(!control || control->get_active()) {
00739             DBG_GUI_E << LOG_HEADER << "Firing: " << event::SDL_KEY_DOWN << ".\n";
00740             if(owner_.fire(event::SDL_KEY_DOWN
00741                     , *keyboard_focus_, key, modifier, unicode)) {
00742                 return;
00743             }
00744         }
00745     }
00746 
00747     for(std::vector<twidget*>::reverse_iterator
00748                 ritor = keyboard_focus_chain_.rbegin()
00749             ; ritor != keyboard_focus_chain_.rend()
00750             ; ++ritor) {
00751 
00752         if(*ritor == keyboard_focus_) {
00753             continue;
00754         }
00755 
00756         if(*ritor == &owner_) {
00757             /**
00758              * @todo Make sure we're not in the event chain.
00759              *
00760              * No idea why we're here, but needs to be fixed, otherwise we keep
00761              * calling this function recursively upon unhandled events...
00762              *
00763              * Probably added to make sure the window can grab the events and
00764              * handle + block them when needed, this is no longer needed with
00765              * the chain.
00766              */
00767             continue;
00768         }
00769 
00770         // Attempt to cast to control, to avoid sending events if the
00771         // widget is disabled. If the cast fails, we assume the widget
00772         // is enabled and ready to receive events.
00773         tcontrol* control = dynamic_cast<tcontrol*>(keyboard_focus_);
00774         if(control != NULL && !control->get_active()) {
00775             continue;
00776         }
00777 
00778         DBG_GUI_E << LOG_HEADER << "Firing: " << event::SDL_KEY_DOWN << ".\n";
00779         if(owner_.fire(event::SDL_KEY_DOWN
00780                 , **ritor, key, modifier, unicode)) {
00781 
00782             return;
00783         }
00784     }
00785 }
00786 
00787 void tdistributor::signal_handler_notify_removal(
00788             tdispatcher& widget, const tevent event)
00789 {
00790     DBG_GUI_E << LOG_HEADER << event << ".\n";
00791 
00792     /**
00793      * @todo Evaluate whether moving the cleanup parts in the subclasses.
00794      *
00795      * It might be cleaner to do it that way, but creates extra small
00796      * functions...
00797      */
00798 
00799     if(hover_widget_ == &widget) {
00800         stop_hover_timer();
00801     }
00802 
00803     if(tmouse_button_left::last_clicked_widget_ == &widget) {
00804         tmouse_button_left::last_clicked_widget_ = NULL;
00805     }
00806     if(tmouse_button_left::focus_ == &widget) {
00807         tmouse_button_left::focus_ = NULL;
00808     }
00809 
00810     if(tmouse_button_middle::last_clicked_widget_ == &widget) {
00811         tmouse_button_middle::last_clicked_widget_ = NULL;
00812     }
00813     if(tmouse_button_middle::focus_ == &widget) {
00814         tmouse_button_middle::focus_ = NULL;
00815     }
00816 
00817     if(tmouse_button_right::last_clicked_widget_ == &widget) {
00818         tmouse_button_right::last_clicked_widget_ = NULL;
00819     }
00820     if(tmouse_button_right::focus_ == &widget) {
00821         tmouse_button_right::focus_ = NULL;
00822     }
00823 
00824     if(mouse_focus_ == &widget) {
00825         mouse_focus_ = NULL;
00826     }
00827 
00828     if(keyboard_focus_ == &widget) {
00829         keyboard_focus_ = NULL;
00830     }
00831     const std::vector<twidget*>::iterator itor = std::find(
00832               keyboard_focus_chain_.begin()
00833             , keyboard_focus_chain_.end()
00834             , &widget);
00835     if(itor != keyboard_focus_chain_.end()) {
00836         keyboard_focus_chain_.erase(itor);
00837     }
00838 }
00839 
00840 } // namespace event
00841 
00842 } // namespace gui2
00843 
 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