comparison ext/guichan-0.8.2/src/gui.cpp @ 378:64738befdf3b

bringing in the changes from the build_system_rework branch in preparation for the 0.3.0 release. This commit will require the Jan2010 devkit. Clients will also need to be modified to the new way to import fife.
author vtchill@33b003aa-7bff-0310-803a-e67f0ece8222
date Mon, 11 Jan 2010 23:34:52 +0000
parents
children
comparison
equal deleted inserted replaced
377:fe6fb0e0ed23 378:64738befdf3b
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 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
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 }