Browse Source

Proper stacking of eventsenders for getEventSender().
Fixed crash if event sender is destroyed while sending.
Tweaked default UI style.

Lasse Öörni 15 years ago
parent
commit
cafd3c1491
3 changed files with 69 additions and 36 deletions
  1. 4 2
      Bin/Data/UI/DefaultStyle.xml
  2. 53 30
      Engine/Common/EventListener.cpp
  3. 12 4
      Engine/UI/UI.cpp

+ 4 - 2
Bin/Data/UI/DefaultStyle.xml

@@ -105,7 +105,8 @@
         <text>
         <text>
             <position value="1 1" />
             <position value="1 1" />
             <font name="Cour.ttf" size="12" />
             <font name="Cour.ttf" size="12" />
-            <selectioncolor value="1.0 0.5 0.5" />
+            <hovercolor value="0.5 0.75 0.5" />
+            <selectioncolor value="0.75 0.75 0.75" />
         </text>
         </text>
         <cursor>
         <cursor>
             <size value="4 16" />
             <size value="4 16" />
@@ -354,7 +355,8 @@
     </element>
     </element>
     <element type="FileSelectorListText">
     <element type="FileSelectorListText">
         <font name="Cour.ttf" size="12" />
         <font name="Cour.ttf" size="12" />
-        <selectioncolor value="0.5 0.75 0.5" />
+        <hovercolor value="0.5 0.75 0.5" />
+        <selectioncolor value="0.75 0.75 0.75" />
     </element>
     </element>
     <element type="FileSelectorTitleText">
     <element type="FileSelectorTitleText">
         <font name="Cour.ttf" size="15" />
         <font name="Cour.ttf" size="15" />

+ 53 - 30
Engine/Common/EventListener.cpp

@@ -36,7 +36,7 @@ static VariantMap noEventData;
 std::map<StringHash, std::list<EventListener*> > EventListener::sEventListeners;
 std::map<StringHash, std::list<EventListener*> > EventListener::sEventListeners;
 std::map<std::pair<EventListener*, StringHash>, std::list<EventListener*> > EventListener::sSpecificEventListeners;
 std::map<std::pair<EventListener*, StringHash>, std::list<EventListener*> > EventListener::sSpecificEventListeners;
 
 
-EventListener* eventSender = 0;
+std::vector<EventListener*> eventSender;
 
 
 EventListener::EventListener()
 EventListener::EventListener()
 {
 {
@@ -44,6 +44,13 @@ EventListener::EventListener()
 
 
 EventListener::~EventListener()
 EventListener::~EventListener()
 {
 {
+    // Check if event sender is destroyed during event handling
+    for (unsigned i = 0; i < eventSender.size(); ++i)
+    {
+        if (eventSender[i] == this)
+            eventSender[i] = 0;
+    }
+    
     unsubscribeFromAllEvents();
     unsubscribeFromAllEvents();
     
     
     // Remove from all specific event listeners
     // Remove from all specific event listeners
@@ -219,6 +226,8 @@ void EventListener::sendEvent(StringHash eventType, VariantMap& eventData)
 {
 {
     std::set<EventListener*> processed;
     std::set<EventListener*> processed;
     
     
+    eventSender.push_back(this);
+    
     // Check first the specific event listeners
     // Check first the specific event listeners
     std::map<std::pair<EventListener*, StringHash>, std::list<EventListener*> >::const_iterator i = sSpecificEventListeners.find(
     std::map<std::pair<EventListener*, StringHash>, std::list<EventListener*> >::const_iterator i = sSpecificEventListeners.find(
         std::make_pair(this, eventType));
         std::make_pair(this, eventType));
@@ -230,54 +239,65 @@ void EventListener::sendEvent(StringHash eventType, VariantMap& eventData)
             // Make a copy of the iterator, because the listener might remove itself as a response
             // Make a copy of the iterator, because the listener might remove itself as a response
             std::list<EventListener*>::const_iterator current = j++;
             std::list<EventListener*>::const_iterator current = j++;
             processed.insert(*current);
             processed.insert(*current);
-            eventSender = this;
             (*current)->onEvent(this, eventType, eventData);
             (*current)->onEvent(this, eventType, eventData);
+            // If sending the event caused self to be destroyed, exit immediately!
+            if (getEventSender() != this)
+            {
+                eventSender.pop_back();
+                return;
+            }
         }
         }
     }
     }
     
     
     // Then the non-specific listeners
     // Then the non-specific listeners
     std::map<StringHash, std::list<EventListener*> >::const_iterator j = sEventListeners.find(eventType);
     std::map<StringHash, std::list<EventListener*> >::const_iterator j = sEventListeners.find(eventType);
-    if (j == sEventListeners.end())
-    {
-        eventSender = 0;
-        return;
-    }
-    const std::list<EventListener*>& listeners = j->second;
-    if (processed.empty())
-    {
-        for (std::list<EventListener*>::const_iterator k = listeners.begin(); k != listeners.end();)
-        {
-            std::list<EventListener*>::const_iterator current = k++;
-            eventSender = this;
-            (*current)->onEvent(this, eventType, eventData);
-        }
-    }
-    else
+    if (j != sEventListeners.end())
     {
     {
-        // If there were specific listeners, check that the event is not sent doubly to them
-        for (std::list<EventListener*>::const_iterator k = listeners.begin(); k != listeners.end();)
+        const std::list<EventListener*>& listeners = j->second;
+        if (processed.empty())
         {
         {
-            if (processed.find(*k) == processed.end())
+            for (std::list<EventListener*>::const_iterator k = listeners.begin(); k != listeners.end();)
             {
             {
                 std::list<EventListener*>::const_iterator current = k++;
                 std::list<EventListener*>::const_iterator current = k++;
-                eventSender = this;
                 (*current)->onEvent(this, eventType, eventData);
                 (*current)->onEvent(this, eventType, eventData);
+                if (getEventSender() != this)
+                {
+                    eventSender.pop_back();
+                    return;
+                }
+            }
+        }
+        else
+        {
+            // If there were specific listeners, check that the event is not sent doubly to them
+            for (std::list<EventListener*>::const_iterator k = listeners.begin(); k != listeners.end();)
+            {
+                if (processed.find(*k) == processed.end())
+                {
+                    std::list<EventListener*>::const_iterator current = k++;
+                    (*current)->onEvent(this, eventType, eventData);
+                    if (getEventSender() != this)
+                    {
+                        eventSender.pop_back();
+                        return;
+                    }
+                }
+                else
+                    ++k;
             }
             }
-            else
-                ++k;
         }
         }
     }
     }
     
     
-    eventSender = 0;
+    eventSender.pop_back();
 }
 }
 
 
 void EventListener::sendEvent(EventListener* receiver, StringHash eventType)
 void EventListener::sendEvent(EventListener* receiver, StringHash eventType)
 {
 {
     if (receiver)
     if (receiver)
     {
     {
-        eventSender = this;
+        eventSender.push_back(this);
         receiver->onEvent(this, eventType, noEventData);
         receiver->onEvent(this, eventType, noEventData);
-        eventSender = 0;
+        eventSender.pop_back();
     }
     }
 }
 }
 
 
@@ -285,9 +305,9 @@ void EventListener::sendEvent(EventListener* receiver, StringHash eventType, Var
 {
 {
     if (receiver)
     if (receiver)
     {
     {
-        eventSender = this;
+        eventSender.push_back(this);
         receiver->onEvent(this, eventType, eventData);
         receiver->onEvent(this, eventType, eventData);
-        eventSender = 0;
+        eventSender.pop_back();
     }
     }
 }
 }
 
 
@@ -343,5 +363,8 @@ void EventListener::removeEventListener(EventListener* sender, StringHash eventT
 
 
 EventListener* getEventSender()
 EventListener* getEventSender()
 {
 {
-    return eventSender;
+    if (eventSender.size())
+        return eventSender.back();
+    else
+        return 0;
 }
 }

+ 12 - 4
Engine/UI/UI.cpp

@@ -114,6 +114,9 @@ void UI::setCursor(Cursor* cursor)
 void UI::setFocusElement(UIElement* element)
 void UI::setFocusElement(UIElement* element)
 {
 {
     using namespace TryFocus;
     using namespace TryFocus;
+   
+    UIElement* originalElement = element;
+    WeakPtr<UIElement> elementWeak(element);
     
     
     VariantMap eventData;
     VariantMap eventData;
     eventData[P_ELEMENT] = (void*)element;
     eventData[P_ELEMENT] = (void*)element;
@@ -121,6 +124,9 @@ void UI::setFocusElement(UIElement* element)
     
     
     // The event receivers may optionally divert the focus
     // The event receivers may optionally divert the focus
     element = static_cast<UIElement*>(eventData[P_ELEMENT].getPtr());
     element = static_cast<UIElement*>(eventData[P_ELEMENT].getPtr());
+    // If element is unchanged, check that it did not expire (the event may have caused its deletion)
+    if ((element == originalElement) && (elementWeak.isExpired()))
+        element = 0;
     
     
     if (element)
     if (element)
     {
     {
@@ -579,13 +585,15 @@ void UI::handleKeyDown(StringHash eventType, VariantMap& eventData)
     UIElement* element = getFocusElement();
     UIElement* element = getFocusElement();
     if (element)
     if (element)
     {
     {
-        // Switch focus between focusable sibling elements
+        // Switch focus between focusable elements in the same top level window
         if (key == KEY_TAB)
         if (key == KEY_TAB)
         {
         {
-            UIElement* parent = element->getParent();
-            if (parent)
+            UIElement* topLevel = element->getParent();
+            while ((topLevel) && (topLevel->getParent() != mRootElement))
+                topLevel = topLevel->getParent();
+            if (topLevel)
             {
             {
-                std::vector<UIElement*> children = parent->getChildren();
+                std::vector<UIElement*> children = topLevel->getChildren(true);
                 for (std::vector<UIElement*>::iterator i = children.begin(); i != children.end();)
                 for (std::vector<UIElement*>::iterator i = children.begin(); i != children.end();)
                 {
                 {
                     if ((*i)->getFocusMode() < FM_FOCUSABLE)
                     if ((*i)->getFocusMode() < FM_FOCUSABLE)