Mercurial > fife-parpg
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 } |