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