diff --git a/TODO b/TODO index 09d0b12..15841d8 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -* Continue rebasing from 03e447d44e29bc81498f912e227c75a35a420d8d +* Continue rebasing from b50089aa71c0625f5273c468ac169b71f8bba664 * Add a focus listener interface. * Make focus apply synchronously. * Graphics and input objects for DirectX. diff --git a/include/guisan/basiccontainer.hpp b/include/guisan/basiccontainer.hpp index a844569..2c1e43f 100644 --- a/include/guisan/basiccontainer.hpp +++ b/include/guisan/basiccontainer.hpp @@ -76,6 +76,11 @@ namespace gcn class GCN_CORE_DECLSPEC BasicContainer : public Widget, public DeathListener { public: + /** + * Constructor. + */ + BasicContainer(); + /** * Destructor */ @@ -120,9 +125,36 @@ namespace gcn virtual void death(const Event& event); protected: + /** + * Moves a widget to the top. Normally one wants to use + * Widget::moveToTop instead. + * + * THIS METHOD IS NOT SAFE TO CALL INSIDE A WIDGETS LOGIC FUNCTION + * INSIDE ANY LISTER FUNCTIONS! + * + * @param widget The widget to move to the top. + * @since 1.1.0 + */ + void _moveToTopWithNoChecks(Widget* widget); + + /** + * Moves a widget to the bottom. Normally one wants to use + * Widget::moveToBottom instead. + * + * THIS METHOD IS NOT SAFE TO CALL INSIDE A WIDGETS LOGIC FUNCTION + * INSIDE ANY LISTER FUNCTIONS! + * + * @param The widget to move to the bottom. + * @since 1.1.0 + */ + void _moveToBottomWithNoChecks(Widget* widget); + /** * Adds a widget to the basic container. * + * THIS METHOD IS NOT SAFE TO CALL INSIDE A WIDGETS LOGIC FUNCTION + * INSIDE ANY LISTER FUNCTIONS! + * * @param widget The widget to add. * @see remove, clear */ @@ -131,6 +163,9 @@ namespace gcn /** * Removes a widget from the basic container. * + * THIS METHOD IS NOT SAFE TO CALL INSIDE A WIDGETS LOGIC FUNCTION + * INSIDE ANY LISTER FUNCTIONS! + * * @param widget The widget to remove. * @see add, clear */ @@ -139,6 +174,9 @@ namespace gcn /** * Clears the basic container from all widgets. * + * THIS METHOD IS NOT SAFE TO CALL INSIDE A WIDGETS LOGIC FUNCTION + * INSIDE ANY LISTER FUNCTIONS! + * * @see remove, clear */ virtual void clear(); @@ -175,6 +213,21 @@ namespace gcn * Holds all widgets of the basic container. */ WidgetList mWidgets; + + /** + * Holds a widget that should be moved to the top. + */ + Widget* mWidgetToBeMovedToTheTop; + + /** + * Holds a widget that should be moved to the bottom. + */ + Widget* mWidgetToBeMovedToTheBottom; + + /** + * True if logic is currently being processed, false otherwise. + */ + bool mLogicIsProcessing; }; } diff --git a/include/guisan/inputevent.hpp b/include/guisan/inputevent.hpp index 4a6b8dc..735f86d 100644 --- a/include/guisan/inputevent.hpp +++ b/include/guisan/inputevent.hpp @@ -75,13 +75,15 @@ namespace gcn /** * Constructor. * - * @param source The source widget of the event. + * @param source The widget the event concerns. + * @param distributor The distributor of the event. * @param isShiftPressed True if shift is pressed, false otherwise. * @param isControlPressed True if control is pressed, false otherwise. * @param isAltPressed True if alt is pressed, false otherwise. * @param isMetaPressed True if meta is pressed, false otherwise. */ InputEvent(Widget* source, + Widget* distributor, bool isShiftPressed, bool isControlPressed, bool isAltPressed, @@ -140,6 +142,14 @@ namespace gcn */ bool isConsumed() const; + /** + * Gets the distributor of the event. + * The function is used to tell which widget actually distributed the + * event. As input events bubbles up, the source of the event + * may not be the same as the distributor of the event. + */ + Widget* getDistributor() const; + protected: /** * True if shift is pressed, false otherwise. @@ -166,6 +176,20 @@ namespace gcn * false otherwise. */ bool mIsConsumed; + + /** + * Holds the distributor of the event. + */ + Widget* mDistributor; + + /** + * Gui is a friend of this class in order to be able to manipulate + * the protected member variables of this class and at the same time + * keep the MouseEvent class as const as possible. Gui needs to + * update the distributer of this class whenever the distributer + * changes as events bubble up. + */ + friend class Gui; }; } diff --git a/include/guisan/keyevent.hpp b/include/guisan/keyevent.hpp index b7443d2..029dc96 100644 --- a/include/guisan/keyevent.hpp +++ b/include/guisan/keyevent.hpp @@ -83,7 +83,8 @@ namespace gcn /** * Constructor. * - * @param source The source widget of the event. + * @param source The widget the event concerns. + * @param distributor The distributor of the event. * @param isShiftPressed True if shift is pressed, false otherwise. * @param isControlPressed True if control is pressed, false otherwise. * @param isAltPressed True if alt is pressed, false otherwise. @@ -94,6 +95,7 @@ namespace gcn * @param key The key of the event. */ KeyEvent(Widget* source, + Widget* distributor, bool isShiftPressed, bool isControlPressed, bool isAltPressed, diff --git a/include/guisan/mouseevent.hpp b/include/guisan/mouseevent.hpp index e22f4dd..335c445 100644 --- a/include/guisan/mouseevent.hpp +++ b/include/guisan/mouseevent.hpp @@ -78,7 +78,8 @@ namespace gcn /** * Constructor. * - * @param source The source widget of the mouse event. + * @param source The widget the event concerns. + * @param distributor The distributor of the mouse event. * @param isShiftPressed True if shift is pressed, false otherwise. * @param isControlPressed True if control is pressed, false otherwise. * @param isAltPressed True if alt is pressed, false otherwise. @@ -91,6 +92,7 @@ namespace gcn * It's set to zero if another button is used. */ MouseEvent(Widget* source, + Widget* distributor, bool isShiftPressed, bool isControlPressed, bool isAltPressed, diff --git a/src/basiccontainer.cpp b/src/basiccontainer.cpp index a0c1cec..6112ae0 100644 --- a/src/basiccontainer.cpp +++ b/src/basiccontainer.cpp @@ -69,6 +69,12 @@ namespace gcn { + BasicContainer::BasicContainer() : + mWidgetToBeMovedToTheTop(NULL), + mWidgetToBeMovedToTheBottom(NULL), + mLogicIsProcessing(false) + {} + BasicContainer::~BasicContainer() { clear(); @@ -76,31 +82,31 @@ namespace gcn void BasicContainer::moveToTop(Widget* widget) { - WidgetListIterator iter; - for (iter = mWidgets.begin(); iter != mWidgets.end(); iter++) + WidgetListIterator iter = std::find(mWidgets.begin(), mWidgets.end(), widget); + + if (iter == mWidgets.end()) { - if (*iter == widget) - { - mWidgets.erase(iter); - mWidgets.push_back(widget); - return; - } + throw GCN_EXCEPTION("There is no such widget in this container."); } - throw GCN_EXCEPTION("There is no such widget in this container."); + if (mLogicIsProcessing) + mWidgetToBeMovedToTheTop = widget; + else + _moveToTopWithNoChecks(widget); } void BasicContainer::moveToBottom(Widget* widget) { - WidgetListIterator iter; - iter = find(mWidgets.begin(), mWidgets.end(), widget); + WidgetListIterator iter = find(mWidgets.begin(), mWidgets.end(), widget); if (iter == mWidgets.end()) { throw GCN_EXCEPTION("There is no such widget in this container."); } - mWidgets.erase(iter); - mWidgets.push_front(widget); + if (mLogicIsProcessing) + mWidgetToBeMovedToTheBottom = widget; + else + _moveToBottomWithNoChecks(widget); } void BasicContainer::death(const Event& event) @@ -219,7 +225,23 @@ namespace gcn void BasicContainer::logic() { + mLogicIsProcessing = true; + mWidgetToBeMovedToTheTop = NULL; + mWidgetToBeMovedToTheBottom = NULL; logicChildren(); + mLogicIsProcessing = false; + + if (mWidgetToBeMovedToTheTop != NULL) + { + _moveToTopWithNoChecks(mWidgetToBeMovedToTheTop); + mWidgetToBeMovedToTheTop = NULL; + } + + if (mWidgetToBeMovedToTheBottom != NULL) + { + _moveToTopWithNoChecks(mWidgetToBeMovedToTheBottom); + mWidgetToBeMovedToTheBottom = NULL; + } } void BasicContainer::_setFocusHandler(FocusHandler* focusHandler) @@ -399,4 +421,16 @@ namespace gcn return NULL; } + + void BasicContainer::_moveToTopWithNoChecks(Widget* widget) + { + mWidgets.remove(widget); + mWidgets.push_back(widget); + } + + void BasicContainer::_moveToBottomWithNoChecks(Widget* widget) + { + mWidgets.remove(widget); + mWidgets.push_front(widget); + } } diff --git a/src/gui.cpp b/src/gui.cpp index c2ffcd0..6e439f1 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -275,6 +275,7 @@ namespace gcn mAltPressed = keyInput.isAltPressed(); KeyEvent keyEventToGlobalKeyListeners(NULL, + NULL, mShiftPressed, mControlPressed, mAltPressed, @@ -297,7 +298,9 @@ namespace gcn // Send key inputs to the focused widgets if (mFocusHandler->getFocused() != NULL) { - KeyEvent keyEvent(getKeyEventSource(), + Widget* source = getKeyEventSource(); + KeyEvent keyEvent(source, + source, mShiftPressed, mControlPressed, mAltPressed, @@ -704,6 +707,7 @@ namespace gcn } MouseEvent mouseEvent(source, + source, mShiftPressed, mControlPressed, mAltPressed, @@ -732,7 +736,7 @@ namespace gcn mouseEvent.mX = x - widgetX; mouseEvent.mY = y - widgetY; - + mouseEvent.mDistributor = widget; std::list mouseListeners = widget->_getMouseListeners(); // Send the event to all mouse listeners of the widget. @@ -788,6 +792,7 @@ namespace gcn // If a non modal focused widget has been reach // and we have modal focus cancel the distribution. if (mFocusHandler->getModalFocused() != NULL + && widget != NULL && !widget->isModalFocused()) { break; @@ -796,6 +801,7 @@ namespace gcn // If a non modal mouse input focused widget has been reach // and we have modal mouse input focus cancel the distribution. if (mFocusHandler->getModalMouseInputFocused() != NULL + && widget != NULL && !widget->isModalMouseInputFocused()) { break; @@ -833,8 +839,9 @@ namespace gcn if (widget->isEnabled()) { + keyEvent.mDistributor = widget; std::list keyListeners = widget->_getKeyListeners(); - + // Send the event to all key listeners of the source widget. for (std::list::iterator it = keyListeners.begin(); it != keyListeners.end(); diff --git a/src/inputevent.cpp b/src/inputevent.cpp index 734e990..4472fd8 100644 --- a/src/inputevent.cpp +++ b/src/inputevent.cpp @@ -63,18 +63,19 @@ namespace gcn { InputEvent::InputEvent(Widget* source, + Widget* distributor, bool isShiftPressed, bool isControlPressed, bool isAltPressed, - bool isMetaPressed) - :Event(source), - mShiftPressed(isShiftPressed), - mControlPressed(isControlPressed), - mAltPressed(isAltPressed), - mMetaPressed(isMetaPressed), - mIsConsumed(false) + bool isMetaPressed) : + Event(source), + mShiftPressed(isShiftPressed), + mControlPressed(isControlPressed), + mAltPressed(isAltPressed), + mMetaPressed(isMetaPressed), + mIsConsumed(false), + mDistributor(distributor) { - } bool InputEvent::isShiftPressed() const @@ -106,4 +107,9 @@ namespace gcn { return mIsConsumed; } -} + + Widget* InputEvent::getDistributor() const + { + return mDistributor; + } +} // namespace gcn diff --git a/src/keyevent.cpp b/src/keyevent.cpp index ff13596..6d59965 100644 --- a/src/keyevent.cpp +++ b/src/keyevent.cpp @@ -63,24 +63,20 @@ namespace gcn { KeyEvent::KeyEvent(Widget* source, + Widget* distributor, bool isShiftPressed, bool isControlPressed, bool isAltPressed, bool isMetaPressed, unsigned int type, bool isNumericPad, - const Key& key) - :InputEvent(source, - isShiftPressed, - isControlPressed, - isAltPressed, - isMetaPressed), - mType(type), - mIsNumericPad(isNumericPad), - mKey(key) - { - - } + const Key& key) : + InputEvent( + source, distributor, isShiftPressed, isControlPressed, isAltPressed, isMetaPressed), + mType(type), + mIsNumericPad(isNumericPad), + mKey(key) + {} KeyEvent::~KeyEvent() { diff --git a/src/mouseevent.cpp b/src/mouseevent.cpp index 6c37056..371e265 100644 --- a/src/mouseevent.cpp +++ b/src/mouseevent.cpp @@ -63,6 +63,7 @@ namespace gcn { MouseEvent::MouseEvent(Widget* source, + Widget* distributor, bool isShiftPressed, bool isControlPressed, bool isAltPressed, @@ -71,20 +72,15 @@ namespace gcn unsigned int button, int x, int y, - int clickCount) - :InputEvent(source, - isShiftPressed, - isControlPressed, - isAltPressed, - isMetaPressed), - mType(type), - mButton(button), - mX(x), - mY(y), - mClickCount(clickCount) - { - - } + int clickCount) : + InputEvent( + source, distributor, isShiftPressed, isControlPressed, isAltPressed, isMetaPressed), + mType(type), + mButton(button), + mX(x), + mY(y), + mClickCount(clickCount) + {} unsigned int MouseEvent::getButton() const {