1 /*************************************************************************** 2 * Copyright (c) 2017-2019 by the fifechan team * 3 * https://github.com/fifengine/fifechan * 4 * This file is part of fifechan. * 5 * * 6 * fifechan is free software; you can redistribute it and/or * 7 * modify it under the terms of the GNU Lesser General Public * 8 * License as published by the Free Software Foundation; either * 9 * version 2.1 of the License, or (at your option) any later version. * 10 * * 11 * This library is distributed in the hope that it will be useful, * 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 * Lesser General Public License for more details. * 15 * * 16 * You should have received a copy of the GNU Lesser General Public * 17 * License along with this library; if not, write to the * 18 * Free Software Foundation, Inc., * 19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 20 ***************************************************************************/ 21 22 /* _______ __ __ __ ______ __ __ _______ __ __ 23 * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ 24 * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / 25 * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / 26 * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / 27 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / 28 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ 29 * 30 * Copyright (c) 2004 - 2008 Olof Naess�n and Per Larsson 31 * 32 * 33 * Per Larsson a.k.a finalman 34 * Olof Naess�n a.k.a jansem/yakslem 35 * 36 * Visit: http://guichan.sourceforge.net 37 * 38 * License: (BSD) 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in 46 * the documentation and/or other materials provided with the 47 * distribution. 48 * 3. Neither the name of Guichan nor the names of its contributors may 49 * be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 53 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 54 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 55 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 56 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 57 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 58 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 59 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 60 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 61 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 62 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 63 */ 64 65 /* 66 * For comments regarding functions please see the header file. 67 */ 68 69 #include "fifechan/gui.hpp" 70 71 #include "fifechan/deathlistener.hpp" 72 #include "fifechan/exception.hpp" 73 #include "fifechan/focushandler.hpp" 74 #include "fifechan/graphics.hpp" 75 #include "fifechan/input.hpp" 76 #include "fifechan/keyinput.hpp" 77 #include "fifechan/keylistener.hpp" 78 #include "fifechan/mouseinput.hpp" 79 #include "fifechan/mouselistener.hpp" 80 #include "fifechan/rectangle.hpp" 81 #include "fifechan/visibilityeventhandler.hpp" 82 #include "fifechan/widget.hpp" 83 84 #include <algorithm> 85 #include <iterator> 86 87 namespace fcn 88 { 89 class GuiDeathListener : public DeathListener { 90 public: GuiDeathListener(Gui * gui)91 GuiDeathListener(Gui* gui) { 92 mGui = gui; 93 } ~GuiDeathListener()94 virtual ~GuiDeathListener() { 95 } death(const Event & event)96 virtual void death(const Event& event) { 97 mGui->widgetDied(event.getSource()); 98 } 99 private: 100 Gui* mGui; 101 }; 102 Gui()103 Gui::Gui() 104 :mTop(NULL), 105 mGraphics(NULL), 106 mInput(NULL), 107 mTabbing(true), 108 mShiftPressed(false), 109 mMetaPressed(false), 110 mControlPressed(false), 111 mAltPressed(false), 112 mLastMousePressButton(0), 113 mLastMousePressTimeStamp(0), 114 mLastMouseX(0), 115 mLastMouseY(0), 116 mClickCount(1), 117 mLastMouseDragButton(0) 118 { 119 mFocusHandler = new FocusHandler(); 120 mVisibilityEventHandler = new VisibilityEventHandler(this); 121 mDeathListener = new GuiDeathListener(this); 122 123 Widget::_setVisibilityEventHandler(mVisibilityEventHandler); 124 125 Widget::_setGuiDeathListener(mDeathListener); 126 } 127 ~Gui()128 Gui::~Gui() 129 { 130 if (Widget::widgetExists(mTop)) 131 { 132 setTop(NULL); 133 } 134 Widget::_setVisibilityEventHandler(NULL); 135 Widget::_setGuiDeathListener(NULL); 136 137 delete mFocusHandler; 138 delete mVisibilityEventHandler; 139 delete mDeathListener; 140 } 141 setTop(Widget * top)142 void Gui::setTop(Widget* top) 143 { 144 if (mTop != NULL) 145 { 146 mTop->_setFocusHandler(NULL); 147 } 148 if (top != NULL) 149 { 150 top->_setFocusHandler(mFocusHandler); 151 } 152 153 mTop = top; 154 } 155 getTop() const156 Widget* Gui::getTop() const 157 { 158 return mTop; 159 } 160 setGraphics(Graphics * graphics)161 void Gui::setGraphics(Graphics* graphics) 162 { 163 mGraphics = graphics; 164 } 165 getGraphics() const166 Graphics* Gui::getGraphics() const 167 { 168 return mGraphics; 169 } 170 setInput(Input * input)171 void Gui::setInput(Input* input) 172 { 173 mInput = input; 174 } 175 getInput() const176 Input* Gui::getInput() const 177 { 178 return mInput; 179 } 180 logic()181 void Gui::logic() 182 { 183 if (mTop == NULL) 184 throw FCN_EXCEPTION("No top widget set"); 185 186 handleModalFocus(); 187 handleModalMouseInputFocus(); 188 189 if (mInput != NULL) 190 { 191 mInput->_pollInput(); 192 193 handleKeyInput(); 194 handleMouseInput(); 195 } 196 197 mTop->_logic(); 198 199 handleHiddenWidgets(); 200 handleShownWidgets(); 201 } 202 draw()203 void Gui::draw() 204 { 205 if (mTop == NULL) 206 throw FCN_EXCEPTION("No top widget set"); 207 208 if (mGraphics == NULL) 209 throw FCN_EXCEPTION("No graphics set"); 210 211 if (!mTop->isVisible()) 212 return; 213 214 mGraphics->_beginDraw(); 215 mTop->_draw(mGraphics); 216 mGraphics->_endDraw(); 217 } 218 focusNone()219 void Gui::focusNone() 220 { 221 mFocusHandler->focusNone(); 222 } 223 setTabbingEnabled(bool tabbing)224 void Gui::setTabbingEnabled(bool tabbing) 225 { 226 mTabbing = tabbing; 227 } 228 isTabbingEnabled()229 bool Gui::isTabbingEnabled() 230 { 231 return mTabbing; 232 } 233 addGlobalKeyListener(KeyListener * keyListener)234 void Gui::addGlobalKeyListener(KeyListener* keyListener) 235 { 236 mKeyListeners.push_back(keyListener); 237 } 238 removeGlobalKeyListener(KeyListener * keyListener)239 void Gui::removeGlobalKeyListener(KeyListener* keyListener) 240 { 241 mKeyListeners.remove(keyListener); 242 } 243 enqueueHiddenWidget(Widget * hidden)244 void Gui::enqueueHiddenWidget(Widget* hidden) 245 { 246 mHiddenWidgets.push(hidden); 247 } 248 enqueueShownWidget(Widget * shown)249 void Gui::enqueueShownWidget(Widget* shown) 250 { 251 mShownWidgets.push(shown); 252 } 253 widgetDied(Widget * widget)254 void Gui::widgetDied(Widget* widget) 255 { 256 std::queue<Widget*> tmp; 257 while(!mShownWidgets.empty()) 258 { 259 Widget* shownWidget = mShownWidgets.front(); 260 if (shownWidget != widget) { 261 tmp.push(shownWidget); 262 } 263 mShownWidgets.pop(); 264 } 265 mShownWidgets = tmp; 266 267 tmp = std::queue<Widget*>(); 268 while(!mHiddenWidgets.empty()) 269 { 270 Widget* hiddenWidget = mHiddenWidgets.front(); 271 if (hiddenWidget != widget) { 272 tmp.push(hiddenWidget); 273 } 274 mHiddenWidgets.pop(); 275 } 276 mHiddenWidgets = tmp; 277 } 278 handleMouseInput()279 void Gui::handleMouseInput() 280 { 281 while (!mInput->isMouseQueueEmpty()) 282 { 283 MouseInput mouseInput = mInput->dequeueMouseInput(); 284 285 switch (mouseInput.getType()) 286 { 287 case MouseInput::Pressed: 288 handleMousePressed(mouseInput); 289 break; 290 case MouseInput::Released: 291 handleMouseReleased(mouseInput); 292 break; 293 case MouseInput::Moved: 294 handleMouseMoved(mouseInput); 295 break; 296 case MouseInput::WheelMovedDown: 297 handleMouseWheelMovedDown(mouseInput); 298 break; 299 case MouseInput::WheelMovedUp: 300 handleMouseWheelMovedUp(mouseInput); 301 break; 302 case MouseInput::WheelMovedRight: 303 handleMouseWheelMovedRight(mouseInput); 304 break; 305 case MouseInput::WheelMovedLeft: 306 handleMouseWheelMovedLeft(mouseInput); 307 break; 308 default: 309 throw FCN_EXCEPTION("Unknown mouse input type."); 310 break; 311 } 312 313 // Save the current mouse state. It's needed to send 314 // mouse exited events and mouse entered events when 315 // the mouse exits a widget and when a widget releases 316 // modal mouse input focus. 317 mLastMouseX = mouseInput.getX(); 318 mLastMouseY = mouseInput.getY(); 319 } 320 } 321 handleKeyInput()322 void Gui::handleKeyInput() 323 { 324 while (!mInput->isKeyQueueEmpty()) 325 { 326 KeyInput keyInput = mInput->dequeueKeyInput(); 327 328 // Save modifiers state 329 mShiftPressed = keyInput.isShiftPressed(); 330 mMetaPressed = keyInput.isMetaPressed(); 331 mControlPressed = keyInput.isControlPressed(); 332 mAltPressed = keyInput.isAltPressed(); 333 334 KeyEvent keyEventToGlobalKeyListeners(NULL, 335 NULL, 336 mShiftPressed, 337 mControlPressed, 338 mAltPressed, 339 mMetaPressed, 340 keyInput.getType(), 341 keyInput.isNumericPad(), 342 keyInput.getKey()); 343 344 distributeKeyEventToGlobalKeyListeners(keyEventToGlobalKeyListeners); 345 346 // If a global key listener consumes the event it will not be 347 // sent further to the source of the event. 348 if (keyEventToGlobalKeyListeners.isConsumed()) 349 { 350 continue; 351 } 352 353 bool keyEventConsumed = false; 354 355 // Send key inputs to the focused widgets 356 if (mFocusHandler->getFocused() != NULL) 357 { 358 Widget* source = getKeyEventSource(); 359 KeyEvent keyEvent(source, 360 source, 361 mShiftPressed, 362 mControlPressed, 363 mAltPressed, 364 mMetaPressed, 365 keyInput.getType(), 366 keyInput.isNumericPad(), 367 keyInput.getKey()); 368 369 370 if (!mFocusHandler->getFocused()->isFocusable()) 371 mFocusHandler->focusNone(); 372 else 373 distributeKeyEvent(keyEvent); 374 375 keyEventConsumed = keyEvent.isConsumed(); 376 } 377 378 // If the key event hasn't been consumed and 379 // tabbing is enable check for tab press and 380 // change focus. 381 if (!keyEventConsumed 382 && mTabbing 383 && keyInput.getKey().getValue() == Key::Tab 384 && keyInput.getType() == KeyInput::Pressed) 385 { 386 if (keyInput.isShiftPressed()) 387 mFocusHandler->tabPrevious(); 388 else 389 mFocusHandler->tabNext(); 390 } 391 } 392 } 393 handleMouseMoved(const MouseInput & mouseInput)394 void Gui::handleMouseMoved(const MouseInput& mouseInput) 395 { 396 // Get tha last widgets with the mouse using the 397 // last known mouse position. 398 std::set<Widget*> mLastWidgetsWithMouse = getWidgetsAt(mLastMouseX, mLastMouseY); 399 400 // Check if the mouse has left the application window. 401 if (mouseInput.getX() < 0 402 || mouseInput.getY() < 0 403 || !mTop->getDimension().isContaining(mouseInput.getX(), mouseInput.getY())) 404 { 405 std::set<Widget*>::const_iterator iter; 406 for (iter = mLastWidgetsWithMouse.begin(); 407 iter != mLastWidgetsWithMouse.end(); 408 iter++) 409 { 410 distributeMouseEvent((*iter), 411 MouseEvent::Exited, 412 mouseInput.getButton(), 413 mouseInput.getX(), 414 mouseInput.getY(), 415 true, 416 true); 417 } 418 } 419 // The mouse is in the application window. 420 else 421 { 422 // Calculate which widgets should receive a mouse exited event 423 // and which should receive a mouse entered event by using the 424 // last known mouse position and the latest mouse position. 425 std::set<Widget*> mWidgetsWithMouse = getWidgetsAt(mouseInput.getX(), mouseInput.getY()); 426 std::set<Widget*> mWidgetsWithMouseExited; 427 std::set<Widget*> mWidgetsWithMouseEntered; 428 std::set_difference(mLastWidgetsWithMouse.begin(), 429 mLastWidgetsWithMouse.end(), 430 mWidgetsWithMouse.begin(), 431 mWidgetsWithMouse.end(), 432 std::inserter(mWidgetsWithMouseExited, mWidgetsWithMouseExited.begin())); 433 std::set_difference(mWidgetsWithMouse.begin(), 434 mWidgetsWithMouse.end(), 435 mLastWidgetsWithMouse.begin(), 436 mLastWidgetsWithMouse.end(), 437 std::inserter(mWidgetsWithMouseEntered, mWidgetsWithMouseEntered.begin())); 438 439 std::set<Widget*>::const_iterator iter; 440 for (iter = mWidgetsWithMouseExited.begin(); 441 iter != mWidgetsWithMouseExited.end(); 442 iter++) 443 { 444 distributeMouseEvent((*iter), 445 MouseEvent::Exited, 446 mouseInput.getButton(), 447 mouseInput.getX(), 448 mouseInput.getY(), 449 true, 450 true); 451 // As the mouse has exited a widget we need 452 // to reset the click count and the last mouse 453 // press time stamp. 454 mClickCount = 1; 455 mLastMousePressTimeStamp = 0; 456 } 457 458 for (iter = mWidgetsWithMouseEntered.begin(); 459 iter != mWidgetsWithMouseEntered.end(); 460 iter++) 461 { 462 Widget* widget = (*iter); 463 // If a widget has modal mouse input focus we 464 // only want to send entered events to that widget 465 // and the widget's parents. 466 if ((mFocusHandler->getModalMouseInputFocused() != NULL 467 && widget->isModalMouseInputFocused()) 468 || mFocusHandler->getModalMouseInputFocused() == NULL) 469 { 470 distributeMouseEvent(widget, 471 MouseEvent::Entered, 472 mouseInput.getButton(), 473 mouseInput.getX(), 474 mouseInput.getY(), 475 true, 476 true); 477 } 478 } 479 } 480 481 if (mFocusHandler->getDraggedWidget() != NULL) 482 { 483 distributeMouseEvent(mFocusHandler->getDraggedWidget(), 484 MouseEvent::Dragged, 485 mLastMouseDragButton, 486 mouseInput.getX(), 487 mouseInput.getY()); 488 } 489 else 490 { 491 Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY()); 492 distributeMouseEvent(sourceWidget, 493 MouseEvent::Moved, 494 mouseInput.getButton(), 495 mouseInput.getX(), 496 mouseInput.getY()); 497 } 498 } 499 handleMousePressed(const MouseInput & mouseInput)500 void Gui::handleMousePressed(const MouseInput& mouseInput) 501 { 502 Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY()); 503 504 if (mFocusHandler->getDraggedWidget() != NULL) 505 sourceWidget = mFocusHandler->getDraggedWidget(); 506 507 int sourceWidgetX, sourceWidgetY; 508 sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY); 509 510 if ((mFocusHandler->getModalFocused() != NULL 511 && sourceWidget->isModalFocused()) 512 || mFocusHandler->getModalFocused() == NULL) 513 { 514 sourceWidget->requestFocus(); 515 } 516 517 if (mouseInput.getTimeStamp() - mLastMousePressTimeStamp < 250 518 && mLastMousePressButton == mouseInput.getButton()) 519 mClickCount++; 520 else 521 mClickCount = 1; 522 523 distributeMouseEvent(sourceWidget, 524 MouseEvent::Pressed, 525 mouseInput.getButton(), 526 mouseInput.getX(), 527 mouseInput.getY()); 528 529 mFocusHandler->setLastWidgetPressed(sourceWidget); 530 531 mFocusHandler->setDraggedWidget(sourceWidget); 532 mLastMouseDragButton = mouseInput.getButton(); 533 534 mLastMousePressButton = mouseInput.getButton(); 535 mLastMousePressTimeStamp = mouseInput.getTimeStamp(); 536 } 537 handleMouseWheelMovedDown(const MouseInput & mouseInput)538 void Gui::handleMouseWheelMovedDown(const MouseInput& mouseInput) 539 { 540 Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY()); 541 542 if (mFocusHandler->getDraggedWidget() != NULL) 543 sourceWidget = mFocusHandler->getDraggedWidget(); 544 545 int sourceWidgetX, sourceWidgetY; 546 sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY); 547 548 distributeMouseEvent(sourceWidget, 549 MouseEvent::WheelMovedDown, 550 mouseInput.getButton(), 551 mouseInput.getX(), 552 mouseInput.getY()); 553 } 554 handleMouseWheelMovedUp(const MouseInput & mouseInput)555 void Gui::handleMouseWheelMovedUp(const MouseInput& mouseInput) 556 { 557 Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY()); 558 559 if (mFocusHandler->getDraggedWidget() != NULL) 560 sourceWidget = mFocusHandler->getDraggedWidget(); 561 562 int sourceWidgetX, sourceWidgetY; 563 sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY); 564 565 distributeMouseEvent(sourceWidget, 566 MouseEvent::WheelMovedUp, 567 mouseInput.getButton(), 568 mouseInput.getX(), 569 mouseInput.getY()); 570 } 571 handleMouseWheelMovedRight(const MouseInput & mouseInput)572 void Gui::handleMouseWheelMovedRight(const MouseInput& mouseInput) 573 { 574 Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY()); 575 576 if (mFocusHandler->getDraggedWidget() != NULL) 577 sourceWidget = mFocusHandler->getDraggedWidget(); 578 579 int sourceWidgetX, sourceWidgetY; 580 sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY); 581 582 distributeMouseEvent(sourceWidget, 583 MouseEvent::WheelMovedRight, 584 mouseInput.getButton(), 585 mouseInput.getX(), 586 mouseInput.getY()); 587 } 588 handleMouseWheelMovedLeft(const MouseInput & mouseInput)589 void Gui::handleMouseWheelMovedLeft(const MouseInput& mouseInput) 590 { 591 Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY()); 592 593 if (mFocusHandler->getDraggedWidget() != NULL) 594 sourceWidget = mFocusHandler->getDraggedWidget(); 595 596 int sourceWidgetX, sourceWidgetY; 597 sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY); 598 599 distributeMouseEvent(sourceWidget, 600 MouseEvent::WheelMovedLeft, 601 mouseInput.getButton(), 602 mouseInput.getX(), 603 mouseInput.getY()); 604 } 605 handleMouseReleased(const MouseInput & mouseInput)606 void Gui::handleMouseReleased(const MouseInput& mouseInput) 607 { 608 Widget* sourceWidget = getMouseEventSource(mouseInput.getX(), mouseInput.getY()); 609 610 if (mFocusHandler->getDraggedWidget() != NULL) 611 { 612 if (sourceWidget != mFocusHandler->getLastWidgetPressed()) 613 mFocusHandler->setLastWidgetPressed(NULL); 614 615 sourceWidget = mFocusHandler->getDraggedWidget(); 616 } 617 618 int sourceWidgetX, sourceWidgetY; 619 sourceWidget->getAbsolutePosition(sourceWidgetX, sourceWidgetY); 620 621 distributeMouseEvent(sourceWidget, 622 MouseEvent::Released, 623 mouseInput.getButton(), 624 mouseInput.getX(), 625 mouseInput.getY()); 626 627 if (mouseInput.getButton() == mLastMousePressButton 628 && mFocusHandler->getLastWidgetPressed() == sourceWidget) 629 { 630 distributeMouseEvent(sourceWidget, 631 MouseEvent::Clicked, 632 mouseInput.getButton(), 633 mouseInput.getX(), 634 mouseInput.getY()); 635 636 mFocusHandler->setLastWidgetPressed(NULL); 637 } 638 else 639 { 640 mLastMousePressButton = 0; 641 mClickCount = 0; 642 } 643 644 if (mFocusHandler->getDraggedWidget() != NULL) 645 mFocusHandler->setDraggedWidget(NULL); 646 } 647 getWidgetAt(int x,int y,Widget * exclude)648 Widget* Gui::getWidgetAt(int x, int y, Widget* exclude) 649 { 650 // If the widget's parent has no child then we have found the widget.. 651 Widget* parent = mTop; 652 Widget* child = mTop; 653 654 while (child != NULL) 655 { 656 Widget* swap = child; 657 int parentX, parentY; 658 parent->getAbsolutePosition(parentX, parentY); 659 child = parent->getWidgetAt(x - parentX, y - parentY, exclude); 660 parent = swap; 661 } 662 663 return parent; 664 } 665 getWidgetsAt(int x,int y)666 std::set<Widget*> Gui::getWidgetsAt(int x, int y) 667 { 668 std::set<Widget*> result; 669 670 Widget* widget = mTop; 671 672 while (widget != NULL) 673 { 674 result.insert(widget); 675 int absoluteX, absoluteY; 676 widget->getAbsolutePosition(absoluteX, absoluteY); 677 widget = widget->getWidgetAt(x - absoluteX, y - absoluteY); 678 } 679 680 return result; 681 } 682 getMouseEventSource(int x,int y)683 Widget* Gui::getMouseEventSource(int x, int y) 684 { 685 Widget* widget = getWidgetAt(x, y); 686 687 if (mFocusHandler->getModalMouseInputFocused() != NULL 688 && !widget->isModalMouseInputFocused()) 689 return mFocusHandler->getModalMouseInputFocused(); 690 691 return widget; 692 } 693 getKeyEventSource()694 Widget* Gui::getKeyEventSource() 695 { 696 Widget* widget = mFocusHandler->getFocused(); 697 698 while (widget->_getInternalFocusHandler() != NULL 699 && widget->_getInternalFocusHandler()->getFocused() != NULL) 700 { 701 widget = widget->_getInternalFocusHandler()->getFocused(); 702 } 703 704 return widget; 705 } 706 distributeMouseEvent(Widget * source,int type,int button,int x,int y,bool force,bool toSourceOnly)707 void Gui::distributeMouseEvent(Widget* source, 708 int type, 709 int button, 710 int x, 711 int y, 712 bool force, 713 bool toSourceOnly) 714 { 715 Widget* parent = source; 716 Widget* widget = source; 717 718 if (mFocusHandler->getModalFocused() != NULL 719 && !widget->isModalFocused() 720 && !force) 721 return; 722 723 if (mFocusHandler->getModalMouseInputFocused() != NULL 724 && !widget->isModalMouseInputFocused() 725 && !force) 726 return; 727 728 MouseEvent mouseEvent(source, 729 source, 730 mShiftPressed, 731 mControlPressed, 732 mAltPressed, 733 mMetaPressed, 734 type, 735 button, 736 x, 737 y, 738 mClickCount); 739 740 while (parent != NULL) 741 { 742 // If the widget has been removed due to input 743 // cancel the distribution. 744 if (!Widget::widgetExists(widget)) 745 break; 746 747 parent = widget->getParent(); 748 749 if (widget->isEnabled() || force) 750 { 751 int widgetX, widgetY; 752 widget->getAbsolutePosition(widgetX, widgetY); 753 754 mouseEvent.mX = x - widgetX; 755 mouseEvent.mY = y - widgetY; 756 mouseEvent.mDistributor = widget; 757 std::list<MouseListener*> mouseListeners = widget->_getMouseListeners(); 758 759 // Send the event to all mouse listeners of the widget. 760 for (std::list<MouseListener*>::iterator it = mouseListeners.begin(); 761 it != mouseListeners.end(); 762 ++it) 763 { 764 switch (mouseEvent.getType()) 765 { 766 case MouseEvent::Entered: 767 (*it)->mouseEntered(mouseEvent); 768 break; 769 case MouseEvent::Exited: 770 (*it)->mouseExited(mouseEvent); 771 break; 772 case MouseEvent::Moved: 773 (*it)->mouseMoved(mouseEvent); 774 break; 775 case MouseEvent::Pressed: 776 (*it)->mousePressed(mouseEvent); 777 break; 778 case MouseEvent::Released: 779 (*it)->mouseReleased(mouseEvent); 780 break; 781 case MouseEvent::WheelMovedUp: 782 (*it)->mouseWheelMovedUp(mouseEvent); 783 break; 784 case MouseEvent::WheelMovedDown: 785 (*it)->mouseWheelMovedDown(mouseEvent); 786 break; 787 case MouseEvent::WheelMovedRight: 788 (*it)->mouseWheelMovedRight(mouseEvent); 789 break; 790 case MouseEvent::WheelMovedLeft: 791 (*it)->mouseWheelMovedLeft(mouseEvent); 792 break; 793 case MouseEvent::Dragged: 794 (*it)->mouseDragged(mouseEvent); 795 break; 796 case MouseEvent::Clicked: 797 (*it)->mouseClicked(mouseEvent); 798 break; 799 default: 800 throw FCN_EXCEPTION("Unknown mouse event type."); 801 } 802 } 803 804 if (toSourceOnly) 805 break; 806 807 } 808 809 Widget* swap = widget; 810 widget = parent; 811 parent = swap->getParent(); 812 813 // If a non modal focused widget has been reach 814 // and we have modal focus cancel the distribution. 815 if (mFocusHandler->getModalFocused() != NULL 816 && widget != NULL 817 && !widget->isModalFocused()) 818 break; 819 820 // If a non modal mouse input focused widget has been reach 821 // and we have modal mouse input focus cancel the distribution. 822 if (mFocusHandler->getModalMouseInputFocused() != NULL 823 && widget != NULL 824 && !widget->isModalMouseInputFocused()) 825 break; 826 } 827 } 828 distributeKeyEvent(KeyEvent & keyEvent)829 void Gui::distributeKeyEvent(KeyEvent& keyEvent) 830 { 831 Widget* parent = keyEvent.getSource(); 832 Widget* widget = keyEvent.getSource(); 833 834 if (mFocusHandler->getModalFocused() != NULL 835 && !widget->isModalFocused()) 836 return; 837 838 while (parent != NULL) 839 { 840 // If the widget has been removed due to input 841 // cancel the distribution. 842 if (!Widget::widgetExists(widget)) 843 break; 844 845 parent = widget->getParent(); 846 847 if (widget->isEnabled()) 848 { 849 keyEvent.mDistributor = widget; 850 std::list<KeyListener*> keyListeners = widget->_getKeyListeners(); 851 852 // Send the event to all key listeners of the source widget. 853 for (std::list<KeyListener*>::iterator it = keyListeners.begin(); 854 it != keyListeners.end(); 855 ++it) 856 { 857 switch (keyEvent.getType()) 858 { 859 case KeyEvent::Pressed: 860 (*it)->keyPressed(keyEvent); 861 break; 862 case KeyEvent::Released: 863 (*it)->keyReleased(keyEvent); 864 break; 865 default: 866 throw FCN_EXCEPTION("Unknown key event type."); 867 } 868 } 869 } 870 871 Widget* swap = widget; 872 widget = parent; 873 parent = swap->getParent(); 874 875 // If a non modal focused widget has been reach 876 // and we have modal focus cancel the distribution. 877 if (mFocusHandler->getModalFocused() != NULL 878 && !widget->isModalFocused()) 879 break; 880 } 881 } 882 distributeKeyEventToGlobalKeyListeners(KeyEvent & keyEvent)883 void Gui::distributeKeyEventToGlobalKeyListeners(KeyEvent& keyEvent) 884 { 885 KeyListenerListIterator it; 886 887 for (it = mKeyListeners.begin(); it != mKeyListeners.end(); it++) 888 { 889 switch (keyEvent.getType()) 890 { 891 case KeyEvent::Pressed: 892 (*it)->keyPressed(keyEvent); 893 break; 894 case KeyEvent::Released: 895 (*it)->keyReleased(keyEvent); 896 break; 897 default: 898 throw FCN_EXCEPTION("Unknown key event type."); 899 } 900 901 if (keyEvent.isConsumed()) 902 break; 903 } 904 } 905 handleModalMouseInputFocus()906 void Gui::handleModalMouseInputFocus() 907 { 908 // Check if modal mouse input focus has been gained by a widget. 909 if ((mFocusHandler->getLastWidgetWithModalMouseInputFocus() 910 != mFocusHandler->getModalMouseInputFocused()) 911 && (mFocusHandler->getLastWidgetWithModalMouseInputFocus() == NULL)) 912 { 913 handleModalMouseInputFocusGained(); 914 } 915 // Check if modal mouse input focus has been released. 916 else if ((mFocusHandler->getLastWidgetWithModalMouseInputFocus() 917 != mFocusHandler->getModalMouseInputFocused()) 918 && (mFocusHandler->getLastWidgetWithModalMouseInputFocus() != NULL)) 919 { 920 handleModalMouseInputFocusReleased(); 921 } 922 } 923 handleModalFocus()924 void Gui::handleModalFocus() 925 { 926 // Check if modal focus has been gained by a widget. 927 if ((mFocusHandler->getLastWidgetWithModalFocus() 928 != mFocusHandler->getModalFocused()) 929 && (mFocusHandler->getLastWidgetWithModalFocus() == NULL)) 930 { 931 handleModalFocusGained(); 932 } 933 // Check if modal focus has been released. 934 else if ((mFocusHandler->getLastWidgetWithModalFocus() 935 != mFocusHandler->getModalFocused()) 936 && (mFocusHandler->getLastWidgetWithModalFocus() != NULL)) 937 { 938 handleModalFocusReleased(); 939 } 940 } 941 handleModalFocusGained()942 void Gui::handleModalFocusGained() 943 { 944 // Get all widgets at the last known mouse position 945 // and send them a mouse exited event. 946 std::set<Widget*> mWidgetsWithMouse = getWidgetsAt(mLastMouseX, mLastMouseY); 947 948 std::set<Widget*>::const_iterator iter; 949 for (iter = mWidgetsWithMouse.begin(); 950 iter != mWidgetsWithMouse.end(); 951 iter++) 952 { 953 if ((*iter)->isModalFocused() || (*iter)->isModalMouseInputFocused()) { 954 continue; 955 } 956 distributeMouseEvent((*iter), 957 MouseEvent::Exited, 958 mLastMousePressButton, 959 mLastMouseX, 960 mLastMouseY, 961 true, 962 true); 963 } 964 mFocusHandler->setLastWidgetWithModalFocus(mFocusHandler->getModalFocused()); 965 } 966 handleModalFocusReleased()967 void Gui::handleModalFocusReleased() 968 { 969 // Get all widgets at the last known mouse position 970 // and send them a mouse entered event. 971 std::set<Widget*> mWidgetsWithMouse = getWidgetsAt(mLastMouseX, mLastMouseY); 972 973 std::set<Widget*>::const_iterator iter; 974 for (iter = mWidgetsWithMouse.begin(); 975 iter != mWidgetsWithMouse.end(); 976 iter++) 977 { 978 distributeMouseEvent((*iter), 979 MouseEvent::Entered, 980 mLastMousePressButton, 981 mLastMouseX, 982 mLastMouseY, 983 false, 984 true); 985 } 986 mFocusHandler->setLastWidgetWithModalFocus(NULL); 987 } 988 handleModalMouseInputFocusGained()989 void Gui::handleModalMouseInputFocusGained() 990 { 991 // Get all widgets at the last known mouse position 992 // and send them a mouse exited event. 993 std::set<Widget*> mWidgetsWithMouse = getWidgetsAt(mLastMouseX, mLastMouseY); 994 995 std::set<Widget*>::const_iterator iter; 996 for (iter = mWidgetsWithMouse.begin(); 997 iter != mWidgetsWithMouse.end(); 998 iter++) 999 { 1000 if ((*iter)->isModalMouseInputFocused()) { 1001 continue; 1002 } 1003 distributeMouseEvent((*iter), 1004 MouseEvent::Exited, 1005 mLastMousePressButton, 1006 mLastMouseX, 1007 mLastMouseY, 1008 true, 1009 true); 1010 } 1011 mFocusHandler->setLastWidgetWithModalMouseInputFocus(mFocusHandler->getModalMouseInputFocused()); 1012 } 1013 handleModalMouseInputFocusReleased()1014 void Gui::handleModalMouseInputFocusReleased() 1015 { 1016 // Get all widgets at the last known mouse position 1017 // and send them a mouse entered event. 1018 std::set<Widget*> mWidgetsWithMouse = getWidgetsAt(mLastMouseX, mLastMouseY); 1019 1020 std::set<Widget*>::const_iterator iter; 1021 for (iter = mWidgetsWithMouse.begin(); 1022 iter != mWidgetsWithMouse.end(); 1023 iter++) 1024 { 1025 distributeMouseEvent((*iter), 1026 MouseEvent::Entered, 1027 mLastMousePressButton, 1028 mLastMouseX, 1029 mLastMouseY, 1030 false, 1031 true); 1032 } 1033 mFocusHandler->setLastWidgetWithModalMouseInputFocus(NULL); 1034 } 1035 handleHiddenWidgets()1036 void Gui::handleHiddenWidgets() 1037 { 1038 //process each hidden widget in queue 1039 while(!mHiddenWidgets.empty()) 1040 { 1041 //if the hidden widget had the mouse cursor inside 1042 Widget* hiddenWidget = mHiddenWidgets.front(); 1043 1044 //make sure that the widget wasn't freed after hiding 1045 if(Widget::widgetExists(hiddenWidget) && hiddenWidget->isEnabled()) 1046 { 1047 int hiddenWidgetX, hiddenWidgetY; 1048 hiddenWidget->getAbsolutePosition(hiddenWidgetX, hiddenWidgetY); 1049 1050 Rectangle r(hiddenWidgetX, hiddenWidgetY, hiddenWidget->getWidth(), hiddenWidget->getHeight()); 1051 1052 if(r.isContaining(mLastMouseX, mLastMouseY)) 1053 { 1054 //get the widget that has the cursor now and distribute that the mouse entered it 1055 Widget* underMouseCursor = getWidgetAt(mLastMouseX, mLastMouseY); 1056 1057 distributeMouseEvent(underMouseCursor, 1058 MouseEvent::Entered, 1059 MouseEvent::Empty, 1060 mLastMouseX, 1061 mLastMouseY, 1062 true, 1063 true); 1064 } 1065 } 1066 1067 mHiddenWidgets.pop(); 1068 } 1069 1070 } 1071 handleShownWidgets()1072 void Gui::handleShownWidgets() 1073 { 1074 //process each shown widget in queue 1075 while(!mShownWidgets.empty()) 1076 { 1077 Widget* shownWidget = mShownWidgets.front(); 1078 1079 //if the shown widget has the mouse cursor inside it 1080 int shownWidgetX, shownWidgetY; 1081 shownWidget->getAbsolutePosition(shownWidgetX, shownWidgetY); 1082 1083 Rectangle r(shownWidgetX, shownWidgetY, shownWidget->getWidth(), shownWidget->getHeight()); 1084 1085 if(r.isContaining(mLastMouseX, mLastMouseY) && shownWidget->isEnabled()) 1086 { 1087 //find which widget had the mouse before and distribute that the mouse exited it 1088 Widget* underMouseCursorBefore = getWidgetAt(mLastMouseX, mLastMouseY, shownWidget); 1089 1090 distributeMouseEvent(underMouseCursorBefore, 1091 MouseEvent::Exited, 1092 MouseEvent::Empty, 1093 mLastMouseX, 1094 mLastMouseY, 1095 true, 1096 true 1097 ); 1098 1099 //find which specific widget in the shown widget had the mouse before 1100 //and distribute that the mouse exited it 1101 Widget* underMouseCursorNow = getWidgetAt(mLastMouseX, mLastMouseY); 1102 1103 distributeMouseEvent(underMouseCursorNow, 1104 MouseEvent::Entered, 1105 MouseEvent::Empty, 1106 mLastMouseX, 1107 mLastMouseY, 1108 true, 1109 true 1110 ); 1111 } 1112 1113 mShownWidgets.pop(); 1114 } 1115 1116 } 1117 } 1118