comparison ext/guichan-0.8.1/src/gui.cpp @ 0:4a0efb7baf70

* Datasets becomes the new trunk and retires after that :-)
author mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222
date Sun, 29 Jun 2008 18:44:17 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4a0efb7baf70
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 {
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
82 Gui::~Gui()
83 {
84 if (Widget::widgetExists(mTop))
85 {
86 setTop(NULL);
87 }
88
89 delete mFocusHandler;
90 }
91
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
106 Widget* Gui::getTop() const
107 {
108 return mTop;
109 }
110
111 void Gui::setGraphics(Graphics* graphics)
112 {
113 mGraphics = graphics;
114 }
115
116 Graphics* Gui::getGraphics() const
117 {
118 return mGraphics;
119 }
120
121 void Gui::setInput(Input* input)
122 {
123 mInput = input;
124 }
125
126 Input* Gui::getInput() const
127 {
128 return mInput;
129 }
130
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
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
192 void Gui::focusNone()
193 {
194 mFocusHandler->focusNone();
195 }
196
197 void Gui::setTabbingEnabled(bool tabbing)
198 {
199 mTabbing = tabbing;
200 }
201
202 bool Gui::isTabbingEnabled()
203 {
204 return mTabbing;
205 }
206
207 void Gui::addGlobalKeyListener(KeyListener* keyListener)
208 {
209 mKeyListeners.push_back(keyListener);
210 }
211
212 void Gui::removeGlobalKeyListener(KeyListener* keyListener)
213 {
214 mKeyListeners.remove(keyListener);
215 }
216
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
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
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
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 distributeMouseEvent(sourceWidget,
517 MouseEvent::PRESSED,
518 mouseInput.getButton(),
519 mouseInput.getX(),
520 mouseInput.getY());
521
522 mFocusHandler->setLastWidgetPressed(sourceWidget);
523
524 mFocusHandler->setDraggedWidget(sourceWidget);
525 mLastMouseDragButton = mouseInput.getButton();
526
527 if (mLastMousePressTimeStamp < 300
528 && mLastMousePressButton == mouseInput.getButton())
529 {
530 mClickCount++;
531 }
532 else
533 {
534 mClickCount = 1;
535 }
536
537 mLastMousePressButton = mouseInput.getButton();
538 mLastMousePressTimeStamp = mouseInput.getTimeStamp();
539 }
540
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
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
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
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
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
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
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
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
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
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
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
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
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 }