Browse Source

Closing an editor window no longer causes an exception in GUIManager
Fixed an issue where scene manager wasn't being notified when a component was being removed due to its parent SceneObject destruction

Marko Pintera 12 years ago
parent
commit
a3d90405e7

+ 15 - 1
BansheeEngine/Include/BsGUIManager.h

@@ -29,6 +29,17 @@ namespace BansheeEngine
 			bool isDirty;
 			bool isDirty;
 		};
 		};
 
 
+		struct WidgetInfo
+		{
+			WidgetInfo(GUIWidget* _widget, const boost::signals::connection& _onAddedConn, const boost::signals::connection& _onRemovedConn)
+				:widget(_widget), onAddedConn(_onAddedConn), onRemovedConn(_onRemovedConn)
+			{ }
+
+			GUIWidget* widget;
+			boost::signals::connection onAddedConn;
+			boost::signals::connection onRemovedConn;
+		};
+
 	public:
 	public:
 		GUIManager();
 		GUIManager();
 		~GUIManager();
 		~GUIManager();
@@ -49,7 +60,7 @@ namespace BansheeEngine
 		GUIInputSelection* getInputSelectionTool() const { return mInputSelection; }
 		GUIInputSelection* getInputSelectionTool() const { return mInputSelection; }
 
 
 	private:
 	private:
-		CM::Vector<GUIWidget*>::type mWidgets;
+		CM::Vector<WidgetInfo>::type mWidgets;
 		CM::UnorderedMap<const CM::Viewport*, GUIRenderData>::type mCachedGUIData;
 		CM::UnorderedMap<const CM::Viewport*, GUIRenderData>::type mCachedGUIData;
 
 
 		// Element and widget mouse is currently over
 		// Element and widget mouse is currently over
@@ -109,6 +120,9 @@ 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;
 	};
 	};

+ 10 - 0
BansheeEngine/Include/BsGUIWidget.h

@@ -5,6 +5,7 @@
 #include "CmRect.h"
 #include "CmRect.h"
 #include "CmVector3.h"
 #include "CmVector3.h"
 #include "CmQuaternion.h"
 #include "CmQuaternion.h"
+#include <boost/signal.hpp>
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -56,6 +57,13 @@ 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;
@@ -70,6 +78,8 @@ namespace BansheeEngine
 		void registerArea(GUIArea* area);
 		void registerArea(GUIArea* area);
 		void unregisterArea(GUIArea* area);
 		void unregisterArea(GUIArea* area);
 	private:
 	private:
+		GUIWidget(const GUIWidget& other) { }
+
 		void updateBounds() const;
 		void updateBounds() const;
 
 
 		virtual void ownerWindowResized();
 		virtual void ownerWindowResized();

+ 67 - 18
BansheeEngine/Source/BsGUIManager.cpp

@@ -72,9 +72,9 @@ namespace BansheeEngine
 	{
 	{
 		// Make a copy of widgets, since destroying them will remove them from mWidgets and
 		// Make a copy of widgets, since destroying them will remove them from mWidgets and
 		// we can't iterate over an array thats getting modified
 		// we can't iterate over an array thats getting modified
-		Vector<GUIWidget*>::type widgetCopy = mWidgets;
+		Vector<WidgetInfo>::type widgetCopy = mWidgets;
 		for(auto& widget : widgetCopy)
 		for(auto& widget : widgetCopy)
-			widget->destroy();
+			widget.widget->destroy();
 
 
 		mOnButtonDownConn.disconnect();
 		mOnButtonDownConn.disconnect();
 		mOnButtonUpConn.disconnect();
 		mOnButtonUpConn.disconnect();
@@ -91,7 +91,10 @@ namespace BansheeEngine
 
 
 	void GUIManager::registerWidget(GUIWidget* widget)
 	void GUIManager::registerWidget(GUIWidget* widget)
 	{
 	{
-		mWidgets.push_back(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));
 
 
 		const Viewport* renderTarget = widget->getTarget();
 		const Viewport* renderTarget = widget->getTarget();
 
 
@@ -107,10 +110,14 @@ namespace BansheeEngine
 
 
 	void GUIManager::unregisterWidget(GUIWidget* widget)
 	void GUIManager::unregisterWidget(GUIWidget* widget)
 	{
 	{
-		auto findIter = std::find(begin(mWidgets), end(mWidgets), widget);
+		auto findIter = std::find_if(begin(mWidgets), end(mWidgets), [=] (const WidgetInfo& x) { return x.widget == widget; } );
 
 
 		if(findIter != end(mWidgets))
 		if(findIter != end(mWidgets))
+		{
+			findIter->onAddedConn.disconnect();
+			findIter->onRemovedConn.disconnect();
 			mWidgets.erase(findIter);
 			mWidgets.erase(findIter);
+		}
 
 
 		if(mMouseOverWidget == widget)
 		if(mMouseOverWidget == widget)
 		{
 		{
@@ -118,12 +125,24 @@ namespace BansheeEngine
 			mMouseOverElement = nullptr;
 			mMouseOverElement = nullptr;
 		}
 		}
 
 
+		if(mKeyboardFocusWidget == widget)
+		{
+			mKeyboardFocusWidget = nullptr;
+			mKeyboardFocusElement = nullptr;
+		}
+
+		if(mActiveWidget == widget)
+		{
+			mActiveWidget = nullptr;
+			mActiveElement = nullptr;
+		}
+
 		const Viewport* renderTarget = widget->getTarget();
 		const Viewport* renderTarget = widget->getTarget();
 		GUIRenderData& renderData = mCachedGUIData[renderTarget];
 		GUIRenderData& renderData = mCachedGUIData[renderTarget];
 
 
-		findIter = std::find(begin(renderData.widgets), end(renderData.widgets), widget);
-		if(findIter != end(renderData.widgets))
-			renderData.widgets.erase(findIter);
+		auto findIter2 = std::find(begin(renderData.widgets), end(renderData.widgets), widget);
+		if(findIter2 != end(renderData.widgets))
+			renderData.widgets.erase(findIter2);
 
 
 		if(renderData.widgets.size() == 0)
 		if(renderData.widgets.size() == 0)
 			mCachedGUIData.erase(renderTarget);
 			mCachedGUIData.erase(renderTarget);
@@ -134,9 +153,9 @@ namespace BansheeEngine
 	void GUIManager::update()
 	void GUIManager::update()
 	{
 	{
 		// Update layouts
 		// Update layouts
-		for(auto& widget : mWidgets)
+		for(auto& widgetInfo : mWidgets)
 		{
 		{
-			widget->_updateLayout();
+			widgetInfo.widget->_updateLayout();
 		}
 		}
 
 
 		// Blink caret
 		// Blink caret
@@ -640,9 +659,9 @@ namespace BansheeEngine
 #if CM_DEBUG_MODE
 #if CM_DEBUG_MODE
 		// Checks if all referenced windows actually exist
 		// Checks if all referenced windows actually exist
 		Vector<RenderWindow*>::type activeWindows = RenderWindowManager::instance().getRenderWindows();
 		Vector<RenderWindow*>::type activeWindows = RenderWindowManager::instance().getRenderWindows();
-		for(auto& widget : mWidgets)
+		for(auto& widgetInfo : mWidgets)
 		{
 		{
-			auto iterFind = std::find(begin(activeWindows), end(activeWindows), widget->getOwnerWindow());
+			auto iterFind = std::find(begin(activeWindows), end(activeWindows), widgetInfo.widget->getOwnerWindow());
 
 
 			if(iterFind == activeWindows.end())
 			if(iterFind == activeWindows.end())
 			{
 			{
@@ -669,13 +688,13 @@ namespace BansheeEngine
 		Int2 screenPos;
 		Int2 screenPos;
 		Int2 localPos;
 		Int2 localPos;
 
 
-		for(auto& widget : mWidgets)
+		for(auto& widgetInfo : mWidgets)
 		{
 		{
-			const RenderWindow* window = widget->getOwnerWindow();
+			const RenderWindow* window = widgetInfo.widget->getOwnerWindow();
 
 
 			if(window->hasFocus())
 			if(window->hasFocus())
 			{
 			{
-				widgetInFocus = widget;
+				widgetInFocus = widgetInfo.widget;
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -688,8 +707,9 @@ namespace BansheeEngine
 			Vector4 vecScreenPos((float)screenPos.x, (float)screenPos.y, 0.0f, 1.0f);
 			Vector4 vecScreenPos((float)screenPos.x, (float)screenPos.y, 0.0f, 1.0f);
 
 
 			UINT32 topMostDepth = std::numeric_limits<UINT32>::max();
 			UINT32 topMostDepth = std::numeric_limits<UINT32>::max();
-			for(auto& widget : mWidgets)
+			for(auto& widgetInfo : mWidgets)
 			{
 			{
+				GUIWidget* widget = widgetInfo.widget;
 				if(widget->getOwnerWindow() == window && widget->inBounds(screenPos))
 				if(widget->getOwnerWindow() == window && widget->inBounds(screenPos))
 				{
 				{
 					const Matrix4& worldTfrm = widget->SO()->getWorldTfrm();
 					const Matrix4& worldTfrm = widget->SO()->getWorldTfrm();
@@ -810,8 +830,9 @@ namespace BansheeEngine
 
 
 	void GUIManager::onWindowFocusGained(RenderWindow& win)
 	void GUIManager::onWindowFocusGained(RenderWindow& win)
 	{
 	{
-		for(auto& widget : mWidgets)
+		for(auto& widgetInfo : mWidgets)
 		{
 		{
+			GUIWidget* widget = widgetInfo.widget;
 			if(widget->getOwnerWindow() == &win)
 			if(widget->getOwnerWindow() == &win)
 				widget->ownerWindowFocusChanged();
 				widget->ownerWindowFocusChanged();
 		}
 		}
@@ -819,8 +840,9 @@ namespace BansheeEngine
 
 
 	void GUIManager::onWindowFocusLost(RenderWindow& win)
 	void GUIManager::onWindowFocusLost(RenderWindow& win)
 	{
 	{
-		for(auto& widget : mWidgets)
+		for(auto& widgetInfo : mWidgets)
 		{
 		{
+			GUIWidget* widget = widgetInfo.widget;
 			if(widget->getOwnerWindow() == &win)
 			if(widget->getOwnerWindow() == &win)
 				widget->ownerWindowFocusChanged();
 				widget->ownerWindowFocusChanged();
 		}
 		}
@@ -828,13 +850,40 @@ namespace BansheeEngine
 
 
 	void GUIManager::onWindowMovedOrResized(RenderWindow& win)
 	void GUIManager::onWindowMovedOrResized(RenderWindow& win)
 	{
 	{
-		for(auto& widget : mWidgets)
+		for(auto& widgetInfo : mWidgets)
 		{
 		{
+			GUIWidget* widget = widgetInfo.widget;
 			if(widget->getOwnerWindow() == &win)
 			if(widget->getOwnerWindow() == &win)
 				widget->ownerWindowResized();
 				widget->ownerWindowResized();
 		}
 		}
 	}
 	}
 
 
+	void GUIManager::onGUIElementRemovedFromWidget(GUIWidget* widget, GUIElement* element)
+	{
+		if(mMouseOverElement == element)
+		{
+			mMouseOverElement = nullptr;
+			mMouseOverWidget = nullptr;
+		}
+
+		if(mActiveElement == element)
+		{
+			mActiveElement = nullptr;
+			mActiveWidget = nullptr;
+		}
+
+		if(mKeyboardFocusElement == element)
+		{
+			mKeyboardFocusElement = nullptr;
+			mKeyboardFocusWidget = nullptr;
+		}
+	}
+
+	void GUIManager::onGUIElementAddedToWidget(GUIWidget* widget, GUIElement* element)
+	{
+
+	}
+
 	GUIMouseButton GUIManager::buttonToMouseButton(ButtonCode code) const
 	GUIMouseButton GUIManager::buttonToMouseButton(ButtonCode code) const
 	{
 	{
 		if(code == BC_MOUSE_LEFT)
 		if(code == BC_MOUSE_LEFT)

+ 3 - 0
BansheeEngine/Source/BsGUIToggleGroup.cpp

@@ -30,6 +30,9 @@ namespace BansheeEngine
 
 
 	void GUIToggleGroup::remove(GUIToggle* toggle)
 	void GUIToggleGroup::remove(GUIToggle* toggle)
 	{
 	{
+		auto sharedPtr = mThis.lock(); // Make sure we keep a reference because calling _setToggleGroup(nullptr) 
+		                               // may otherwise clear the last reference and cause us to destruct
+
 		auto iterFind = std::find(begin(mButtons), end(mButtons), toggle);
 		auto iterFind = std::find(begin(mButtons), end(mButtons), toggle);
 		if(iterFind == end(mButtons))
 		if(iterFind == end(mButtons))
 			return;
 			return;

+ 9 - 0
BansheeEngine/Source/BsGUIWidget.cpp

@@ -28,6 +28,9 @@ 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()
@@ -179,6 +182,9 @@ 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)
@@ -192,6 +198,9 @@ 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)

+ 2 - 0
CamelotCore/Include/CmComponent.h

@@ -37,6 +37,8 @@ namespace CamelotFramework
 		virtual ~Component();
 		virtual ~Component();
 
 
 		HSceneObject mParent;
 		HSceneObject mParent;
+	private:
+		Component(const Component& other) { }
 
 
 		/************************************************************************/
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/* 								RTTI		                     		*/

+ 1 - 0
CamelotCore/Source/CmSceneObject.cpp

@@ -65,6 +65,7 @@ namespace CamelotFramework
 
 
 		for(auto iter = mComponents.begin(); iter != mComponents.end(); ++iter)
 		for(auto iter = mComponents.begin(); iter != mComponents.end(); ++iter)
 		{
 		{
+			gSceneManager().notifyComponentRemoved((*iter));
 			(*iter).destroy();
 			(*iter).destroy();
 		}
 		}
 
 

+ 0 - 1
EditorWindowDock.txt

@@ -57,7 +57,6 @@ Implementation plan:
  - Continue with DockManager (flesh it out later)
  - Continue with DockManager (flesh it out later)
 
 
  GUIManager holds a ptr to GUIElements, and when elements are destroyed, GUIManager holds an invalid ptr
  GUIManager holds a ptr to GUIElements, and when elements are destroyed, GUIManager holds an invalid ptr
-Tabs need toggle groups
 Hook up DbgEditorWidget1::close()
 Hook up DbgEditorWidget1::close()
  - In EditorWidget instead of having a onClose callback, instead keep EditorWidgetContainer parent and then notify it before it is closed. And if the widget is closed by parent container, 
  - In EditorWidget instead of having a onClose callback, instead keep EditorWidgetContainer parent and then notify it before it is closed. And if the widget is closed by parent container, 
    then the container can remove parent and then close it so it doesn't receive the callback.
    then the container can remove parent and then close it so it doesn't receive the callback.