gui.cpp

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

Generated on Sat Apr 26 13:40:08 2008 for Guichan by  doxygen 1.5.2