Преглед на файлове

Added a better way of destroying GUIElements which also solved an exception that was happening when window was being drag and dropped

Marko Pintera преди 12 години
родител
ревизия
72b857281b

+ 2 - 0
BansheeEngine/Include/BsGUIElement.h

@@ -104,6 +104,7 @@ namespace BansheeEngine
 		CM::Int2 _getOffset() const { return mOffset; }
 		CM::Int2 _getOffset() const { return mOffset; }
 		virtual CM::UINT32 _getRenderElementDepth(CM::UINT32 renderElementIdx) const { return _getDepth(); }
 		virtual CM::UINT32 _getRenderElementDepth(CM::UINT32 renderElementIdx) const { return _getDepth(); }
 		Type _getType() const { return GUIElementBase::Type::Element; }
 		Type _getType() const { return GUIElementBase::Type::Element; }
+		bool _isDestroyed() const { return mIsDestroyed; }
 
 
 		const CM::Rect& _getClippedBounds() const { return mClippedBounds; }
 		const CM::Rect& _getClippedBounds() const { return mClippedBounds; }
 		CM::UINT32 _getDepth() const { return mDepth; }
 		CM::UINT32 _getDepth() const { return mDepth; }
@@ -137,6 +138,7 @@ namespace BansheeEngine
 		static GUILayoutOptions getDefaultLayoutOptions(const GUIElementStyle* style);
 		static GUILayoutOptions getDefaultLayoutOptions(const GUIElementStyle* style);
 
 
 		GUIWidget* mParent;
 		GUIWidget* mParent;
+		bool mIsDestroyed;
 		GUILayoutOptions mLayoutOptions;
 		GUILayoutOptions mLayoutOptions;
 		CM::Rect mClippedBounds;
 		CM::Rect mClippedBounds;
 
 

+ 7 - 7
BansheeEngine/Include/BsGUIManager.h

@@ -31,13 +31,11 @@ namespace BansheeEngine
 
 
 		struct WidgetInfo
 		struct WidgetInfo
 		{
 		{
-			WidgetInfo(GUIWidget* _widget, const boost::signals::connection& _onAddedConn, const boost::signals::connection& _onRemovedConn)
-				:widget(_widget), onAddedConn(_onAddedConn), onRemovedConn(_onRemovedConn)
+			WidgetInfo(GUIWidget* _widget)
+				:widget(_widget)
 			{ }
 			{ }
 
 
 			GUIWidget* widget;
 			GUIWidget* widget;
-			boost::signals::connection onAddedConn;
-			boost::signals::connection onRemovedConn;
 		};
 		};
 
 
 	public:
 	public:
@@ -50,6 +48,8 @@ namespace BansheeEngine
 		void update();
 		void update();
 		void render(CM::ViewportPtr& target, CM::RenderQueue& renderQueue) const;
 		void render(CM::ViewportPtr& target, CM::RenderQueue& renderQueue) const;
 
 
+		void queueForDestroy(GUIElement* element);
+
 		void setCaretColor(const CM::Color& color) { mCaretColor = color; updateCaretTexture(); }
 		void setCaretColor(const CM::Color& color) { mCaretColor = color; updateCaretTexture(); }
 		void setTextSelectionColor(const CM::Color& color) { mTextSelectionColor = color; updateTextSelectionTexture(); }
 		void setTextSelectionColor(const CM::Color& color) { mTextSelectionColor = color; updateTextSelectionTexture(); }
 		const SpriteTexturePtr& getCaretTexture() const { return mCaretTexture; }
 		const SpriteTexturePtr& getCaretTexture() const { return mCaretTexture; }
@@ -65,6 +65,8 @@ namespace BansheeEngine
 		CM::Vector<WidgetInfo>::type mWidgets;
 		CM::Vector<WidgetInfo>::type mWidgets;
 		CM::UnorderedMap<const CM::Viewport*, GUIRenderData>::type mCachedGUIData;
 		CM::UnorderedMap<const CM::Viewport*, GUIRenderData>::type mCachedGUIData;
 
 
+		CM::Stack<GUIElement*>::type mScheduledForDestruction;
+
 		// Element and widget mouse is currently over
 		// Element and widget mouse is currently over
 		GUIWidget* mMouseOverWidget;
 		GUIWidget* mMouseOverWidget;
 		GUIElement* mMouseOverElement;
 		GUIElement* mMouseOverElement;
@@ -111,6 +113,7 @@ namespace BansheeEngine
 		void updateMeshes();
 		void updateMeshes();
 		void updateCaretTexture();
 		void updateCaretTexture();
 		void updateTextSelectionTexture();
 		void updateTextSelectionTexture();
+		void processDestroyQueue();
 
 
 		void onButtonDown(const CM::ButtonEvent& event);
 		void onButtonDown(const CM::ButtonEvent& event);
 		void onButtonUp(const CM::ButtonEvent& event);
 		void onButtonUp(const CM::ButtonEvent& event);
@@ -124,9 +127,6 @@ namespace BansheeEngine
 		void onWindowFocusLost(CM::RenderWindow& win);
 		void onWindowFocusLost(CM::RenderWindow& win);
 		void onWindowMovedOrResized(CM::RenderWindow& win);
 		void onWindowMovedOrResized(CM::RenderWindow& win);
 
 
-		void onGUIElementAddedToWidget(GUIWidget* widget, GUIElement* element);
-		void onGUIElementRemovedFromWidget(GUIWidget* widget, GUIElement* element);
-
 		GUIMouseButton buttonToMouseButton(CM::ButtonCode code) const;
 		GUIMouseButton buttonToMouseButton(CM::ButtonCode code) const;
 		CM::Int2 getWidgetRelativePos(const GUIWidget& widget, const CM::Int2& screenPos) const;
 		CM::Int2 getWidgetRelativePos(const GUIWidget& widget, const CM::Int2& screenPos) const;
 
 

+ 0 - 7
BansheeEngine/Include/BsGUIWidget.h

@@ -57,13 +57,6 @@ namespace BansheeEngine
 		 * 			must be a child of this widget.
 		 * 			must be a child of this widget.
 		 */
 		 */
 		virtual bool _keyEvent(GUIElement* element, const GUIKeyEvent& ev);
 		virtual bool _keyEvent(GUIElement* element, const GUIKeyEvent& ev);
-
-		// Note: These are shared_ptrs because of boosts non_copyable limitation on signals
-		// (which triggers a compile error although the copy constructor is private and I don't make any copies.
-		// Presumably containers like vector or map trigger it). So instead of keeping signals by value
-		// I use a shared_ptr.
-		std::shared_ptr<boost::signal<void(GUIElement*)>> onElementAdded;
-		std::shared_ptr<boost::signal<void(GUIElement*)>> onElementRemoved;
 	protected:
 	protected:
 		friend class CM::SceneObject;
 		friend class CM::SceneObject;
 		friend class GUIElement;
 		friend class GUIElement;

+ 5 - 4
BansheeEngine/Source/BsGUIElement.cpp

@@ -2,6 +2,7 @@
 #include "BsGUIWidget.h"
 #include "BsGUIWidget.h"
 #include "BsGUISkin.h"
 #include "BsGUISkin.h"
 #include "BsGUILayout.h"
 #include "BsGUILayout.h"
+#include "BsGUIManager.h"
 #include "CmException.h"
 #include "CmException.h"
 
 
 using namespace CamelotFramework;
 using namespace CamelotFramework;
@@ -10,7 +11,7 @@ namespace BansheeEngine
 {
 {
 	GUIElement::GUIElement(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions, bool acceptsKeyboardFocus)
 	GUIElement::GUIElement(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions, bool acceptsKeyboardFocus)
 		:mParent(&parent), mLayoutOptions(layoutOptions), mWidth(0), mHeight(0), mDepth(0), mStyle(style),
 		:mParent(&parent), mLayoutOptions(layoutOptions), mWidth(0), mHeight(0), mDepth(0), mStyle(style),
-		mAcceptsKeyboardFocus(acceptsKeyboardFocus)
+		mAcceptsKeyboardFocus(acceptsKeyboardFocus), mIsDestroyed(false)
 	{
 	{
 		mParent->registerElement(this);
 		mParent->registerElement(this);
 	}
 	}
@@ -209,8 +210,8 @@ namespace BansheeEngine
 		if(element->mParent != nullptr)
 		if(element->mParent != nullptr)
 			element->mParent->unregisterElement(element);
 			element->mParent->unregisterElement(element);
 
 
-		// Destroy at beginning of next frame, because we can't be sure that something isn't currently referencing
-		// this element (e..g GUIManager)
-		deferredCall(std::bind(&cm_delete<PoolAlloc, GUIElement>, element));
+		element->mIsDestroyed = true;
+
+		GUIManager::instance().queueForDestroy(element);
 	}
 	}
 }
 }

+ 29 - 26
BansheeEngine/Source/BsGUIManager.cpp

@@ -100,10 +100,7 @@ namespace BansheeEngine
 
 
 	void GUIManager::registerWidget(GUIWidget* widget)
 	void GUIManager::registerWidget(GUIWidget* widget)
 	{
 	{
-		boost::signals::connection onElementAddedConn = widget->onElementAdded->connect(boost::bind(&GUIManager::onGUIElementAddedToWidget, this, widget, _1));
-		boost::signals::connection onElementRemovedConn = widget->onElementRemoved->connect(boost::bind(&GUIManager::onGUIElementRemovedFromWidget, this, widget, _1));
-
-		mWidgets.push_back(WidgetInfo(widget, onElementAddedConn, onElementRemovedConn));
+		mWidgets.push_back(WidgetInfo(widget));
 
 
 		const Viewport* renderTarget = widget->getTarget();
 		const Viewport* renderTarget = widget->getTarget();
 
 
@@ -123,8 +120,6 @@ namespace BansheeEngine
 
 
 		if(findIter != end(mWidgets))
 		if(findIter != end(mWidgets))
 		{
 		{
-			findIter->onAddedConn.disconnect();
-			findIter->onRemovedConn.disconnect();
 			mWidgets.erase(findIter);
 			mWidgets.erase(findIter);
 		}
 		}
 
 
@@ -186,6 +181,26 @@ namespace BansheeEngine
 		}
 		}
 
 
 		updateMeshes();
 		updateMeshes();
+
+		if(mMouseOverElement != nullptr && mMouseOverElement->_isDestroyed())
+		{
+			mMouseOverElement = nullptr;
+			mMouseOverWidget = nullptr;
+		}
+
+		if(mActiveElement != nullptr && mActiveElement->_isDestroyed())
+		{
+			mActiveElement = nullptr;
+			mActiveWidget = nullptr;
+		}
+
+		if(mKeyboardFocusElement != nullptr && mKeyboardFocusElement->_isDestroyed())
+		{
+			mKeyboardFocusElement = nullptr;
+			mKeyboardFocusWidget = nullptr;
+		}
+
+		processDestroyQueue();
 	}
 	}
 
 
 	void GUIManager::render(ViewportPtr& target, CM::RenderQueue& renderQueue) const
 	void GUIManager::render(ViewportPtr& target, CM::RenderQueue& renderQueue) const
@@ -890,30 +905,18 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
-	void GUIManager::onGUIElementRemovedFromWidget(GUIWidget* widget, GUIElement* element)
+	void GUIManager::queueForDestroy(GUIElement* element)
 	{
 	{
-		if(mMouseOverElement == element)
-		{
-			mMouseOverElement = nullptr;
-			mMouseOverWidget = nullptr;
-		}
-
-		if(mActiveElement == element)
-		{
-			mActiveElement = nullptr;
-			mActiveWidget = nullptr;
-		}
-
-		if(mKeyboardFocusElement == element)
-		{
-			mKeyboardFocusElement = nullptr;
-			mKeyboardFocusWidget = nullptr;
-		}
+		mScheduledForDestruction.push(element);
 	}
 	}
 
 
-	void GUIManager::onGUIElementAddedToWidget(GUIWidget* widget, GUIElement* element)
+	void GUIManager::processDestroyQueue()
 	{
 	{
-
+		while(!mScheduledForDestruction.empty())
+		{
+			cm_delete<PoolAlloc>(mScheduledForDestruction.top());
+			mScheduledForDestruction.pop();
+		}
 	}
 	}
 
 
 	GUIMouseButton GUIManager::buttonToMouseButton(ButtonCode code) const
 	GUIMouseButton GUIManager::buttonToMouseButton(ButtonCode code) const

+ 0 - 9
BansheeEngine/Source/BsGUIWidget.cpp

@@ -28,9 +28,6 @@ namespace BansheeEngine
 		mLastFramePosition = SO()->getWorldPosition();
 		mLastFramePosition = SO()->getWorldPosition();
 		mLastFrameRotation = SO()->getWorldRotation();
 		mLastFrameRotation = SO()->getWorldRotation();
 		mLastFrameScale = SO()->getWorldScale();
 		mLastFrameScale = SO()->getWorldScale();
-
-		onElementAdded = std::shared_ptr<boost::signal<void(GUIElement*)>>(cm_new<boost::signal<void(GUIElement*)>>());
-		onElementRemoved = std::shared_ptr<boost::signal<void(GUIElement*)>>(cm_new<boost::signal<void(GUIElement*)>>());
 	}
 	}
 
 
 	GUIWidget::~GUIWidget()
 	GUIWidget::~GUIWidget()
@@ -182,9 +179,6 @@ namespace BansheeEngine
 		mElements.push_back(elem);
 		mElements.push_back(elem);
 
 
 		mWidgetIsDirty = true;
 		mWidgetIsDirty = true;
-
-		if(!onElementAdded->empty())
-			(*onElementAdded)(elem);
 	}
 	}
 
 
 	void GUIWidget::unregisterElement(GUIElement* elem)
 	void GUIWidget::unregisterElement(GUIElement* elem)
@@ -198,9 +192,6 @@ namespace BansheeEngine
 
 
 		mElements.erase(iterFind);
 		mElements.erase(iterFind);
 		mWidgetIsDirty = true;
 		mWidgetIsDirty = true;
-
-		if(!onElementRemoved->empty())
-			(*onElementRemoved)(elem);
 	}
 	}
 
 
 	void GUIWidget::registerArea(GUIArea* area)
 	void GUIWidget::registerArea(GUIArea* area)

+ 0 - 1
EditorWindowDock.txt

@@ -8,7 +8,6 @@ Ensure that dropping a window onto a mover will actually dock it properly
 
 
 Moving a cursor to a non-client area doesn't seem to refresh the GUIElements properly. They are handled as if I was mousing over them.
 Moving a cursor to a non-client area doesn't seem to refresh the GUIElements properly. They are handled as if I was mousing over them.
 I still have the issue where GUIManager hack code got triggered
 I still have the issue where GUIManager hack code got triggered
-Get rid of WIndowMover and WindowFrame!! (Change them to GUIToggle and GUITexture)
 
 
 Get rid of the GUIManager mouseUp hack when I ensure resize/move using non client areas work
 Get rid of the GUIManager mouseUp hack when I ensure resize/move using non client areas work