Przeglądaj źródła

Changed how GUI MouseOver and MouseOut are handled so that it works correctly when elements use by those events

Marko Pintera 10 lat temu
rodzic
commit
9c96e84d26

+ 19 - 2
BansheeEngine/Include/BsGUIManager.h

@@ -81,6 +81,23 @@ namespace BansheeEngine
 			GUIWidget* widget;
 			GUIWidget* widget;
 		};
 		};
 
 
+		/**
+		 * @brief	Container for data about a single GUI element and its widget currently under the pointer.
+		 */
+		struct ElementInfoUnderPointer
+		{
+			ElementInfoUnderPointer(GUIElement* element, GUIWidget* widget)
+				:element(element), widget(widget), usesMouseOver(false), 
+				receivedMouseOver(false), isHovering(false)
+			{ }
+
+			GUIElement* element;
+			GUIWidget* widget;
+			bool usesMouseOver;
+			bool receivedMouseOver;
+			bool isHovering;
+		};
+
 		/**
 		/**
 		 * @brief	Container for GUI element in focus.
 		 * @brief	Container for GUI element in focus.
 		 */
 		 */
@@ -347,8 +364,8 @@ namespace BansheeEngine
 		Stack<GUIElement*> mScheduledForDestruction;
 		Stack<GUIElement*> mScheduledForDestruction;
 
 
 		// Element and widget pointer is currently over
 		// Element and widget pointer is currently over
-		Vector<ElementInfo> mElementsUnderPointer;
-		Vector<ElementInfo> mNewElementsUnderPointer;
+		Vector<ElementInfoUnderPointer> mElementsUnderPointer;
+		Vector<ElementInfoUnderPointer> mNewElementsUnderPointer;
 
 
 		// Element and widget that's being clicked on
 		// Element and widget that's being clicked on
 		GUIMouseButton mActiveMouseButton;
 		GUIMouseButton mActiveMouseButton;

+ 16 - 0
BansheeEngine/Source/BsGUIDropDownHitBox.cpp

@@ -64,6 +64,22 @@ namespace BansheeEngine
 			{
 			{
 				return true;
 				return true;
 			}
 			}
+			else if (ev.getType() == GUIMouseEventType::MouseOver)
+			{
+				return true;
+			}
+			else if (ev.getType() == GUIMouseEventType::MouseOut)
+			{
+				return true;
+			}
+			else if (ev.getType() == GUIMouseEventType::MouseMove)
+			{
+				return true;
+			}
+			else if (ev.getType() == GUIMouseEventType::MouseDoubleClick)
+			{
+				return true;
+			}
 		}
 		}
 
 
 		return processed;
 		return processed;

+ 57 - 29
BansheeEngine/Source/BsGUIManager.cpp

@@ -949,7 +949,7 @@ namespace BansheeEngine
 
 
 		for(auto& elementInfo : mElementsUnderPointer)
 		for(auto& elementInfo : mElementsUnderPointer)
 		{
 		{
-			mNewElementsInFocus.push_back(elementInfo);
+			mNewElementsInFocus.push_back(ElementInfo(elementInfo.element, elementInfo.widget));
 
 
 			auto iterFind = std::find_if(begin(mElementsInFocus), end(mElementsInFocus), 
 			auto iterFind = std::find_if(begin(mElementsInFocus), end(mElementsInFocus), 
 				[=] (const ElementInfo& x) { return x.element == elementInfo.element; });
 				[=] (const ElementInfo& x) { return x.element == elementInfo.element; });
@@ -1169,7 +1169,18 @@ namespace BansheeEngine
 
 
 						if(!element->_isDisabled() && element->_isInBounds(localPos))
 						if(!element->_isDisabled() && element->_isInBounds(localPos))
 						{
 						{
-							mNewElementsUnderPointer.push_back(ElementInfo(element, widget));
+							ElementInfoUnderPointer elementInfo(element, widget);
+
+							auto iterFind = std::find_if(mElementsUnderPointer.begin(), mElementsUnderPointer.end(),
+								[=](const ElementInfoUnderPointer& x) { return x.element == element; });
+
+							if (iterFind != mElementsUnderPointer.end())
+							{
+								elementInfo.usesMouseOver = iterFind->usesMouseOver;
+								elementInfo.receivedMouseOver = iterFind->receivedMouseOver;
+							}
+
+							mNewElementsUnderPointer.push_back(elementInfo);
 						}
 						}
 					}
 					}
 				}
 				}
@@ -1179,63 +1190,80 @@ namespace BansheeEngine
 		}
 		}
 
 
 		std::sort(mNewElementsUnderPointer.begin(), mNewElementsUnderPointer.end(), 
 		std::sort(mNewElementsUnderPointer.begin(), mNewElementsUnderPointer.end(), 
-			[](const ElementInfo& a, const ElementInfo& b)
+			[](const ElementInfoUnderPointer& a, const ElementInfoUnderPointer& b)
 		{
 		{
 			return a.element->_getDepth() < b.element->_getDepth();
 			return a.element->_getDepth() < b.element->_getDepth();
 		});
 		});
 
 
 		// Send MouseOut and MouseOver events
 		// Send MouseOut and MouseOver events
+
 		bool eventProcessed = false;
 		bool eventProcessed = false;
-		for(auto& elementInfo : mElementsUnderPointer)
+
+		for (auto& elementInfo : mNewElementsUnderPointer)
 		{
 		{
 			GUIElement* element = elementInfo.element;
 			GUIElement* element = elementInfo.element;
 			GUIWidget* widget = elementInfo.widget;
 			GUIWidget* widget = elementInfo.widget;
 
 
-			auto iterFind = std::find_if(mNewElementsUnderPointer.begin(), mNewElementsUnderPointer.end(), 
-				[=] (const ElementInfo& x) { return x.element == element; });
+			if (elementInfo.receivedMouseOver)
+			{
+				elementInfo.isHovering = true;
+				if (elementInfo.usesMouseOver)
+					break;
 
 
-			if(iterFind == mNewElementsUnderPointer.end())
+				continue;
+			}
+
+			auto iterFind = std::find_if(mActiveElements.begin(), mActiveElements.end(),
+				[&](const ElementInfo& x) { return x.element == element; });
+
+			// Send MouseOver event
+			if (mActiveElements.size() == 0 || iterFind != mActiveElements.end())
 			{
 			{
-				auto iterFind2 = std::find_if(mActiveElements.begin(), mActiveElements.end(), 
-					[=](const ElementInfo& x) { return x.element == element; });
+				Vector2I localPos;
+				if (widget != nullptr)
+					localPos = getWidgetRelativePos(*widget, pointerScreenPos);
 
 
-				// Send MouseOut event
-				if(mActiveElements.size() == 0 || iterFind2 != mActiveElements.end())
-				{
-					Vector2I localPos = getWidgetRelativePos(*widget, pointerScreenPos);
+				mMouseEvent = GUIMouseEvent(buttonStates, shift, control, alt);
 
 
-					mMouseEvent.setMouseOutData(localPos);
-					if(sendMouseEvent(widget, element, mMouseEvent))
-						eventProcessed = true;
+				mMouseEvent.setMouseOverData(localPos);
+				elementInfo.receivedMouseOver = true;
+				elementInfo.isHovering = true;
+				if (sendMouseEvent(widget, element, mMouseEvent))
+				{
+					eventProcessed = true;
+					elementInfo.usesMouseOver = true;
+					break;
 				}
 				}
 			}
 			}
 		}
 		}
 
 
-		for(auto& elementInfo : mNewElementsUnderPointer)
+		for(auto& elementInfo : mElementsUnderPointer)
 		{
 		{
 			GUIElement* element = elementInfo.element;
 			GUIElement* element = elementInfo.element;
 			GUIWidget* widget = elementInfo.widget;
 			GUIWidget* widget = elementInfo.widget;
 
 
-			auto iterFind = std::find_if(begin(mElementsUnderPointer), end(mElementsUnderPointer), 
-				[=] (const ElementInfo& x) { return x.element == element; });
+			if (!elementInfo.receivedMouseOver)
+				continue;
+
+			auto iterFind = std::find_if(mNewElementsUnderPointer.begin(), mNewElementsUnderPointer.end(),
+				[=] (const ElementInfoUnderPointer& x) { return x.element == element; });
 
 
-			if(iterFind == mElementsUnderPointer.end())
+			if (iterFind == mNewElementsUnderPointer.end() || !iterFind->isHovering)
 			{
 			{
 				auto iterFind2 = std::find_if(mActiveElements.begin(), mActiveElements.end(), 
 				auto iterFind2 = std::find_if(mActiveElements.begin(), mActiveElements.end(), 
-					[&](const ElementInfo& x) { return x.element == element; });
+					[=](const ElementInfo& x) { return x.element == element; });
 
 
-				// Send MouseOver event
+				// Send MouseOut event
 				if(mActiveElements.size() == 0 || iterFind2 != mActiveElements.end())
 				if(mActiveElements.size() == 0 || iterFind2 != mActiveElements.end())
 				{
 				{
-					Vector2I localPos;
-					if(widget != nullptr)
-						localPos = getWidgetRelativePos(*widget, pointerScreenPos);
-
-					mMouseEvent = GUIMouseEvent(buttonStates, shift, control, alt);
+					Vector2I localPos = getWidgetRelativePos(*widget, pointerScreenPos);
 
 
-					mMouseEvent.setMouseOverData(localPos);
-					if(sendMouseEvent(widget, element, mMouseEvent))
+					mMouseEvent.setMouseOutData(localPos);
+					if (sendMouseEvent(widget, element, mMouseEvent))
+					{
 						eventProcessed = true;
 						eventProcessed = true;
+						break;
+					}
 				}
 				}
 			}
 			}
 		}
 		}

+ 2 - 10
TODO.txt

@@ -25,16 +25,8 @@ GUIResourceField doesn't distinguish between tex2d, tex3d and texcube.
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 Project window
 Project window
 
 
-Crash when opening and closing the context menu many times, trying to delete a GUILayout that has already been deleted
- - This might happen when parent layout or panel goes out of scope. It will get destroyed but it will not mark any of its children as destroyed
- - And I can't just call Destroy in finalizer since it accesses its children which might have been finalized already
- - When a window is closed(editor, modal or drop down, do I call destroy on its child layout?)
- - SOLUTION: My only option to deal with this might be to store child elements ScriptObject references in C++. If I do that make sure
-   to properly unregister elements when they're removed manually from the parent, and if they go out of scope (i.e. child goes out of scope
-   before the parent)
- - In general, do I want GUI elements to go out of scope when not being referenced? Probably doesn't matter much, and even if I add C++ handles
-   that doesn't solve my issue as elements will go out of scope during assembly refresh
-
+Right-clicking on an element to open a context menu doesn't seem to properly select the element first
+ - This might only happen if the right click happens while another context menu is already open
 When clicking on drop down window it will interact with GUI elements beneath it
 When clicking on drop down window it will interact with GUI elements beneath it
 
 
 Simple tasks:
 Simple tasks: