1 /*      _______   __   __   __   ______   __   __   _______   __   __
2  *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
3  *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
4  *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
5  *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
6  * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
7  * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
8  *
9  * Copyright (c) 2004 - 2008 Olof Naess�n and Per Larsson
10  *
11  *
12  * Per Larsson a.k.a finalman
13  * Olof Naess�n a.k.a jansem/yakslem
14  *
15  * Visit: http://guichan.sourceforge.net
16  *
17  * License: (BSD)
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in
25  *    the documentation and/or other materials provided with the
26  *    distribution.
27  * 3. Neither the name of Guichan nor the names of its contributors may
28  *    be used to endorse or promote products derived from this software
29  *    without specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
37  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
38  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
39  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42  */
43 
44 /*
45  * For comments regarding functions please see the header file.
46  */
47 
48 #include "guichan/gui.hpp"
49 
50 #include "guichan/basiccontainer.hpp"
51 #include "guichan/exception.hpp"
52 #include "guichan/focushandler.hpp"
53 #include "guichan/graphics.hpp"
54 #include "guichan/input.hpp"
55 #include "guichan/keyinput.hpp"
56 #include "guichan/keylistener.hpp"
57 #include "guichan/mouseinput.hpp"
58 #include "guichan/mouselistener.hpp"
59 #include "guichan/widget.hpp"
60 
61 namespace gcn
62 {
Gui()63     Gui::Gui()
64             :mTop(NULL),
65              mGraphics(NULL),
66              mInput(NULL),
67              mTabbing(true),
68              mShiftPressed(false),
69              mMetaPressed(false),
70              mControlPressed(false),
71              mAltPressed(false),
72              mLastMousePressButton(0),
73              mLastMousePressTimeStamp(0),
74              mLastMouseX(0),
75              mLastMouseY(0),
76              mClickCount(1),
77              mLastMouseDragButton(0)
78     {
79         mFocusHandler = new FocusHandler();
80     }
81 
~Gui()82     Gui::~Gui()
83     {
84         if (Widget::widgetExists(mTop))
85         {
86             setTop(NULL);
87         }
88 
89         delete mFocusHandler;
90     }
91 
setTop(Widget * top)92     void Gui::setTop(Widget* top)
93     {
94         if (mTop != NULL)
95         {
96             mTop->_setFocusHandler(NULL);
97         }
98         if (top != NULL)
99         {
100             top->_setFocusHandler(mFocusHandler);
101         }
102 
103         mTop = top;
104     }
105 
getTop() const106     Widget* Gui::getTop() const
107     {
108         return mTop;
109     }
110 
setGraphics(Graphics * graphics)111     void Gui::setGraphics(Graphics* graphics)
112     {
113         mGraphics = graphics;
114     }
115 
getGraphics() const116     Graphics* Gui::getGraphics() const
117     {
118         return mGraphics;
119     }
120 
setInput(Input * input)121     void Gui::setInput(Input* input)
122     {
123         mInput = input;
124     }
125 
getInput() const126     Input* Gui::getInput() const
127     {
128         return mInput;
129     }
130 
logic()131     void Gui::logic()
132     {
133         if (mTop == NULL)
134         {
135             throw GCN_EXCEPTION("No top widget set");
136         }
137 
138         handleModalFocus();
139         handleModalMouseInputFocus();
140 
141         if (mInput != NULL)
142         {
143             mInput->_pollInput();
144 
145             handleKeyInput();
146             handleMouseInput();
147 
148         } // end if
149 
150         mTop->logic();
151     }
152 
draw()153     void Gui::draw()
154     {
155         if (mTop == NULL)
156         {
157             throw GCN_EXCEPTION("No top widget set");
158         }
159         if (mGraphics == NULL)
160         {
161             throw GCN_EXCEPTION("No graphics set");
162         }
163 
164         if (!mTop->isVisible())
165         {
166             return;
167         }
168 
169         mGraphics->_beginDraw();
170 
171         // If top has a frame,
172         // draw it before drawing top
173         if (mTop->getFrameSize() > 0)
174         {
175             Rectangle rec = mTop->getDimension();
176             rec.x -= mTop->getFrameSize();
177             rec.y -= mTop->getFrameSize();
178             rec.width += 2 * mTop->getFrameSize();
179             rec.height += 2 * mTop->getFrameSize();
180             mGraphics->pushClipArea(rec);
181             mTop->drawFrame(mGraphics);
182             mGraphics->popClipArea();
183         }
184 
185         mGraphics->pushClipArea(mTop->getDimension());
186         mTop->draw(mGraphics);
187         mGraphics->popClipArea();
188 
189         mGraphics->_endDraw();
190     }
191 
focusNone()192     void Gui::focusNone()
193     {
194         mFocusHandler->focusNone();
195     }
196 
setTabbingEnabled(bool tabbing)197     void Gui::setTabbingEnabled(bool tabbing)
198     {
199         mTabbing = tabbing;
200     }
201 
isTabbingEnabled()202     bool Gui::isTabbingEnabled()
203     {
204         return mTabbing;
205     }
206 
addGlobalKeyListener(KeyListener * keyListener)207     void Gui::addGlobalKeyListener(KeyListener* keyListener)
208     {
209         mKeyListeners.push_back(keyListener);
210     }
211 
removeGlobalKeyListener(KeyListener * keyListener)212     void Gui::removeGlobalKeyListener(KeyListener* keyListener)
213     {
214         mKeyListeners.remove(keyListener);
215     }
216 
handleMouseInput()217     void Gui::handleMouseInput()
218     {
219         while (!mInput->isMouseQueueEmpty())
220          {
221              MouseInput mouseInput = mInput->dequeueMouseInput();
222 
223              // Save the current mouse state. It will be needed if modal focus
224              // changes or modal mouse input focus changes.
225              mLastMouseX = mouseInput.getX();
226              mLastMouseY = mouseInput.getY();
227 
228              switch (mouseInput.getType())
229              {
230                case MouseInput::PRESSED:
231                    handleMousePressed(mouseInput);
232                    break;
233                case MouseInput::RELEASED:
234                    handleMouseReleased(mouseInput);
235                    break;
236                case MouseInput::MOVED:
237                    handleMouseMoved(mouseInput);
238                    break;
239                case MouseInput::WHEEL_MOVED_DOWN:
240                    handleMouseWheelMovedDown(mouseInput);
241                    break;
242                case MouseInput::WHEEL_MOVED_UP:
243                    handleMouseWheelMovedUp(mouseInput);
244                    break;
245                default:
246                    throw GCN_EXCEPTION("Unknown mouse input type.");
247                    break;
248              }
249          }
250     }
251 
handleKeyInput()252     void Gui::handleKeyInput()
253     {
254         while (!mInput->isKeyQueueEmpty())
255         {
256             KeyInput keyInput = mInput->dequeueKeyInput();
257 
258             // Save modifiers state
259             mShiftPressed = keyInput.isShiftPressed();
260             mMetaPressed = keyInput.isMetaPressed();
261             mControlPressed = keyInput.isControlPressed();
262             mAltPressed = keyInput.isAltPressed();
263 
264             KeyEvent keyEventToGlobalKeyListeners(NULL,
265                                                   mShiftPressed,
266                                                   mControlPressed,
267                                                   mAltPressed,
268                                                   mMetaPressed,
269                                                   keyInput.getType(),
270                                                   keyInput.isNumericPad(),
271                                                   keyInput.getKey());
272 
273             distributeKeyEventToGlobalKeyListeners(keyEventToGlobalKeyListeners);
274 
275             // If a global key listener consumes the event it will not be
276             // sent further to the source of the event.
277             if (keyEventToGlobalKeyListeners.isConsumed())
278             {
279                 continue;
280             }
281 
282             bool keyEventConsumed = false;
283 
284             // Send key inputs to the focused widgets
285             if (mFocusHandler->getFocused() != NULL)
286             {
287                 KeyEvent keyEvent(getKeyEventSource(),
288                                   mShiftPressed,
289                                   mControlPressed,
290                                   mAltPressed,
291                                   mMetaPressed,
292                                   keyInput.getType(),
293                                   keyInput.isNumericPad(),
294                                   keyInput.getKey());
295 
296 
297                 if (!mFocusHandler->getFocused()->isFocusable())
298                 {
299                     mFocusHandler->focusNone();
300                 }
301                 else
302                 {
303                     distributeKeyEvent(keyEvent);
304                 }
305 
306                 keyEventConsumed = keyEvent.isConsumed();
307             }
308 
309             // If the key event hasn't been consumed and
310             // tabbing is enable check for tab press and
311             // change focus.
312             if (!keyEventConsumed
313                 && mTabbing
314                 && keyInput.getKey().getValue() == Key::TAB
315                 && keyInput.getType() == KeyInput::PRESSED)
316             {
317                 if (keyInput.isShiftPressed())
318                 {
319                     mFocusHandler->tabPrevious();
320                 }
321                 else
322                 {
323                     mFocusHandler->tabNext();
324                 }
325             }
326 
327         } // end while
328     }
329 
handleMouseMoved(const MouseInput & mouseInput)330     void Gui::handleMouseMoved(const MouseInput& mouseInput)
331     {
332         // Check if the mouse leaves the application window.
333         if (!mWidgetWithMouseQueue.empty()
334             && (mouseInput.getX() < 0
335                 || mouseInput.getY() < 0
336                 || !mTop->getDimension().isPointInRect(mouseInput.getX(), mouseInput.getY()))
337             )
338         {
339             // Distribute an event to all widgets in the "widget with mouse" queue.
340             while (!mWidgetWithMouseQueue.empty())
341             {
342                 Widget* widget = mWidgetWithMouseQueue.front();
343 
344                 if (Widget::widgetExists(widget))
345                 {
346                     distributeMouseEvent(widget,
347                                          MouseEvent::EXITED,
348                                          mouseInput.getButton(),
349                                          mouseInput.getX(),
350                                          mouseInput.getY(),
351                                          true,
352                                          true);
353                 }
354 
355                 mWidgetWithMouseQueue.pop_front();
356             }
357 
358             return;
359         }
360 
361         // Check if there is a need to send mouse exited events by
362         // traversing the "widget with mouse" queue.
363         bool widgetWithMouseQueueCheckDone = mWidgetWithMouseQueue.empty();
364         while (!widgetWithMouseQueueCheckDone)
365         {
366             unsigned int iterations = 0;
367             std::deque<Widget*>::iterator iter;
368             for (iter = mWidgetWithMouseQueue.begin();
369                  iter != mWidgetWithMouseQueue.end();
370                  iter++)
371             {
372                 Widget* widget = *iter;
373 
374                 // If a widget in the "widget with mouse queue" doesn't
375                 // exists anymore it should be removed from the queue.
376                 if (!Widget::widgetExists(widget))
377                 {
378                     mWidgetWithMouseQueue.erase(iter);
379                     break;
380                 }
381                 else
382                 {
383                     int x, y;
384                     widget->getAbsolutePosition(x, y);
385 
386                     if (x > mouseInput.getX()
387                         || y > mouseInput.getY()
388                         || x + widget->getWidth() <= mouseInput.getX()
389                         || y + widget->getHeight() <= mouseInput.getY()
390                         || !widget->isVisible())
391                     {
392                         distributeMouseEvent(widget,
393                                              MouseEvent::EXITED,
394                                              mouseInput.getButton(),
395                                              mouseInput.getX(),
396                                              mouseInput.getY(),
397                                              true,
398                                              true);
399                         mClickCount = 1;
400                         mLastMousePressTimeStamp = 0;
401                         mWidgetWithMouseQueue.erase(iter);
402                         break;
403                     }
404                 }
405 
406                 iterations++;
407             }
408 
409             widgetWithMouseQueueCheckDone = iterations == mWidgetWithMouseQueue.size();
410         }
411 
412         // Check all widgets below the mouse to see if they are
413         // present in the "widget with mouse" queue. If a widget
414         // is not then it should be added and an entered event should
415         // be sent to it.
416         Widget* parent = getMouseEventSource(mouseInput.getX(), mouseInput.getY());
417         Widget* widget = parent;
418 
419         // If a widget has modal mouse input focus then it will
420         // always be returned from getMouseEventSource, but we only wan't to send
421         // mouse entered events if the mouse has actually entered the widget with
422         // modal mouse input focus, hence we need to check if that's the case. If
423         // it's not we should simply ignore to send any mouse entered events.
424         if (mFocusHandler->getModalMouseInputFocused() != NULL
425             && widget == mFocusHandler->getModalMouseInputFocused()
426             && Widget::widgetExists(widget))
427         {
428             int x, y;
429             widget->getAbsolutePosition(x, y);
430 
431             if (x > mouseInput.getX()
432                 || y > mouseInput.getY()
433                 || x + widget->getWidth() <= mouseInput.getX()
434                 || y + widget->getHeight() <= mouseInput.getY())
435             {
436                 parent = NULL;
437             }
438         }
439 
440         while (parent != NULL)
441         {
442             parent = (Widget*)widget->getParent();
443 
444             // Check if the widget is present in the "widget with mouse" queue.
445             bool widgetIsPresentInQueue = false;
446             std::deque<Widget*>::iterator iter;
447             for (iter = mWidgetWithMouseQueue.begin();
448                  iter != mWidgetWithMouseQueue.end();
449                  iter++)
450             {
451                 if (*iter == widget)
452                 {
453                     widgetIsPresentInQueue = true;
454                     break;
455                 }
456             }
457 
458             // Widget is not present, send an entered event and add
459             // it to the "widget with mouse" queue.
460             if (!widgetIsPresentInQueue
461                 && Widget::widgetExists(widget))
462             {
463                 distributeMouseEvent(widget,
464                                      MouseEvent::ENTERED,
465                                      mouseInput.getButton(),
466                                      mouseInput.getX(),
467                                      mouseInput.getY(),
468                                      true,
469                                      true);
470                 mWidgetWithMouseQueue.push_front(widget);
471             }
472 
473             Widget* swap = widget;
474             widget = parent;
475             parent = (Widget*)swap->getParent();
476         }
477 
478         if (mFocusHandler->getDraggedWidget() != NULL)
479         {
480             distributeMouseEvent(mFocusHandler->getDraggedWidget(),
481                                  MouseEvent::DRAGGED,
482                                  mLastMouseDragButton,
483                                  mouseInput.getX(),
484                                  mouseInput.getY());
485         }
486         else
487         {
488             Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY());
489             distributeMouseEvent(sourceWidget,
490                                  MouseEvent::MOVED,
491                                  mouseInput.getButton(),
492                                  mouseInput.getX(),
493                                  mouseInput.getY());
494         }
495     }
496 
handleMousePressed(const MouseInput & mouseInput)497     void Gui::handleMousePressed(const MouseInput& mouseInput)
498     {
499         Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY());
500 
501         if (mFocusHandler->getDraggedWidget() != NULL)
502         {
503             sourceWidget = mFocusHandler->getDraggedWidget();
504         }
505 
506         int sourceWidgetX, sourceWidgetY;
507         sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY);
508 
509         if ((mFocusHandler->getModalFocused() != NULL
510             && sourceWidget->isModalFocused())
511             || mFocusHandler->getModalFocused() == NULL)
512         {
513             sourceWidget->requestFocus();
514         }
515 
516         if (mouseInput.getTimeStamp() - mLastMousePressTimeStamp < 250
517             && mLastMousePressButton == mouseInput.getButton())
518         {
519             mClickCount++;
520         }
521         else
522         {
523             mClickCount = 1;
524         }
525 
526         distributeMouseEvent(sourceWidget,
527                              MouseEvent::PRESSED,
528                              mouseInput.getButton(),
529                              mouseInput.getX(),
530                              mouseInput.getY());
531 
532         mFocusHandler->setLastWidgetPressed(sourceWidget);
533 
534         mFocusHandler->setDraggedWidget(sourceWidget);
535         mLastMouseDragButton = mouseInput.getButton();
536 
537         mLastMousePressButton = mouseInput.getButton();
538         mLastMousePressTimeStamp = mouseInput.getTimeStamp();
539     }
540 
handleMouseWheelMovedDown(const MouseInput & mouseInput)541     void Gui::handleMouseWheelMovedDown(const MouseInput& mouseInput)
542     {
543         Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY());
544 
545         if (mFocusHandler->getDraggedWidget() != NULL)
546         {
547             sourceWidget = mFocusHandler->getDraggedWidget();
548         }
549 
550         int sourceWidgetX, sourceWidgetY;
551         sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY);
552 
553         distributeMouseEvent(sourceWidget,
554                              MouseEvent::WHEEL_MOVED_DOWN,
555                              mouseInput.getButton(),
556                              mouseInput.getX(),
557                              mouseInput.getY());
558     }
559 
handleMouseWheelMovedUp(const MouseInput & mouseInput)560     void Gui::handleMouseWheelMovedUp(const MouseInput& mouseInput)
561     {
562         Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY());
563 
564         if (mFocusHandler->getDraggedWidget() != NULL)
565         {
566             sourceWidget = mFocusHandler->getDraggedWidget();
567         }
568 
569         int sourceWidgetX, sourceWidgetY;
570         sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY);
571 
572         distributeMouseEvent(sourceWidget,
573                              MouseEvent::WHEEL_MOVED_UP,
574                              mouseInput.getButton(),
575                              mouseInput.getX(),
576                              mouseInput.getY());
577     }
578 
handleMouseReleased(const MouseInput & mouseInput)579     void Gui::handleMouseReleased(const MouseInput& mouseInput)
580     {
581         Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY());
582 
583         if (mFocusHandler->getDraggedWidget() != NULL)
584         {
585             if (sourceWidget != mFocusHandler->getLastWidgetPressed())
586             {
587                 mFocusHandler->setLastWidgetPressed(NULL);
588             }
589 
590             sourceWidget = mFocusHandler->getDraggedWidget();
591         }
592 
593         int sourceWidgetX, sourceWidgetY;
594         sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY);
595 
596         distributeMouseEvent(sourceWidget,
597                              MouseEvent::RELEASED,
598                              mouseInput.getButton(),
599                              mouseInput.getX(),
600                              mouseInput.getY());
601 
602         if (mouseInput.getButton() == mLastMousePressButton
603             && mFocusHandler->getLastWidgetPressed() == sourceWidget)
604         {
605             distributeMouseEvent(sourceWidget,
606                                  MouseEvent::CLICKED,
607                                  mouseInput.getButton(),
608                                  mouseInput.getX(),
609                                  mouseInput.getY());
610 
611             mFocusHandler->setLastWidgetPressed(NULL);
612         }
613         else
614         {
615             mLastMousePressButton = 0;
616             mClickCount = 0;
617         }
618 
619         if (mFocusHandler->getDraggedWidget() != NULL)
620         {
621             mFocusHandler->setDraggedWidget(NULL);
622         }
623     }
624 
getWidgetAt(int x,int y)625     Widget* Gui::getWidgetAt(int x, int y)
626     {
627         // If the widget's parent has no child then we have found the widget..
628         Widget* parent = mTop;
629         Widget* child = mTop;
630 
631         while (child != NULL)
632         {
633             Widget* swap = child;
634             int parentX, parentY;
635             parent->getAbsolutePosition(parentX, parentY);
636             child = parent->getWidgetAt(x - parentX, y - parentY);
637             parent = swap;
638         }
639 
640         return parent;
641     }
642 
getMouseEventSource(int x,int y)643     Widget* Gui::getMouseEventSource(int x, int y)
644     {
645         Widget* widget = getWidgetAt(x, y);
646 
647         if (mFocusHandler->getModalMouseInputFocused() != NULL
648             && !widget->isModalMouseInputFocused())
649         {
650             return mFocusHandler->getModalMouseInputFocused();
651         }
652 
653         return widget;
654     }
655 
getKeyEventSource()656     Widget* Gui::getKeyEventSource()
657     {
658         Widget* widget = mFocusHandler->getFocused();
659 
660         while (widget->_getInternalFocusHandler() != NULL
661                && widget->_getInternalFocusHandler()->getFocused() != NULL)
662         {
663             widget = widget->_getInternalFocusHandler()->getFocused();
664         }
665 
666         return widget;
667     }
668 
distributeMouseEvent(Widget * source,int type,int button,int x,int y,bool force,bool toSourceOnly)669     void Gui::distributeMouseEvent(Widget* source,
670                                    int type,
671                                    int button,
672                                    int x,
673                                    int y,
674                                    bool force,
675                                    bool toSourceOnly)
676     {
677         Widget* parent = source;
678         Widget* widget = source;
679 
680         if (mFocusHandler->getModalFocused() != NULL
681             && !widget->isModalFocused()
682             && !force)
683         {
684             return;
685         }
686 
687         if (mFocusHandler->getModalMouseInputFocused() != NULL
688             && !widget->isModalMouseInputFocused()
689             && !force)
690         {
691             return;
692         }
693 
694         MouseEvent mouseEvent(source,
695                               mShiftPressed,
696                               mControlPressed,
697                               mAltPressed,
698                               mMetaPressed,
699                               type,
700                               button,
701                               x,
702                               y,
703                               mClickCount);
704 
705         while (parent != NULL)
706         {
707             // If the widget has been removed due to input
708             // cancel the distribution.
709             if (!Widget::widgetExists(widget))
710             {
711                 break;
712             }
713 
714             parent = (Widget*)widget->getParent();
715 
716             if (widget->isEnabled() || force)
717             {
718                 int widgetX, widgetY;
719                 widget->getAbsolutePosition(widgetX, widgetY);
720 
721                 mouseEvent.mX = x - widgetX;
722                 mouseEvent.mY = y - widgetY;
723 
724                 std::list<MouseListener*> mouseListeners = widget->_getMouseListeners();
725 
726                 // Send the event to all mouse listeners of the widget.
727                 for (std::list<MouseListener*>::iterator it = mouseListeners.begin();
728                      it != mouseListeners.end();
729                      ++it)
730                 {
731                     switch (mouseEvent.getType())
732                     {
733                       case MouseEvent::ENTERED:
734                           (*it)->mouseEntered(mouseEvent);
735                           break;
736                       case MouseEvent::EXITED:
737                           (*it)->mouseExited(mouseEvent);
738                           break;
739                       case MouseEvent::MOVED:
740                           (*it)->mouseMoved(mouseEvent);
741                           break;
742                       case MouseEvent::PRESSED:
743                           (*it)->mousePressed(mouseEvent);
744                           break;
745                       case MouseEvent::RELEASED:
746                           (*it)->mouseReleased(mouseEvent);
747                           break;
748                       case MouseEvent::WHEEL_MOVED_UP:
749                           (*it)->mouseWheelMovedUp(mouseEvent);
750                           break;
751                       case MouseEvent::WHEEL_MOVED_DOWN:
752                           (*it)->mouseWheelMovedDown(mouseEvent);
753                           break;
754                       case MouseEvent::DRAGGED:
755                           (*it)->mouseDragged(mouseEvent);
756                           break;
757                       case MouseEvent::CLICKED:
758                           (*it)->mouseClicked(mouseEvent);
759                           break;
760                       default:
761                           throw GCN_EXCEPTION("Unknown mouse event type.");
762                     }
763                 }
764 
765                 if (toSourceOnly)
766                 {
767                     break;
768                 }
769 
770             }
771 
772             Widget* swap = widget;
773             widget = parent;
774             parent = (Widget*)swap->getParent();
775 
776             // If a non modal focused widget has been reach
777             // and we have modal focus cancel the distribution.
778             if (mFocusHandler->getModalFocused() != NULL
779                 && !widget->isModalFocused())
780             {
781                 break;
782             }
783 
784             // If a non modal mouse input focused widget has been reach
785             // and we have modal mouse input focus cancel the distribution.
786             if (mFocusHandler->getModalMouseInputFocused() != NULL
787                 && !widget->isModalMouseInputFocused())
788             {
789                 break;
790             }
791         }
792     }
793 
distributeKeyEvent(KeyEvent & keyEvent)794     void Gui::distributeKeyEvent(KeyEvent& keyEvent)
795     {
796         Widget* parent = keyEvent.getSource();
797         Widget* widget = keyEvent.getSource();
798 
799         if (mFocusHandler->getModalFocused() != NULL
800             && !widget->isModalFocused())
801         {
802             return;
803         }
804 
805         if (mFocusHandler->getModalMouseInputFocused() != NULL
806             && !widget->isModalMouseInputFocused())
807         {
808             return;
809         }
810 
811         while (parent != NULL)
812         {
813             // If the widget has been removed due to input
814             // cancel the distribution.
815             if (!Widget::widgetExists(widget))
816             {
817                 break;
818             }
819 
820             parent = (Widget*)widget->getParent();
821 
822             if (widget->isEnabled())
823             {
824                 std::list<KeyListener*> keyListeners = widget->_getKeyListeners();
825 
826                 // Send the event to all key listeners of the source widget.
827                 for (std::list<KeyListener*>::iterator it = keyListeners.begin();
828                      it != keyListeners.end();
829                      ++it)
830                 {
831                     switch (keyEvent.getType())
832                     {
833                       case KeyEvent::PRESSED:
834                           (*it)->keyPressed(keyEvent);
835                           break;
836                       case KeyEvent::RELEASED:
837                           (*it)->keyReleased(keyEvent);
838                           break;
839                       default:
840                           throw GCN_EXCEPTION("Unknown key event type.");
841                     }
842                 }
843             }
844 
845             Widget* swap = widget;
846             widget = parent;
847             parent = (Widget*)swap->getParent();
848 
849             // If a non modal focused widget has been reach
850             // and we have modal focus cancel the distribution.
851             if (mFocusHandler->getModalFocused() != NULL
852                 && !widget->isModalFocused())
853             {
854                 break;
855             }
856         }
857     }
858 
distributeKeyEventToGlobalKeyListeners(KeyEvent & keyEvent)859     void Gui::distributeKeyEventToGlobalKeyListeners(KeyEvent& keyEvent)
860     {
861         KeyListenerListIterator it;
862 
863         for (it = mKeyListeners.begin(); it != mKeyListeners.end(); it++)
864         {
865             switch (keyEvent.getType())
866             {
867               case KeyEvent::PRESSED:
868                   (*it)->keyPressed(keyEvent);
869                   break;
870               case KeyEvent::RELEASED:
871                   (*it)->keyReleased(keyEvent);
872                   break;
873               default:
874                   throw GCN_EXCEPTION("Unknown key event type.");
875             }
876 
877             if (keyEvent.isConsumed())
878             {
879                 break;
880             }
881         }
882     }
883 
handleModalMouseInputFocus()884     void Gui::handleModalMouseInputFocus()
885     {
886         // Check if modal mouse input focus has been gained by a widget.
887         if ((mFocusHandler->getLastWidgetWithModalMouseInputFocus()
888                 != mFocusHandler->getModalMouseInputFocused())
889              && (mFocusHandler->getLastWidgetWithModalMouseInputFocus() == NULL))
890         {
891             handleModalFocusGained();
892             mFocusHandler->setLastWidgetWithModalMouseInputFocus(mFocusHandler->getModalMouseInputFocused());
893         }
894         // Check if modal mouse input focus has been released.
895         else if ((mFocusHandler->getLastWidgetWithModalMouseInputFocus()
896                     != mFocusHandler->getModalMouseInputFocused())
897                     && (mFocusHandler->getLastWidgetWithModalMouseInputFocus() != NULL))
898         {
899             handleModalFocusReleased();
900             mFocusHandler->setLastWidgetWithModalMouseInputFocus(NULL);
901         }
902     }
903 
handleModalFocus()904      void Gui::handleModalFocus()
905     {
906         // Check if modal focus has been gained by a widget.
907         if ((mFocusHandler->getLastWidgetWithModalFocus()
908                 != mFocusHandler->getModalFocused())
909              && (mFocusHandler->getLastWidgetWithModalFocus() == NULL))
910         {
911             handleModalFocusGained();
912             mFocusHandler->setLastWidgetWithModalFocus(mFocusHandler->getModalFocused());
913         }
914         // Check if modal focus has been released.
915         else if ((mFocusHandler->getLastWidgetWithModalFocus()
916                     != mFocusHandler->getModalFocused())
917                     && (mFocusHandler->getLastWidgetWithModalFocus() != NULL))
918         {
919             handleModalFocusReleased();
920             mFocusHandler->setLastWidgetWithModalFocus(NULL);
921         }
922     }
923 
handleModalFocusGained()924     void Gui::handleModalFocusGained()
925     {
926          // Distribute an event to all widgets in the "widget with mouse" queue.
927         while (!mWidgetWithMouseQueue.empty())
928         {
929             Widget* widget = mWidgetWithMouseQueue.front();
930 
931             if (Widget::widgetExists(widget))
932             {
933                 distributeMouseEvent(widget,
934                                      MouseEvent::EXITED,
935                                      mLastMousePressButton,
936                                      mLastMouseX,
937                                      mLastMouseY,
938                                      true,
939                                      true);
940             }
941 
942             mWidgetWithMouseQueue.pop_front();
943         }
944 
945         mFocusHandler->setLastWidgetWithModalMouseInputFocus(mFocusHandler->getModalMouseInputFocused());
946     }
947 
handleModalFocusReleased()948     void Gui::handleModalFocusReleased()
949     {
950          // Check all widgets below the mouse to see if they are
951         // present in the "widget with mouse" queue. If a widget
952         // is not then it should be added and an entered event should
953         // be sent to it.
954         Widget* widget = getMouseEventSource(mLastMouseX, mLastMouseY);
955         Widget* parent = widget;
956 
957         while (parent != NULL)
958         {
959             parent = (Widget*)widget->getParent();
960 
961             // Check if the widget is present in the "widget with mouse" queue.
962             bool widgetIsPresentInQueue = false;
963             std::deque<Widget*>::iterator iter;
964             for (iter = mWidgetWithMouseQueue.begin();
965                  iter != mWidgetWithMouseQueue.end();
966                  iter++)
967             {
968                 if (*iter == widget)
969                 {
970                     widgetIsPresentInQueue = true;
971                     break;
972                 }
973             }
974 
975             // Widget is not present, send an entered event and add
976             // it to the "widget with mouse" queue.
977             if (!widgetIsPresentInQueue
978                 && Widget::widgetExists(widget))
979             {
980                 distributeMouseEvent(widget,
981                                      MouseEvent::ENTERED,
982                                      mLastMousePressButton,
983                                      mLastMouseX,
984                                      mLastMouseY,
985                                      false,
986                                      true);
987                 mWidgetWithMouseQueue.push_front(widget);
988             }
989 
990             Widget* swap = widget;
991             widget = parent;
992             parent = (Widget*)swap->getParent();
993         }
994     }
995 }
996