gui.cpp

00001 /*      _______   __   __   __   ______   __   __   _______   __   __
00002  *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
00003  *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
00004  *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
00005  *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
00006  * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
00007  * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
00008  *
00009  * Copyright (c) 2004, 2005, 2006, 2007 Olof Naessén and Per Larsson
00010  *
00011  *                                                         Js_./
00012  * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
00013  * Olof Naessén a.k.a jansem/yakslem                _asww7!uY`>  )\a//
00014  *                                                 _Qhm`] _f "'c  1!5m
00015  * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
00016  *                                               .)j(] .d_/ '-(  P .   S
00017  * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
00018  * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
00019  * binary forms, with or without                 )4d[#7r, .   '     )d`)[
00020  * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
00021  * that the following conditions are met:       j<<WP+k/);.        _W=j f
00022  * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
00023  *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
00024  *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
00025  *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
00026  * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
00027  *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
00028  *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
00029  *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
00030  *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
00031  *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
00032  * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
00033  *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
00034  *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
00035  *    from this software without specific        (js, \[QQW$QWW#?!V"".
00036  *    prior written permission.                    ]y:.<\..          .
00037  *                                                 -]n w/ '         [.
00038  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
00039  * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
00040  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
00041  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
00042  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
00043  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
00044  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
00045  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
00046  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
00047  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
00048  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
00049  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
00050  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00051  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00052  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00053  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00054  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00055  */
00056 
00057 /*
00058  * For comments regarding functions please see the header file.
00059  */
00060 
00061 #include "guichan/gui.hpp"
00062 
00063 #include "guichan/basiccontainer.hpp"
00064 #include "guichan/exception.hpp"
00065 #include "guichan/focushandler.hpp"
00066 #include "guichan/graphics.hpp"
00067 #include "guichan/input.hpp"
00068 #include "guichan/keyinput.hpp"
00069 #include "guichan/keylistener.hpp"
00070 #include "guichan/mouseinput.hpp"
00071 #include "guichan/mouselistener.hpp"
00072 #include "guichan/widget.hpp"
00073 
00074 namespace gcn
00075 {
00076     Gui::Gui()
00077             :mTop(NULL),
00078              mGraphics(NULL),
00079              mInput(NULL),
00080              mTabbing(true),
00081              mShiftPressed(false),
00082              mMetaPressed(false),
00083              mControlPressed(false),
00084              mAltPressed(false),
00085              mLastMousePressButton(0),
00086              mLastMousePressTimeStamp(0),
00087              mLastMouseX(0),
00088              mLastMouseY(0),
00089              mClickCount(1),
00090              mLastMouseDragButton(0)
00091     {
00092         mFocusHandler = new FocusHandler();
00093     }
00094 
00095     Gui::~Gui()
00096     {
00097         if (Widget::widgetExists(mTop))
00098         {
00099             setTop(NULL);
00100         }
00101 
00102         delete mFocusHandler;
00103     }
00104 
00105     void Gui::setTop(Widget* top)
00106     {
00107         if (mTop != NULL)
00108         {
00109             mTop->_setFocusHandler(NULL);
00110         }
00111         if (top != NULL)
00112         {
00113             top->_setFocusHandler(mFocusHandler);
00114         }
00115 
00116         mTop = top;
00117     }
00118 
00119     Widget* Gui::getTop() const
00120     {
00121         return mTop;
00122     }
00123 
00124     void Gui::setGraphics(Graphics* graphics)
00125     {
00126         mGraphics = graphics;
00127     }
00128 
00129     Graphics* Gui::getGraphics() const
00130     {
00131         return mGraphics;
00132     }
00133 
00134     void Gui::setInput(Input* input)
00135     {
00136         mInput = input;
00137     }
00138 
00139     Input* Gui::getInput() const
00140     {
00141         return mInput;
00142     }
00143 
00144     void Gui::logic()
00145     {
00146         if (mTop == NULL)
00147         {
00148             throw GCN_EXCEPTION("No top widget set");
00149         }
00150 
00151         handleModalFocus();
00152         handleModalMouseInputFocus();
00153 
00154         if (mInput != NULL)
00155         {
00156             mInput->_pollInput();
00157 
00158             handleKeyInput();
00159             handleMouseInput();
00160  
00161         } // end if
00162 
00163         mTop->logic();
00164     }
00165 
00166     void Gui::draw()
00167     {
00168         if (mTop == NULL)
00169         {
00170             throw GCN_EXCEPTION("No top widget set");
00171         }
00172         if (mGraphics == NULL)
00173         {
00174             throw GCN_EXCEPTION("No graphics set");
00175         }
00176 
00177         if (!mTop->isVisible())
00178         {
00179             return;
00180         }
00181 
00182         mGraphics->_beginDraw();
00183 
00184         // If top has a frame,
00185         // draw it before drawing top
00186         if (mTop->getFrameSize() > 0)
00187         {
00188             Rectangle rec = mTop->getDimension();
00189             rec.x -= mTop->getFrameSize();
00190             rec.y -= mTop->getFrameSize();
00191             rec.width += 2 * mTop->getFrameSize();
00192             rec.height += 2 * mTop->getFrameSize();
00193             mGraphics->pushClipArea(rec);
00194             mTop->drawFrame(mGraphics);
00195             mGraphics->popClipArea();
00196         }
00197 
00198         mGraphics->pushClipArea(mTop->getDimension());
00199         mTop->draw(mGraphics);
00200         mGraphics->popClipArea();
00201 
00202         mGraphics->_endDraw();
00203     }
00204 
00205     void Gui::focusNone()
00206     {
00207         mFocusHandler->focusNone();
00208     }
00209 
00210     void Gui::setTabbingEnabled(bool tabbing)
00211     {
00212         mTabbing = tabbing;
00213     }
00214 
00215     bool Gui::isTabbingEnabled()
00216     {
00217         return mTabbing;
00218     }
00219 
00220     void Gui::addGlobalKeyListener(KeyListener* keyListener)
00221     {
00222         mKeyListeners.push_back(keyListener);
00223     }
00224 
00225     void Gui::removeGlobalKeyListener(KeyListener* keyListener)
00226     {
00227         mKeyListeners.remove(keyListener);
00228     }
00229 
00230     void Gui::handleMouseInput()
00231     {
00232         while (!mInput->isMouseQueueEmpty())
00233          {
00234              MouseInput mouseInput = mInput->dequeueMouseInput();
00235 
00236              // Save the current mouse state. It will be needed if modal focus
00237              // changes or modal mouse input focus changes.
00238              mLastMouseX = mouseInput.getX();
00239              mLastMouseY = mouseInput.getY();
00240 
00241              switch (mouseInput.getType())
00242              {
00243                case MouseInput::PRESSED:
00244                    handleMousePressed(mouseInput);
00245                    break;
00246                case MouseInput::RELEASED:
00247                    handleMouseReleased(mouseInput);
00248                    break;
00249                case MouseInput::MOVED:
00250                    handleMouseMoved(mouseInput);
00251                    break;
00252                case MouseInput::WHEEL_MOVED_DOWN:
00253                    handleMouseWheelMovedDown(mouseInput);
00254                    break;
00255                case MouseInput::WHEEL_MOVED_UP:
00256                    handleMouseWheelMovedUp(mouseInput);
00257                    break;
00258                default:
00259                    throw GCN_EXCEPTION("Unknown mouse input type.");
00260                    break;
00261              }
00262          }
00263     }
00264 
00265     void Gui::handleKeyInput()
00266     {
00267         while (!mInput->isKeyQueueEmpty())
00268         {
00269             KeyInput keyInput = mInput->dequeueKeyInput();
00270 
00271             // Save modifiers state
00272             mShiftPressed = keyInput.isShiftPressed();
00273             mMetaPressed = keyInput.isMetaPressed();
00274             mControlPressed = keyInput.isControlPressed();
00275             mAltPressed = keyInput.isAltPressed();
00276 
00277             KeyEvent keyEventToGlobalKeyListeners(NULL,
00278                                                   mShiftPressed,
00279                                                   mControlPressed,
00280                                                   mAltPressed,
00281                                                   mMetaPressed,
00282                                                   keyInput.getType(),
00283                                                   keyInput.isNumericPad(),
00284                                                   keyInput.getKey());
00285 
00286             distributeKeyEventToGlobalKeyListeners(keyEventToGlobalKeyListeners);
00287 
00288             // If a global key listener consumes the event it will not be
00289             // sent further to the source of the event.
00290             if (keyEventToGlobalKeyListeners.isConsumed())
00291             {
00292                 continue;
00293             }
00294 
00295             bool keyEventConsumed = false;
00296             
00297             // Send key inputs to the focused widgets
00298             if (mFocusHandler->getFocused() != NULL)
00299             {
00300                 KeyEvent keyEvent(getKeyEventSource(),
00301                                   mShiftPressed,
00302                                   mControlPressed,
00303                                   mAltPressed,
00304                                   mMetaPressed,
00305                                   keyInput.getType(),
00306                                   keyInput.isNumericPad(),
00307                                   keyInput.getKey());
00308                 
00309 
00310                 if (!mFocusHandler->getFocused()->isFocusable())
00311                 {
00312                     mFocusHandler->focusNone();
00313                 }
00314                 else
00315                 {                    
00316                     distributeKeyEvent(keyEvent);                    
00317                 }
00318 
00319                 keyEventConsumed = keyEvent.isConsumed();
00320             }
00321 
00322             // If the key event hasn't been consumed and
00323             // tabbing is enable check for tab press and
00324             // change focus.
00325             if (!keyEventConsumed
00326                 && mTabbing
00327                 && keyInput.getKey().getValue() == Key::TAB
00328                 && keyInput.getType() == KeyInput::PRESSED)
00329             {
00330                 if (keyInput.isShiftPressed())
00331                 {
00332                     mFocusHandler->tabPrevious();
00333                 }
00334                 else
00335                 {
00336                     mFocusHandler->tabNext();
00337                 }
00338             }                           
00339                 
00340         } // end while
00341     }
00342 
00343     void Gui::handleMouseMoved(const MouseInput& mouseInput)
00344     {
00345         // Check if the mouse leaves the application window.
00346         if (!mWidgetWithMouseQueue.empty()
00347             && (mouseInput.getX() < 0
00348                 || mouseInput.getY() < 0
00349                 || !mTop->getDimension().isPointInRect(mouseInput.getX(), mouseInput.getY()))
00350             )
00351         {
00352             // Distribute an event to all widgets in the "widget with mouse" queue.
00353             while (!mWidgetWithMouseQueue.empty())
00354             {
00355                 Widget* widget = mWidgetWithMouseQueue.front();
00356 
00357                 if (Widget::widgetExists(widget))
00358                 {
00359                     distributeMouseEvent(widget,
00360                                          MouseEvent::EXITED,
00361                                          mouseInput.getButton(),
00362                                          mouseInput.getX(),
00363                                          mouseInput.getX(),
00364                                          true,
00365                                          true);
00366                 }
00367 
00368                 mWidgetWithMouseQueue.pop_front();
00369             }
00370 
00371             return;
00372         }
00373 
00374         // Check if there is a need to send mouse exited events by
00375         // traversing the "widget with mouse" queue.
00376         bool widgetWithMouseQueueCheckDone = mWidgetWithMouseQueue.empty();
00377         while (!widgetWithMouseQueueCheckDone)
00378         {
00379             unsigned int iterations = 0;
00380             std::deque<Widget*>::iterator iter;
00381             for (iter = mWidgetWithMouseQueue.begin();
00382                  iter != mWidgetWithMouseQueue.end();
00383                  iter++)
00384             {
00385                 Widget* widget = *iter;
00386                             
00387                 // If a widget in the "widget with mouse queue" doesn't
00388                 // exists anymore it should be removed from the queue.
00389                 if (!Widget::widgetExists(widget))
00390                 {
00391                     mWidgetWithMouseQueue.erase(iter);
00392                     break;
00393                 }
00394                 else
00395                 {
00396                     int x, y;
00397                     widget->getAbsolutePosition(x, y);
00398 
00399                     if (x > mouseInput.getX()
00400                         || y > mouseInput.getY()
00401                         || x + widget->getWidth() <= mouseInput.getX()
00402                         || y + widget->getHeight() <= mouseInput.getY()
00403                         || !widget->isVisible())
00404                     {
00405                         distributeMouseEvent(widget,
00406                                              MouseEvent::EXITED,
00407                                              mouseInput.getButton(),
00408                                              mouseInput.getX(),
00409                                              mouseInput.getX(),
00410                                              true,
00411                                              true);                                       
00412                         mClickCount = 1;
00413                         mLastMousePressTimeStamp = 0;
00414                         mWidgetWithMouseQueue.erase(iter);
00415                         break;
00416                     }
00417                 }
00418 
00419                 iterations++;
00420             }
00421 
00422             widgetWithMouseQueueCheckDone = iterations == mWidgetWithMouseQueue.size();
00423         }
00424 
00425         // Check all widgets below the mouse to see if they are
00426         // present in the "widget with mouse" queue. If a widget
00427         // is not then it should be added and an entered event should
00428         // be sent to it.
00429         Widget* parent = getMouseEventSource(mouseInput.getX(), mouseInput.getY());
00430         Widget* widget = parent;
00431 
00432         // If a widget has modal mouse input focus then it will
00433         // always be returned from getMouseEventSource, but we only wan't to send
00434         // mouse entered events if the mouse has actually entered the widget with
00435         // modal mouse input focus, hence we need to check if that's the case. If
00436         // it's not we should simply ignore to send any mouse entered events.
00437         if (mFocusHandler->getModalMouseInputFocused() != NULL
00438             && widget == mFocusHandler->getModalMouseInputFocused()
00439             && Widget::widgetExists(widget))
00440         {
00441             int x, y;
00442             widget->getAbsolutePosition(x, y);
00443 
00444             if (x > mouseInput.getX()
00445                 || y > mouseInput.getY()
00446                 || x + widget->getWidth() <= mouseInput.getX() 
00447                 || y + widget->getHeight() <= mouseInput.getY())
00448             {
00449                 parent = NULL;
00450             }
00451         }
00452 
00453         while (parent != NULL)
00454         {
00455             parent = (Widget*)widget->getParent();
00456 
00457             // Check if the widget is present in the "widget with mouse" queue.
00458             bool widgetIsPresentInQueue = false;
00459             std::deque<Widget*>::iterator iter;
00460             for (iter = mWidgetWithMouseQueue.begin();
00461                  iter != mWidgetWithMouseQueue.end();
00462                  iter++)
00463             {
00464                 if (*iter == widget)
00465                 {
00466                     widgetIsPresentInQueue = true;
00467                     break;
00468                 }
00469             }
00470 
00471             // Widget is not present, send an entered event and add
00472             // it to the "widget with mouse" queue.
00473             if (!widgetIsPresentInQueue
00474                 && Widget::widgetExists(widget))
00475             {
00476                 distributeMouseEvent(widget,
00477                                      MouseEvent::ENTERED,
00478                                      mouseInput.getButton(),
00479                                      mouseInput.getX(),
00480                                      mouseInput.getY(),
00481                                      true,
00482                                      true);
00483                 mWidgetWithMouseQueue.push_front(widget);
00484             }
00485 
00486             Widget* swap = widget;
00487             widget = parent;
00488             parent = (Widget*)swap->getParent();
00489         }
00490 
00491         if (mFocusHandler->getDraggedWidget() != NULL)
00492         {
00493             distributeMouseEvent(mFocusHandler->getDraggedWidget(),
00494                                  MouseEvent::DRAGGED,
00495                                  mLastMouseDragButton,
00496                                  mouseInput.getX(),
00497                                  mouseInput.getY());
00498         }
00499         else
00500         {
00501             Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY());
00502             distributeMouseEvent(sourceWidget,
00503                                  MouseEvent::MOVED,
00504                                  mouseInput.getButton(),
00505                                  mouseInput.getX(),
00506                                  mouseInput.getY());
00507         }
00508     }
00509 
00510     void Gui::handleMousePressed(const MouseInput& mouseInput)
00511     {
00512         Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY());
00513 
00514         if (mFocusHandler->getDraggedWidget() != NULL)
00515         {
00516             sourceWidget = mFocusHandler->getDraggedWidget();
00517         }
00518 
00519         int sourceWidgetX, sourceWidgetY;
00520         sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY);
00521         
00522         distributeMouseEvent(sourceWidget,
00523                              MouseEvent::PRESSED,
00524                              mouseInput.getButton(),
00525                              mouseInput.getX(),
00526                              mouseInput.getY());
00527 
00528         mFocusHandler->setLastWidgetPressed(sourceWidget);
00529         
00530         if (mFocusHandler->getModalFocused() != NULL
00531             && sourceWidget->isModalFocused()
00532             || mFocusHandler->getModalFocused() == NULL)
00533         {
00534             sourceWidget->requestFocus();
00535         }
00536 
00537         mFocusHandler->setDraggedWidget(sourceWidget);
00538         mLastMouseDragButton = mouseInput.getButton();
00539 
00540         if (mLastMousePressTimeStamp < 300
00541             && mLastMousePressButton == mouseInput.getButton())
00542         {
00543             mClickCount++;
00544         }
00545         else
00546         {
00547             mClickCount = 1;
00548         }
00549 
00550         mLastMousePressButton = mouseInput.getButton();
00551         mLastMousePressTimeStamp = mouseInput.getTimeStamp();
00552     }
00553 
00554     void Gui::handleMouseWheelMovedDown(const MouseInput& mouseInput)
00555     {
00556         Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY());
00557 
00558         if (mFocusHandler->getDraggedWidget() != NULL)
00559         {
00560             sourceWidget = mFocusHandler->getDraggedWidget();
00561         }
00562 
00563         int sourceWidgetX, sourceWidgetY;
00564         sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY);
00565 
00566         distributeMouseEvent(sourceWidget,
00567                              MouseEvent::WHEEL_MOVED_DOWN,
00568                              mouseInput.getButton(),
00569                              mouseInput.getX(),
00570                              mouseInput.getY());
00571     }
00572 
00573     void Gui::handleMouseWheelMovedUp(const MouseInput& mouseInput)
00574     {
00575         Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY());
00576 
00577         if (mFocusHandler->getDraggedWidget() != NULL)
00578         {
00579             sourceWidget = mFocusHandler->getDraggedWidget();
00580         }
00581 
00582         int sourceWidgetX, sourceWidgetY;
00583         sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY);
00584 
00585         distributeMouseEvent(sourceWidget,
00586                              MouseEvent::WHEEL_MOVED_UP,
00587                              mouseInput.getButton(),
00588                              mouseInput.getX(),
00589                              mouseInput.getY());
00590     }
00591 
00592     void Gui::handleMouseReleased(const MouseInput& mouseInput)
00593     {
00594         Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY());
00595 
00596         if (mFocusHandler->getDraggedWidget() != NULL)
00597         {
00598             if (sourceWidget != mFocusHandler->getLastWidgetPressed())
00599             {
00600                 mFocusHandler->setLastWidgetPressed(NULL);
00601             }
00602             
00603             sourceWidget = mFocusHandler->getDraggedWidget();
00604         }
00605 
00606         int sourceWidgetX, sourceWidgetY;
00607         sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY);
00608         
00609         distributeMouseEvent(sourceWidget,
00610                              MouseEvent::RELEASED,
00611                              mouseInput.getButton(),
00612                              mouseInput.getX(),
00613                              mouseInput.getY());
00614 
00615         if (mouseInput.getButton() == mLastMousePressButton            
00616             && mFocusHandler->getLastWidgetPressed() == sourceWidget)
00617         {
00618             distributeMouseEvent(sourceWidget,
00619                                  MouseEvent::CLICKED,
00620                                  mouseInput.getButton(),
00621                                  mouseInput.getX(),
00622                                  mouseInput.getY());
00623             
00624             mFocusHandler->setLastWidgetPressed(NULL);
00625         }
00626         else
00627         {
00628             mLastMousePressButton = 0;
00629             mClickCount = 0;
00630         }
00631 
00632         if (mFocusHandler->getDraggedWidget() != NULL)
00633         {
00634             mFocusHandler->setDraggedWidget(NULL);
00635         }
00636     }
00637 
00638     Widget* Gui::getWidgetAt(int x, int y)
00639     {
00640         // If the widget's parent has no child then we have found the widget..
00641         Widget* parent = mTop;
00642         Widget* child = mTop;
00643 
00644         while (child != NULL)
00645         {
00646             Widget* swap = child;
00647             int parentX, parentY;
00648             parent->getAbsolutePosition(parentX, parentY);
00649             child = parent->getWidgetAt(x - parentX, y - parentY);
00650             parent = swap;
00651         }
00652 
00653         return parent;
00654     }
00655 
00656     Widget* Gui::getMouseEventSource(int x, int y)
00657     {
00658         Widget* widget = getWidgetAt(x, y);
00659 
00660         if (mFocusHandler->getModalMouseInputFocused() != NULL
00661             && !widget->isModalMouseInputFocused())
00662         {
00663             return mFocusHandler->getModalMouseInputFocused();
00664         }
00665 
00666         return widget;
00667     }
00668 
00669     Widget* Gui::getKeyEventSource()
00670     {
00671         Widget* widget = mFocusHandler->getFocused();
00672 
00673         while (widget->_getInternalFocusHandler() != NULL
00674                && widget->_getInternalFocusHandler()->getFocused() != NULL)
00675         {
00676             widget = widget->_getInternalFocusHandler()->getFocused();
00677         }
00678 
00679         return widget;
00680     }
00681 
00682     void Gui::distributeMouseEvent(Widget* source,
00683                                    int type,
00684                                    int button,
00685                                    int x,
00686                                    int y,
00687                                    bool force,
00688                                    bool toSourceOnly)
00689     {
00690         Widget* parent = source;
00691         Widget* widget = source;
00692 
00693         if (mFocusHandler->getModalFocused() != NULL
00694             && !widget->isModalFocused()
00695             && !force)
00696         {
00697             return;
00698         }
00699 
00700         if (mFocusHandler->getModalMouseInputFocused() != NULL
00701             && !widget->isModalMouseInputFocused()
00702             && !force)
00703         {
00704             return;
00705         }
00706 
00707         MouseEvent mouseEvent(source,
00708                               mShiftPressed,
00709                               mControlPressed,
00710                               mAltPressed,
00711                               mMetaPressed,
00712                               type,
00713                               button,
00714                               x,
00715                               y,
00716                               mClickCount);
00717 
00718         while (parent != NULL)
00719         {
00720             // If the widget has been removed due to input
00721             // cancel the distribution.
00722             if (!Widget::widgetExists(widget))
00723             {
00724                 break;
00725             }
00726 
00727             parent = (Widget*)widget->getParent();
00728 
00729             if (widget->isEnabled() || force)
00730             {
00731                 int widgetX, widgetY;
00732                 widget->getAbsolutePosition(widgetX, widgetY);
00733 
00734                 mouseEvent.mX = x - widgetX;
00735                 mouseEvent.mY = y - widgetY;
00736                                       
00737                 std::list<MouseListener*> mouseListeners = widget->_getMouseListeners();
00738 
00739                 // Send the event to all mouse listeners of the widget.
00740                 for (std::list<MouseListener*>::iterator it = mouseListeners.begin();
00741                      it != mouseListeners.end();
00742                      ++it)
00743                 {
00744                     switch (mouseEvent.getType())
00745                     {
00746                       case MouseEvent::ENTERED:
00747                           (*it)->mouseEntered(mouseEvent);
00748                           break;
00749                       case MouseEvent::EXITED:
00750                           (*it)->mouseExited(mouseEvent);
00751                           break;
00752                       case MouseEvent::MOVED:
00753                           (*it)->mouseMoved(mouseEvent);
00754                           break;
00755                       case MouseEvent::PRESSED:
00756                           (*it)->mousePressed(mouseEvent);
00757                           break;
00758                       case MouseEvent::RELEASED:
00759                           (*it)->mouseReleased(mouseEvent);
00760                           break;
00761                       case MouseEvent::WHEEL_MOVED_UP:
00762                           (*it)->mouseWheelMovedUp(mouseEvent);
00763                           break;
00764                       case MouseEvent::WHEEL_MOVED_DOWN:
00765                           (*it)->mouseWheelMovedDown(mouseEvent);
00766                           break;
00767                       case MouseEvent::DRAGGED:
00768                           (*it)->mouseDragged(mouseEvent);
00769                           break;
00770                       case MouseEvent::CLICKED:
00771                           (*it)->mouseClicked(mouseEvent);
00772                           break;
00773                       default:
00774                           throw GCN_EXCEPTION("Unknown mouse event type.");
00775                     }                    
00776                 }
00777                 
00778                 if (toSourceOnly)
00779                 {
00780                     break;
00781                 }
00782 
00783             }
00784 
00785             Widget* swap = widget;
00786             widget = parent;
00787             parent = (Widget*)swap->getParent();
00788 
00789             // If a non modal focused widget has been reach
00790             // and we have modal focus cancel the distribution.
00791             if (mFocusHandler->getModalFocused() != NULL
00792                 && !widget->isModalFocused())
00793             {
00794                 break;
00795             }
00796 
00797             // If a non modal mouse input focused widget has been reach
00798             // and we have modal mouse input focus cancel the distribution.
00799             if (mFocusHandler->getModalMouseInputFocused() != NULL
00800                 && !widget->isModalMouseInputFocused())
00801             {
00802                 break;
00803             }
00804         }
00805     }
00806 
00807     void Gui::distributeKeyEvent(KeyEvent& keyEvent)
00808     {
00809         Widget* parent = keyEvent.getSource();
00810         Widget* widget = keyEvent.getSource();
00811 
00812         if (mFocusHandler->getModalFocused() != NULL
00813             && !widget->isModalFocused())
00814         {
00815             return;
00816         }
00817 
00818         if (mFocusHandler->getModalMouseInputFocused() != NULL
00819             && !widget->isModalMouseInputFocused())
00820         {
00821             return;
00822         }
00823 
00824         while (parent != NULL)
00825         {
00826             // If the widget has been removed due to input
00827             // cancel the distribution.
00828             if (!Widget::widgetExists(widget))
00829             {
00830                 break;
00831             }
00832 
00833             parent = (Widget*)widget->getParent();
00834 
00835             if (widget->isEnabled())
00836             {
00837                 std::list<KeyListener*> keyListeners = widget->_getKeyListeners();
00838             
00839                 // Send the event to all key listeners of the source widget.
00840                 for (std::list<KeyListener*>::iterator it = keyListeners.begin();
00841                      it != keyListeners.end();
00842                      ++it)
00843                 {
00844                     switch (keyEvent.getType())
00845                     {
00846                       case KeyEvent::PRESSED:
00847                           (*it)->keyPressed(keyEvent);
00848                           break;
00849                       case KeyEvent::RELEASED:
00850                           (*it)->keyReleased(keyEvent);
00851                           break;
00852                       default:
00853                           throw GCN_EXCEPTION("Unknown key event type.");
00854                     }                
00855                 }
00856             }
00857 
00858             Widget* swap = widget;
00859             widget = parent;
00860             parent = (Widget*)swap->getParent();
00861 
00862             // If a non modal focused widget has been reach
00863             // and we have modal focus cancel the distribution.
00864             if (mFocusHandler->getModalFocused() != NULL
00865                 && !widget->isModalFocused())
00866             {
00867                 break;
00868             }
00869         }
00870     }
00871 
00872     void Gui::distributeKeyEventToGlobalKeyListeners(KeyEvent& keyEvent)
00873     {
00874         KeyListenerListIterator it;
00875 
00876         for (it = mKeyListeners.begin(); it != mKeyListeners.end(); it++)
00877         {
00878             switch (keyEvent.getType())
00879             {
00880               case KeyEvent::PRESSED:
00881                   (*it)->keyPressed(keyEvent);
00882                   break;
00883               case KeyEvent::RELEASED:
00884                   (*it)->keyReleased(keyEvent);
00885                   break;
00886               default:
00887                   throw GCN_EXCEPTION("Unknown key event type.");
00888             }
00889 
00890             if (keyEvent.isConsumed())
00891             {
00892                 break;
00893             }
00894         }
00895     }
00896 
00897     void Gui::handleModalMouseInputFocus()
00898     {
00899         // Check if modal mouse input focus has been gained by a widget.
00900         if ((mFocusHandler->getLastWidgetWithModalMouseInputFocus() 
00901                 != mFocusHandler->getModalMouseInputFocused())
00902              && (mFocusHandler->getLastWidgetWithModalMouseInputFocus() == NULL))
00903         {
00904             handleModalFocusGained();
00905             mFocusHandler->setLastWidgetWithModalMouseInputFocus(mFocusHandler->getModalMouseInputFocused());
00906         }
00907         // Check if modal mouse input focus has been released.
00908         else if ((mFocusHandler->getLastWidgetWithModalMouseInputFocus()
00909                     != mFocusHandler->getModalMouseInputFocused())
00910                     && (mFocusHandler->getLastWidgetWithModalMouseInputFocus() != NULL))
00911         {
00912             handleModalFocusReleased();
00913             mFocusHandler->setLastWidgetWithModalMouseInputFocus(NULL);
00914         }
00915     }
00916 
00917      void Gui::handleModalFocus()
00918     {
00919         // Check if modal focus has been gained by a widget.
00920         if ((mFocusHandler->getLastWidgetWithModalFocus() 
00921                 != mFocusHandler->getModalFocused())
00922              && (mFocusHandler->getLastWidgetWithModalFocus() == NULL))
00923         {
00924             handleModalFocusGained();
00925             mFocusHandler->setLastWidgetWithModalFocus(mFocusHandler->getModalFocused());
00926         }
00927         // Check if modal focus has been released.
00928         else if ((mFocusHandler->getLastWidgetWithModalFocus()
00929                     != mFocusHandler->getModalFocused())
00930                     && (mFocusHandler->getLastWidgetWithModalFocus() != NULL))
00931         {
00932             handleModalFocusReleased();
00933             mFocusHandler->setLastWidgetWithModalFocus(NULL);
00934         }
00935     }
00936 
00937     void Gui::handleModalFocusGained()
00938     {
00939          // Distribute an event to all widgets in the "widget with mouse" queue.
00940         while (!mWidgetWithMouseQueue.empty())
00941         {
00942             Widget* widget = mWidgetWithMouseQueue.front();
00943 
00944             if (Widget::widgetExists(widget))
00945             {
00946                 distributeMouseEvent(widget,
00947                                      MouseEvent::EXITED,
00948                                      mLastMousePressButton,
00949                                      mLastMouseX,
00950                                      mLastMouseY,
00951                                      true,
00952                                      true);
00953             }
00954 
00955             mWidgetWithMouseQueue.pop_front();
00956         }
00957 
00958         mFocusHandler->setLastWidgetWithModalMouseInputFocus(mFocusHandler->getModalMouseInputFocused());
00959     }
00960 
00961     void Gui::handleModalFocusReleased()
00962     {
00963          // Check all widgets below the mouse to see if they are
00964         // present in the "widget with mouse" queue. If a widget
00965         // is not then it should be added and an entered event should
00966         // be sent to it.
00967         Widget* widget = getMouseEventSource(mLastMouseX, mLastMouseY);
00968         Widget* parent = widget;
00969 
00970         while (parent != NULL)
00971         {
00972             parent = (Widget*)widget->getParent();
00973 
00974             // Check if the widget is present in the "widget with mouse" queue.
00975             bool widgetIsPresentInQueue = false;
00976             std::deque<Widget*>::iterator iter;
00977             for (iter = mWidgetWithMouseQueue.begin();
00978                  iter != mWidgetWithMouseQueue.end();
00979                  iter++)
00980             {
00981                 if (*iter == widget)
00982                 {
00983                     widgetIsPresentInQueue = true;
00984                     break;
00985                 }
00986             }
00987 
00988             // Widget is not present, send an entered event and add
00989             // it to the "widget with mouse" queue.
00990             if (!widgetIsPresentInQueue
00991                 && Widget::widgetExists(widget))
00992             {
00993                 distributeMouseEvent(widget,
00994                                      MouseEvent::ENTERED,
00995                                      mLastMousePressButton,
00996                                      mLastMouseX,
00997                                      mLastMouseY,
00998                                      false,
00999                                      true);
01000                 mWidgetWithMouseQueue.push_front(widget);
01001             }
01002 
01003             Widget* swap = widget;
01004             widget = parent;
01005             parent = (Widget*)swap->getParent();
01006         }
01007     }
01008 }

Generated on Sun Jan 20 21:48:14 2008 for Guichan by  doxygen 1.5.2