Pārlūkot izejas kodu

Editor windows get properly released on application exit
Making sure that editor window/widget/container gets released as user closes the widget

Marko Pintera 12 gadi atpakaļ
vecāks
revīzija
746c64ab6c

+ 1 - 0
BansheeEngine/Source/BsGUILayout.cpp

@@ -45,6 +45,7 @@ namespace BansheeEngine
 			if(child->_getType() == GUIElementBase::Type::Element && child == element)
 			if(child->_getType() == GUIElementBase::Type::Element && child == element)
 			{
 			{
 				mChildren.erase(iter);
 				mChildren.erase(iter);
+				element->_setParent(nullptr);
 				foundElem = true;
 				foundElem = true;
 				
 				
 				markContentAsDirty();
 				markContentAsDirty();

+ 21 - 0
CamelotClient/CamelotClient.cpp

@@ -24,6 +24,7 @@
 #include "CmCommandQueue.h"
 #include "CmCommandQueue.h"
 #include "CmBlendState.h"
 #include "CmBlendState.h"
 
 
+#include "BsEditorWindowManager.h"
 #include "CmDebugCamera.h"
 #include "CmDebugCamera.h"
 #include "CmTestTextSprite.h"
 #include "CmTestTextSprite.h"
 #include "DbgEditorWidget1.h"
 #include "DbgEditorWidget1.h"
@@ -284,10 +285,30 @@ int CALLBACK WinMain(
 
 
 	dbgCursor.reset();
 	dbgCursor.reset();
 
 
+	/************************************************************************/
+	/* 								EDITOR INIT                      		*/
+	/************************************************************************/
+
+	EditorWindowManager::startUp(cm_new<EditorWindowManager>());
+
+	/************************************************************************/
+	/* 							  EDITOR INIT END                    		*/
+	/************************************************************************/
+
 	DbgEditorWidget1::open();
 	DbgEditorWidget1::open();
 
 
 	gBansheeApp().runMainLoop();
 	gBansheeApp().runMainLoop();
 
 
+	/************************************************************************/
+	/* 							EDITOR SHUTDOWN                      		*/
+	/************************************************************************/
+
+	EditorWindowManager::shutDown();
+
+	/************************************************************************/
+	/* 							EDITOR SHUTDOWN END                    		*/
+	/************************************************************************/
+
 	//testMaterial->destroy();
 	//testMaterial->destroy();
 #ifdef DX11
 #ifdef DX11
 	gpuProgInclude.reset();
 	gpuProgInclude.reset();

+ 2 - 0
CamelotClient/CamelotClient.vcxproj

@@ -262,6 +262,7 @@
     <ClInclude Include="Include\BsEditorWidgetContainer.h" />
     <ClInclude Include="Include\BsEditorWidgetContainer.h" />
     <ClInclude Include="Include\BsEditorWindow.h" />
     <ClInclude Include="Include\BsEditorWindow.h" />
     <ClInclude Include="Include\BsEditorWindowBase.h" />
     <ClInclude Include="Include\BsEditorWindowBase.h" />
+    <ClInclude Include="Include\BsEditorWindowManager.h" />
     <ClInclude Include="Include\BsGUITabbedTitleBar.h" />
     <ClInclude Include="Include\BsGUITabbedTitleBar.h" />
     <ClInclude Include="Include\BsGUIWindowFrameWidget.h" />
     <ClInclude Include="Include\BsGUIWindowFrameWidget.h" />
     <ClInclude Include="Include\DbgEditorWidget1.h" />
     <ClInclude Include="Include\DbgEditorWidget1.h" />
@@ -277,6 +278,7 @@
     <ClCompile Include="Source\BsEditorWidgetContainer.cpp" />
     <ClCompile Include="Source\BsEditorWidgetContainer.cpp" />
     <ClCompile Include="Source\BsEditorWindow.cpp" />
     <ClCompile Include="Source\BsEditorWindow.cpp" />
     <ClCompile Include="Source\BsEditorWindowBase.cpp" />
     <ClCompile Include="Source\BsEditorWindowBase.cpp" />
+    <ClCompile Include="Source\BsEditorWindowManager.cpp" />
     <ClCompile Include="Source\BsGUITabbedTitleBar.cpp" />
     <ClCompile Include="Source\BsGUITabbedTitleBar.cpp" />
     <ClCompile Include="Source\BsGUIWindowFrameWidget.cpp" />
     <ClCompile Include="Source\BsGUIWindowFrameWidget.cpp" />
     <ClCompile Include="Source\DbgEditorWidget1.cpp" />
     <ClCompile Include="Source\DbgEditorWidget1.cpp" />

+ 6 - 0
CamelotClient/CamelotClient.vcxproj.filters

@@ -63,6 +63,9 @@
     <ClInclude Include="Include\BsEditorPrerequisites.h">
     <ClInclude Include="Include\BsEditorPrerequisites.h">
       <Filter>Header Files\Editor</Filter>
       <Filter>Header Files\Editor</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsEditorWindowManager.h">
+      <Filter>Header Files\Editor</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="stdafx.cpp">
     <ClCompile Include="stdafx.cpp">
@@ -101,5 +104,8 @@
     <ClCompile Include="Source\BsEditorWidget.cpp">
     <ClCompile Include="Source\BsEditorWidget.cpp">
       <Filter>Source Files\Editor</Filter>
       <Filter>Source Files\Editor</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsEditorWindowManager.cpp">
+      <Filter>Source Files\Editor</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 1 - 0
CamelotClient/Include/BsEditorPrerequisites.h

@@ -10,4 +10,5 @@ namespace BansheeEditor
 	class EditorWidget;
 	class EditorWidget;
 	class EditorWidgetContainer;
 	class EditorWidgetContainer;
 	class GUITabbedTitleBar;
 	class GUITabbedTitleBar;
+	class EditorWindowManager;
 }
 }

+ 2 - 0
CamelotClient/Include/BsEditorWidget.h

@@ -18,6 +18,8 @@ namespace BansheeEditor
 		void _disable();
 		void _disable();
 		void _enable();
 		void _enable();
 
 
+		static void destroy(EditorWidget* widget);
+
 	protected:
 	protected:
 		EditorWidget(const CM::WString& name);
 		EditorWidget(const CM::WString& name);
 
 

+ 7 - 0
CamelotClient/Include/BsEditorWidgetContainer.h

@@ -1,6 +1,7 @@
 #pragma once
 #pragma once
 
 
 #include "BsEditorPrerequisites.h"
 #include "BsEditorPrerequisites.h"
+#include <boost/signal.hpp>
 
 
 namespace BansheeEditor
 namespace BansheeEditor
 {
 {
@@ -16,6 +17,10 @@ namespace BansheeEditor
 
 
 		void setSize(CM::UINT32 width, CM::UINT32 height);
 		void setSize(CM::UINT32 width, CM::UINT32 height);
 		void setPosition(CM::INT32 x, CM::INT32 y);
 		void setPosition(CM::INT32 x, CM::INT32 y);
+
+		CM::UINT32 getNumWidgets() const { return (CM::UINT32)mWidgets.size(); }
+
+		boost::signal<void()> onWidgetClosed;
 	private:
 	private:
 		GUITabbedTitleBar* mTitleBar;
 		GUITabbedTitleBar* mTitleBar;
 		BS::GUIWidget* mParent;
 		BS::GUIWidget* mParent;
@@ -27,5 +32,7 @@ namespace BansheeEditor
 		static const CM::UINT32 TitleBarHeight;
 		static const CM::UINT32 TitleBarHeight;
 
 
 		void setActiveWidget(CM::UINT32 idx);
 		void setActiveWidget(CM::UINT32 idx);
+		void tabActivated(CM::UINT32 idx);
+		void tabClosed(CM::UINT32 idx);
 	};
 	};
 }
 }

+ 4 - 1
CamelotClient/Include/BsEditorWindow.h

@@ -12,13 +12,16 @@ namespace BansheeEditor
 
 
 		EditorWidgetContainer& getWidgets() const { return *mWidgets; }
 		EditorWidgetContainer& getWidgets() const { return *mWidgets; }
 
 
-		static EditorWindow& create();
+		static EditorWindow* create();
 
 
 	protected:
 	protected:
+		friend class EditorWindowManager;
 		EditorWindow();
 		EditorWindow();
 
 
 		virtual void movedOrResized();
 		virtual void movedOrResized();
 	private:
 	private:
 		EditorWidgetContainer* mWidgets;
 		EditorWidgetContainer* mWidgets;
+
+		void widgetRemoved();
 	};
 	};
 }
 }

+ 2 - 0
CamelotClient/Include/BsEditorWindowBase.h

@@ -17,6 +17,8 @@ namespace BansheeEditor
 
 
 		CM::UINT32 getWidth() const;
 		CM::UINT32 getWidth() const;
 		CM::UINT32 getHeight() const;
 		CM::UINT32 getHeight() const;
+
+		virtual void close();
 	protected:
 	protected:
 		EditorWindowBase();
 		EditorWindowBase();
 		BS::HGUIWidget mGUI;
 		BS::HGUIWidget mGUI;

+ 20 - 0
CamelotClient/Include/BsEditorWindowManager.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "CmModule.h"
+#include <boost/signals.hpp>
+
+namespace BansheeEditor
+{
+	class EditorWindowManager : public CM::Module<EditorWindowManager>
+	{
+	public:
+		~EditorWindowManager();
+
+		EditorWindow* create();
+		void destroy(EditorWindowBase* window);
+
+	protected:
+		CM::Vector<EditorWindowBase*>::type mEditorWindows;
+	};
+}

+ 19 - 3
CamelotClient/Include/BsGUITabbedTitleBar.h

@@ -7,6 +7,16 @@ namespace BansheeEditor
 {
 {
 	class GUITabbedTitleBar
 	class GUITabbedTitleBar
 	{
 	{
+		struct Tab
+		{
+			Tab(BS::GUIToggle* _toggle, CM::UINT32 _index)
+				:toggle(_toggle), index(_index)
+			{ }
+
+			BS::GUIToggle* toggle;
+			CM::UINT32 index;
+		};
+
 	public:
 	public:
 		GUITabbedTitleBar(BS::GUIWidget* parent);
 		GUITabbedTitleBar(BS::GUIWidget* parent);
 		virtual ~GUITabbedTitleBar();
 		virtual ~GUITabbedTitleBar();
@@ -19,12 +29,13 @@ namespace BansheeEditor
 		void removeTab(CM::UINT32 idx);
 		void removeTab(CM::UINT32 idx);
 
 
 		boost::signal<void(CM::UINT32)> onTabActivated;
 		boost::signal<void(CM::UINT32)> onTabActivated;
-		boost::signal<void(CM::UINT32)> onTabAdded;
-		boost::signal<void(CM::UINT32)> onTabRemoved;
+		boost::signal<void(CM::UINT32)> onTabClosed;
 	protected:
 	protected:
 		CM::Vector<BS::GUIWindowMover*>::type mDragDropElements;
 		CM::Vector<BS::GUIWindowMover*>::type mDragDropElements;
-		CM::Vector<BS::GUIToggle*>::type mTabButtons;
+		CM::Vector<Tab>::type mTabButtons;
 
 
+		CM::UINT32 mUniqueTabIdx;
+		CM::UINT32 mActiveTabIdx;
 		BS::GUIWidget* mParentWidget;
 		BS::GUIWidget* mParentWidget;
 		BS::GUIArea* mMainArea;
 		BS::GUIArea* mMainArea;
 		BS::GUIArea* mBackgroundArea;
 		BS::GUIArea* mBackgroundArea;
@@ -32,5 +43,10 @@ namespace BansheeEditor
 		BS::GUIButton* mMinBtn;
 		BS::GUIButton* mMinBtn;
 		BS::GUIButton* mCloseBtn;
 		BS::GUIButton* mCloseBtn;
 		BS::GUIWindowMover* mLastDropElement;
 		BS::GUIWindowMover* mLastDropElement;
+
+		void tabToggled(CM::UINT32 tabIdx);
+		void tabClosed();
+
+		CM::INT32 uniqueIdxToIdx(CM::UINT32 uniqueIdx) const;
 	};
 	};
 }
 }

+ 3 - 3
CamelotClient/Include/DbgEditorWidget1.h

@@ -10,8 +10,8 @@ namespace BansheeEditor
 	public:
 	public:
 		virtual ~DbgEditorWidget1();
 		virtual ~DbgEditorWidget1();
 
 
-		static std::shared_ptr<DbgEditorWidget1> instance();
-		static std::shared_ptr<DbgEditorWidget1> open();
+		static DbgEditorWidget1* instance();
+		static DbgEditorWidget1* open();
 		static void close();
 		static void close();
 
 
 	protected:
 	protected:
@@ -19,6 +19,6 @@ namespace BansheeEditor
 
 
 		void initialize();
 		void initialize();
 	private:
 	private:
-		static std::shared_ptr<DbgEditorWidget1> Instance;
+		static DbgEditorWidget1* Instance;
 	};
 	};
 }
 }

+ 5 - 0
CamelotClient/Source/BsEditorWidget.cpp

@@ -23,6 +23,11 @@ namespace BansheeEditor
 
 
 	}
 	}
 
 
+	void EditorWidget::destroy(EditorWidget* widget)
+	{
+		cm_delete(widget);
+	}
+
 	void EditorWidget::_setPosition(INT32 x, INT32 y)
 	void EditorWidget::_setPosition(INT32 x, INT32 y)
 	{
 	{
 		if(mContent == nullptr)
 		if(mContent == nullptr)

+ 22 - 4
CamelotClient/Source/BsEditorWidgetContainer.cpp

@@ -13,11 +13,18 @@ namespace BansheeEditor
 		:mParent(parent), mX(0), mY(0), mWidth(0), mHeight(0), mTitleBar(nullptr), mActiveWidget(-1)
 		:mParent(parent), mX(0), mY(0), mWidth(0), mHeight(0), mTitleBar(nullptr), mActiveWidget(-1)
 	{
 	{
 		mTitleBar = cm_new<GUITabbedTitleBar>(parent);
 		mTitleBar = cm_new<GUITabbedTitleBar>(parent);
+		mTitleBar->onTabActivated.connect(boost::bind(&EditorWidgetContainer::tabActivated, this, _1));
+		mTitleBar->onTabClosed.connect(boost::bind(&EditorWidgetContainer::tabClosed, this, _1));
 	}
 	}
 
 
 	EditorWidgetContainer::~EditorWidgetContainer()
 	EditorWidgetContainer::~EditorWidgetContainer()
 	{
 	{
 		cm_delete(mTitleBar);
 		cm_delete(mTitleBar);
+
+		for(auto& widget : mWidgets)
+		{
+			EditorWidget::destroy(widget);
+		}
 	}
 	}
 
 
 	void EditorWidgetContainer::add(EditorWidget& widget)
 	void EditorWidgetContainer::add(EditorWidget& widget)
@@ -66,10 +73,6 @@ namespace BansheeEditor
 			{
 			{
 				setActiveWidget(0);
 				setActiveWidget(0);
 			}
 			}
-			else
-			{
-				// TODO - Container is empty, send a signal to the parent EditorWindow and/or DockManager
-			}
 		}
 		}
 	}
 	}
 
 
@@ -131,4 +134,19 @@ namespace BansheeEditor
 		setPosition(mX, mY);
 		setPosition(mX, mY);
 		setSize(mWidth, mHeight);
 		setSize(mWidth, mHeight);
 	}
 	}
+
+	void EditorWidgetContainer::tabActivated(UINT32 idx)
+	{
+		setActiveWidget(idx);
+	}
+
+	void EditorWidgetContainer::tabClosed(UINT32 idx)
+	{
+		EditorWidget* widget = mWidgets[idx];
+		remove(*widget);
+		EditorWidget::destroy(widget);
+
+		if(!onWidgetClosed.empty())
+			onWidgetClosed();
+	}
 }
 }

+ 9 - 5
CamelotClient/Source/BsEditorWindow.cpp

@@ -1,5 +1,6 @@
 #include "BsEditorWindow.h"
 #include "BsEditorWindow.h"
 #include "BsEditorWidgetContainer.h"
 #include "BsEditorWidgetContainer.h"
+#include "BsEditorWindowManager.h"
 
 
 using namespace CamelotFramework;
 using namespace CamelotFramework;
 using namespace BansheeEngine;
 using namespace BansheeEngine;
@@ -9,7 +10,7 @@ namespace BansheeEditor
 	EditorWindow::EditorWindow()
 	EditorWindow::EditorWindow()
 		:mWidgets(cm_new<EditorWidgetContainer>(mGUI.get()))
 		:mWidgets(cm_new<EditorWidgetContainer>(mGUI.get()))
 	{
 	{
-		
+		mWidgets->onWidgetClosed.connect(boost::bind(&EditorWindow::widgetRemoved, this));
 	}
 	}
 
 
 	EditorWindow::~EditorWindow()
 	EditorWindow::~EditorWindow()
@@ -29,11 +30,14 @@ namespace BansheeEditor
 		mWidgets->setSize(widgetWidth, widgetHeight);
 		mWidgets->setSize(widgetWidth, widgetHeight);
 	}
 	}
 
 
-	EditorWindow& EditorWindow::create()
+	void EditorWindow::widgetRemoved()
 	{
 	{
-		EditorWindow* newWindow = new (cm_alloc<EditorWindow>()) EditorWindow();
-		newWindow->initialize();
+		if(mWidgets->getNumWidgets() == 0)
+			close();
+	}
 
 
-		return *newWindow;
+	EditorWindow* EditorWindow::create()
+	{
+		return EditorWindowManager::instance().create();
 	}
 	}
 }
 }

+ 8 - 0
CamelotClient/Source/BsEditorWindowBase.cpp

@@ -4,6 +4,8 @@
 #include "CmRenderWindow.h"
 #include "CmRenderWindow.h"
 #include "CmRenderWindowManager.h"
 #include "CmRenderWindowManager.h"
 
 
+
+#include "BsEditorWindowManager.h"
 #include "BsCamera.h"
 #include "BsCamera.h"
 #include "BsGUIWindowFrameWidget.h"
 #include "BsGUIWindowFrameWidget.h"
 #include "BsEngineGUI.h"
 #include "BsEngineGUI.h"
@@ -50,6 +52,7 @@ namespace BansheeEditor
 	EditorWindowBase::~EditorWindowBase()
 	EditorWindowBase::~EditorWindowBase()
 	{
 	{
 		mRenderWindow->destroy();
 		mRenderWindow->destroy();
+		mSceneObject->destroy();
 	}
 	}
 
 
 	void EditorWindowBase::initialize()
 	void EditorWindowBase::initialize()
@@ -58,6 +61,11 @@ namespace BansheeEditor
 		setSize(200, 200);
 		setSize(200, 200);
 	}
 	}
 
 
+	void EditorWindowBase::close()
+	{
+		EditorWindowManager::instance().destroy(this);
+	}
+
 	void EditorWindowBase::movedOrResized(RenderWindow& renderWindow)
 	void EditorWindowBase::movedOrResized(RenderWindow& renderWindow)
 	{
 	{
 		if(&renderWindow == mRenderWindow.get())
 		if(&renderWindow == mRenderWindow.get())

+ 34 - 0
CamelotClient/Source/BsEditorWindowManager.cpp

@@ -0,0 +1,34 @@
+#include "BsEditorWindowManager.h"
+#include "BsEditorWindow.h"
+
+using namespace CamelotFramework;
+using namespace BansheeEngine;
+
+namespace BansheeEditor
+{
+	EditorWindowManager::~EditorWindowManager()
+	{
+		while(mEditorWindows.size() > 0)
+			destroy(mEditorWindows[0]);
+	}
+
+	EditorWindow* EditorWindowManager::create()
+	{
+		EditorWindow* newWindow = new (cm_alloc<EditorWindow>()) EditorWindow();
+		mEditorWindows.push_back(newWindow);
+
+		newWindow->initialize();
+		return newWindow;
+	}
+
+	void EditorWindowManager::destroy(EditorWindowBase* window)
+	{
+		auto iterFind = std::find(begin(mEditorWindows), end(mEditorWindows), window);
+
+		if(iterFind == end(mEditorWindows))
+			CM_EXCEPT(InternalErrorException, "Trying to destroy an editor window that's not registered in the window manager.");
+
+		mEditorWindows.erase(iterFind);
+		cm_delete(window);
+	}
+}

+ 67 - 5
CamelotClient/Source/BsGUITabbedTitleBar.cpp

@@ -17,7 +17,7 @@ namespace BansheeEditor
 {
 {
 	GUITabbedTitleBar::GUITabbedTitleBar(BS::GUIWidget* parent)
 	GUITabbedTitleBar::GUITabbedTitleBar(BS::GUIWidget* parent)
 		:mLastDropElement(nullptr), mMinBtn(nullptr), mCloseBtn(nullptr), 
 		:mLastDropElement(nullptr), mMinBtn(nullptr), mCloseBtn(nullptr), 
-		mMainArea(nullptr), mMainLayout(nullptr), mParentWidget(parent), mBackgroundArea(nullptr)
+		mMainArea(nullptr), mMainLayout(nullptr), mParentWidget(parent), mBackgroundArea(nullptr), mUniqueTabIdx(0), mActiveTabIdx(0)
 	{
 	{
 		mBackgroundArea = GUIArea::create(*parent, 0, 0, 1, 13, 9900);
 		mBackgroundArea = GUIArea::create(*parent, 0, 0, 1, 13, 9900);
 		GUIWindowMover* titleBarBg = GUIWindowMover::create(*parent, parent->getSkin()->getStyle("TitleBarBackground"));
 		GUIWindowMover* titleBarBg = GUIWindowMover::create(*parent, parent->getSkin()->getStyle("TitleBarBackground"));
@@ -33,6 +33,8 @@ namespace BansheeEditor
 		mMinBtn = GUIButton::create(*parent, L"", parent->getSkin()->getStyle("WinMinimizeBtn"));
 		mMinBtn = GUIButton::create(*parent, L"", parent->getSkin()->getStyle("WinMinimizeBtn"));
 		mCloseBtn = GUIButton::create(*parent, L"", parent->getSkin()->getStyle("WinCloseBtn"));
 		mCloseBtn = GUIButton::create(*parent, L"", parent->getSkin()->getStyle("WinCloseBtn"));
 
 
+		mCloseBtn->onClick.connect(boost::bind(&GUITabbedTitleBar::tabClosed, this));
+
 		mMainArea->getLayout().addSpace(1);
 		mMainArea->getLayout().addSpace(1);
 		mMainLayout = &mMainArea->getLayout().addLayoutX();
 		mMainLayout = &mMainArea->getLayout().addLayoutX();
 		mMainLayout->addElement(dragDropElement);
 		mMainLayout->addElement(dragDropElement);
@@ -44,7 +46,22 @@ namespace BansheeEditor
 
 
 	GUITabbedTitleBar::~GUITabbedTitleBar()
 	GUITabbedTitleBar::~GUITabbedTitleBar()
 	{
 	{
-		// TODO - Clean up buttons, layouts, areas
+		GUIArea::destroy(mMainArea);
+		GUIArea::destroy(mBackgroundArea);
+
+		GUIElement::destroy(mLastDropElement);
+		GUIElement::destroy(mMinBtn);
+		GUIElement::destroy(mCloseBtn);
+
+		for(auto& tabButton : mTabButtons)
+		{
+			GUIElement::destroy(tabButton.toggle);
+		}
+
+		for(auto& dragDropButton : mDragDropElements)
+		{
+			GUIElement::destroy(dragDropButton);
+		}
 	}
 	}
 
 
 	void GUITabbedTitleBar::addTab(const CM::WString& name)
 	void GUITabbedTitleBar::addTab(const CM::WString& name)
@@ -59,11 +76,15 @@ namespace BansheeEditor
 
 
 		idx = Math::Clamp(idx, 0U, (UINT32)mTabButtons.size());
 		idx = Math::Clamp(idx, 0U, (UINT32)mTabButtons.size());
 
 
-		mTabButtons.insert(mTabButtons.begin() + idx, newTabToggle);
+		newTabToggle->onToggled.connect(boost::bind(&GUITabbedTitleBar::tabToggled, this, mUniqueTabIdx));
+
+		mTabButtons.insert(mTabButtons.begin() + idx, Tab(newTabToggle, mUniqueTabIdx));
 		mDragDropElements.insert(mDragDropElements.begin() + idx, newDragDropElement);
 		mDragDropElements.insert(mDragDropElements.begin() + idx, newDragDropElement);
 
 
 		mMainLayout->insertElement(idx * 2, newTabToggle);
 		mMainLayout->insertElement(idx * 2, newTabToggle);
 		mMainLayout->insertElement(idx * 2, newDragDropElement);
 		mMainLayout->insertElement(idx * 2, newDragDropElement);
+
+		mUniqueTabIdx++;
 	}
 	}
 
 
 	void GUITabbedTitleBar::removeTab(UINT32 idx)
 	void GUITabbedTitleBar::removeTab(UINT32 idx)
@@ -73,8 +94,8 @@ namespace BansheeEditor
 
 
 		idx = Math::Clamp(idx, 0U, (UINT32)mTabButtons.size() - 1);
 		idx = Math::Clamp(idx, 0U, (UINT32)mTabButtons.size() - 1);
 
 
-		mMainLayout->removeElement(mTabButtons[idx]);
-		mMainLayout->removeElement(mDragDropElements[idx]);
+		GUIElement::destroy(mTabButtons[idx].toggle);
+		GUIElement::destroy(mDragDropElements[idx]);
 
 
 		mTabButtons.erase(mTabButtons.begin() + idx);
 		mTabButtons.erase(mTabButtons.begin() + idx);
 		mDragDropElements.erase(mDragDropElements.begin() + idx);
 		mDragDropElements.erase(mDragDropElements.begin() + idx);
@@ -91,4 +112,45 @@ namespace BansheeEditor
 		mMainArea->setSize(width, height);
 		mMainArea->setSize(width, height);
 		mBackgroundArea->setSize(width, height);
 		mBackgroundArea->setSize(width, height);
 	}
 	}
+
+	void GUITabbedTitleBar::tabToggled(CM::UINT32 tabIdx)
+	{
+		INT32 idx = uniqueIdxToIdx(tabIdx);
+		if(idx != -1)
+		{
+			if(!onTabActivated.empty())
+				onTabActivated(idx);
+		}
+
+		mActiveTabIdx = tabIdx;
+	}
+
+	void GUITabbedTitleBar::tabClosed()
+	{
+		INT32 idx = uniqueIdxToIdx(mActiveTabIdx);
+		if(idx != -1)
+		{
+			removeTab(idx);
+
+			if(mTabButtons.size() > 0)
+				mActiveTabIdx = mTabButtons[0].index;
+
+			if(!onTabClosed.empty())
+				onTabClosed(idx);
+		}
+	}
+
+	CM::INT32 GUITabbedTitleBar::uniqueIdxToIdx(CM::UINT32 uniqueIdx) const
+	{
+		UINT32 idx = 0;
+		for(auto& tab : mTabButtons)
+		{
+			if(tab.index == uniqueIdx)
+				return idx;
+
+			idx++;
+		}
+
+		return -1;
+	}
 }
 }

+ 6 - 6
CamelotClient/Source/DbgEditorWidget1.cpp

@@ -14,7 +14,7 @@ using namespace BansheeEngine;
 
 
 namespace BansheeEditor
 namespace BansheeEditor
 {
 {
-	std::shared_ptr<DbgEditorWidget1> DbgEditorWidget1::Instance;
+	DbgEditorWidget1* DbgEditorWidget1::Instance = nullptr;
 
 
 	DbgEditorWidget1::DbgEditorWidget1()
 	DbgEditorWidget1::DbgEditorWidget1()
 		:EditorWidget(L"DbgEditorWidget1")
 		:EditorWidget(L"DbgEditorWidget1")
@@ -84,20 +84,20 @@ namespace BansheeEditor
 		//mRenderWindow->setVisible(false);
 		//mRenderWindow->setVisible(false);
 	}
 	}
 
 
-	std::shared_ptr<DbgEditorWidget1> DbgEditorWidget1::instance()
+	DbgEditorWidget1* DbgEditorWidget1::instance()
 	{
 	{
 		return Instance;
 		return Instance;
 	}
 	}
 
 
-	std::shared_ptr<DbgEditorWidget1> DbgEditorWidget1::open()
+	DbgEditorWidget1* DbgEditorWidget1::open()
 	{
 	{
 		if(Instance != nullptr)
 		if(Instance != nullptr)
 			return Instance;
 			return Instance;
 
 
-		EditorWindow& newWindow = EditorWindow::create();
+		EditorWindow* newWindow = EditorWindow::create();
 
 
-		std::shared_ptr<DbgEditorWidget1> newWidget = std::shared_ptr<DbgEditorWidget1>(new (cm_alloc<DbgEditorWidget1>()) DbgEditorWidget1());
-		newWindow.getWidgets().add(*newWidget);
+		DbgEditorWidget1* newWidget = new (cm_alloc<DbgEditorWidget1>()) DbgEditorWidget1();
+		newWindow->getWidgets().add(*newWidget);
 		newWidget->initialize();
 		newWidget->initialize();
 		Instance = newWidget;
 		Instance = newWidget;
 
 

+ 4 - 14
EditorWindowDock.txt

@@ -56,21 +56,11 @@ Implementation plan:
    - Will require implementing most of the DragAndDropManager and improve GUIManager
    - Will require implementing most of the DragAndDropManager and improve GUIManager
  - Continue with DockManager (flesh it out later)
  - Continue with DockManager (flesh it out later)
 
 
- TODO - I don't release EditorWindow or EditorWidget anywhere!!!
-
- Things that need cleanup:
-  All elements contained in GUITabbedTitleBar
-  EditorWidget when its closed
-  EditorWidgetContainer when last widget is removed
-  EditorWindow when last widget is removed
-
+ GUIManager holds a ptr to GUIElements, and when elements are destroyed, GUIManager holds an invalid ptr
 Shutdown of the game should destroy all EditorWindows (and all their children)
 Shutdown of the game should destroy all EditorWindows (and all their children)
-
-A way to disable/enable EditorWidgets so I can switch tabs in EditorWidgetContainer
- - Also hook up the toggle buttons
-A way to move EditorWidget child GUIArea and GUIElements to another widget
-Notify parent EditorWindow or Dockmanager when last element is removed from EditorWidgetContainer (probably just a callback)
- - Also hook up the X button on the tabbed title bar so it closes the widget
+Tabs need toggle groups
+Hook up DbgEditorWidget1::close()
+Test tab switch/tab close/window close
 
 
 ------------------------
 ------------------------