Explorar o código

Initial work on the dock manager

Marko Pintera %!s(int64=12) %!d(string=hai) anos
pai
achega
ad49ed2913

+ 4 - 0
CamelotClient/CamelotClient.cpp

@@ -24,7 +24,11 @@
 #include "CmCommandQueue.h"
 #include "CmBlendState.h"
 
+// Editor includes
 #include "BsEditorWindowManager.h"
+// End editor includes
+
+
 #include "CmDebugCamera.h"
 #include "CmTestTextSprite.h"
 #include "DbgEditorWidget1.h"

+ 2 - 0
CamelotClient/CamelotClient.vcxproj

@@ -257,6 +257,7 @@
   <ItemGroup>
     <ClInclude Include="CmDebugCamera.h" />
     <ClInclude Include="CmTestTextSprite.h" />
+    <ClInclude Include="Include\BsDockManager.h" />
     <ClInclude Include="Include\BsEditorPrerequisites.h" />
     <ClInclude Include="Include\BsEditorWidget.h" />
     <ClInclude Include="Include\BsEditorWidgetContainer.h" />
@@ -274,6 +275,7 @@
     <ClCompile Include="CamelotClient.cpp" />
     <ClCompile Include="CmDebugCamera.cpp" />
     <ClCompile Include="CmTestTextSprite.cpp" />
+    <ClCompile Include="Source\BsDockManager.cpp" />
     <ClCompile Include="Source\BsEditorWidget.cpp" />
     <ClCompile Include="Source\BsEditorWidgetContainer.cpp" />
     <ClCompile Include="Source\BsEditorWindow.cpp" />

+ 6 - 0
CamelotClient/CamelotClient.vcxproj.filters

@@ -66,6 +66,9 @@
     <ClInclude Include="Include\BsEditorWindowManager.h">
       <Filter>Header Files\Editor</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsDockManager.h">
+      <Filter>Header Files\Editor</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="stdafx.cpp">
@@ -107,5 +110,8 @@
     <ClCompile Include="Source\BsEditorWindowManager.cpp">
       <Filter>Source Files\Editor</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsDockManager.cpp">
+      <Filter>Source Files\Editor</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 54 - 0
CamelotClient/Include/BsDockManager.h

@@ -0,0 +1,54 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+
+namespace BansheeEditor
+{
+	enum class DockLocation
+	{
+		Left, Right, Top, Bottom, Center
+	};
+
+	class DockManager
+	{
+		class DockContainer
+		{
+		public:
+			DockContainer();
+			~DockContainer();
+
+			void setArea(CM::INT32 x, CM::INT32 y, CM::UINT32 width, CM::UINT32 height);
+			void makeLeaf(BS::GUIWidget* widgetParent, EditorWidget* widget);
+			void addLeft(BS::GUIWidget* widgetParent, EditorWidget* widget);
+			void addRight(BS::GUIWidget* widgetParent, EditorWidget* widget);
+			void addTop(BS::GUIWidget* widgetParent, EditorWidget* widget);
+			void addBottom(BS::GUIWidget* widgetParent, EditorWidget* widget);
+
+			DockContainer* find(EditorWidgetContainer* widgetContainer);
+
+			bool mIsLeaf;
+			DockContainer* mChildren[2];
+			EditorWidgetContainer* mWidgets;
+			CM::INT32 mX, mY;
+			CM::UINT32 mWidth, mHeight;
+			float mSplitPosition;
+			bool mIsHorizontal;
+
+			static const CM::UINT32 SliderSize;
+
+		private:
+			void splitContainer(BS::GUIWidget* widgetParent, EditorWidget* widget, bool horizontal, bool newChildIsFirst);
+		};
+	public:
+		DockManager(BS::GUIWidget* parent);
+		~DockManager();
+
+		void insert(EditorWidgetContainer* relativeTo, EditorWidget* widgetToInsert, DockLocation location);
+
+		void setSize(CM::UINT32 width, CM::UINT32 height);
+
+	private:
+		BS::GUIWidget* mParent;
+		DockContainer mRootContainer;
+	};
+}

+ 1 - 0
CamelotClient/Include/BsEditorPrerequisites.h

@@ -11,4 +11,5 @@ namespace BansheeEditor
 	class EditorWidgetContainer;
 	class GUITabbedTitleBar;
 	class EditorWindowManager;
+	class DockManager;
 }

+ 199 - 0
CamelotClient/Source/BsDockManager.cpp

@@ -0,0 +1,199 @@
+#include "BsDockManager.h"
+#include "BsEditorWidgetContainer.h"
+#include "CmMath.h"
+#include "CmException.h"
+
+using namespace CamelotFramework;
+using namespace BansheeEngine;
+
+namespace BansheeEditor
+{
+	const CM::UINT32 DockManager::DockContainer::SliderSize = 4;
+
+	DockManager::DockContainer::DockContainer()
+		:mIsLeaf(false), mWidgets(nullptr), mX(0), mY(0), mWidth(0), mHeight(0), mSplitPosition(0.5f),
+		mIsHorizontal(false)
+	{
+		mChildren[0] = nullptr;
+		mChildren[1] = nullptr;
+	}
+
+	DockManager::DockContainer::~DockContainer()
+	{
+		if(mIsLeaf && mWidgets != nullptr)
+			cm_delete(mWidgets);
+
+		if(!mIsLeaf)
+		{
+			if(mChildren[0] != nullptr)
+				cm_delete(mChildren[0]);
+
+			if(mChildren[1] != nullptr)
+				cm_delete(mChildren[1]);
+		}
+
+		// TODO - Clean up slider
+	}
+
+	void DockManager::DockContainer::setArea(CM::INT32 x, CM::INT32 y, UINT32 width, UINT32 height)
+	{
+		mX = x;
+		mY = y;
+		mWidth = width;
+		mHeight = height;
+
+		if(mIsLeaf)
+		{
+			if(mWidgets != nullptr)
+			{
+				mWidgets->setPosition(x, y);
+				mWidgets->setSize(width, height);
+			}
+		}
+		else if(mChildren[0] != nullptr && mChildren[1] != nullptr)
+		{
+			if(mIsHorizontal)
+			{
+				UINT32 remainingSize = (UINT32)std::max(0, (INT32)mHeight - (INT32)SliderSize);
+				UINT32 sizeTop = Math::FloorToInt(remainingSize * mSplitPosition);
+				UINT32 sizeBottom = remainingSize - sizeTop;
+
+				mChildren[0]->setArea(mX, mY, mWidth, sizeTop);
+				mChildren[1]->setArea(mX, mY + sizeTop + SliderSize, mWidth, sizeBottom);
+
+				// TODO - Set slider position
+			}
+			else
+			{
+				UINT32 remainingSize = (UINT32)std::max(0, (INT32)mWidth - (INT32)SliderSize);
+				UINT32 sizeLeft = Math::FloorToInt(remainingSize * mSplitPosition);
+				UINT32 sizeRight = remainingSize - sizeLeft;
+
+				mChildren[0]->setArea(mX, mY, sizeLeft, mHeight);
+				mChildren[1]->setArea(mX + sizeLeft + SliderSize, mY, sizeRight, mHeight);
+
+				// TODO - Set slider position
+			}
+		}
+	}
+
+	void DockManager::DockContainer::makeLeaf(GUIWidget* widgetParent, EditorWidget* widget)
+	{
+		mIsLeaf = true;
+		mWidgets = cm_new<EditorWidgetContainer>(widgetParent);
+
+		mWidgets->add(*widget);
+		mWidgets->setPosition(mX, mY);
+		mWidgets->setSize(mWidth, mHeight);
+	}
+
+	void DockManager::DockContainer::addLeft(BS::GUIWidget* widgetParent, EditorWidget* widget)
+	{
+		splitContainer(widgetParent, widget, false, true);
+	}
+
+	void DockManager::DockContainer::addRight(BS::GUIWidget* widgetParent, EditorWidget* widget)
+	{
+		splitContainer(widgetParent, widget, false, false);
+	}
+
+	void DockManager::DockContainer::addTop(BS::GUIWidget* widgetParent, EditorWidget* widget)
+	{
+		splitContainer(widgetParent, widget, true, true);
+	}
+
+	void DockManager::DockContainer::addBottom(BS::GUIWidget* widgetParent, EditorWidget* widget)
+	{
+		splitContainer(widgetParent, widget, true, false);
+	}
+
+	void DockManager::DockContainer::splitContainer(BS::GUIWidget* widgetParent, EditorWidget* widget, bool horizontal, bool newChildIsFirst)
+	{
+		UINT32 idxA = newChildIsFirst ? 0 : 1;
+		UINT32 idxB = (idxA + 1) % 2;
+
+		mChildren[idxA] = cm_new<DockContainer>();
+		mChildren[idxB] = cm_new<DockContainer>(*this);
+
+		mChildren[idxA]->makeLeaf(widgetParent, widget);
+
+		mIsLeaf = false;
+		mIsHorizontal = horizontal;
+		mWidgets = nullptr;
+		mSplitPosition = 0.5f;
+
+		// TODO - Add slider
+
+		setArea(mX, mY, mWidth, mHeight);
+	}
+
+	DockManager::DockContainer* DockManager::DockContainer::find(EditorWidgetContainer* widgetContainer)
+	{
+		if(mIsLeaf)
+		{
+			if(mWidgets == widgetContainer)
+				return this;
+			else
+				return nullptr;
+		}
+		else
+		{
+			if(mChildren[0] != nullptr && mChildren[0]->find(widgetContainer) != nullptr)
+				return mChildren[0];
+
+			if(mChildren[1] != nullptr && mChildren[1]->find(widgetContainer) != nullptr)
+				return mChildren[1];
+		}
+
+		return nullptr;
+	}
+
+	DockManager::DockManager(BS::GUIWidget* parent)
+		:mParent(parent)
+	{
+
+	}
+
+	DockManager::~DockManager()
+	{
+
+	}
+
+	void DockManager::insert(EditorWidgetContainer* relativeTo, EditorWidget* widgetToInsert, DockLocation location)
+	{
+		if(relativeTo != nullptr)
+		{
+			DockContainer* container = mRootContainer.find(relativeTo);
+			if(container == nullptr)
+				CM_EXCEPT(InternalErrorException, "Cannot find the wanted widget container relative to which the widget should be inserted.");
+
+			switch(location)
+			{
+			case DockLocation::Left:
+				container->addLeft(mParent, widgetToInsert);
+				break;
+			case DockLocation::Right:
+				container->addRight(mParent, widgetToInsert);
+				break;
+			case DockLocation::Top:
+				container->addTop(mParent, widgetToInsert);
+				break;
+			case DockLocation::Bottom:
+				container->addBottom(mParent, widgetToInsert);
+				break;
+			}
+		}
+		else
+		{
+			if(mRootContainer.mWidgets != nullptr)
+				CM_EXCEPT(InternalErrorException, "Trying to insert a widget into dock manager root container but one already exists.");
+
+			mRootContainer.makeLeaf(mParent, widgetToInsert);
+		}
+	}
+
+	void DockManager::setSize(CM::UINT32 width, CM::UINT32 height)
+	{
+		mRootContainer.setArea(0, 0, width, height);
+	}
+}

+ 26 - 19
EditorWindowDock.txt

@@ -1,12 +1,3 @@
-DragAndDropManager
- - Very simple interface
- - dragObject(icon, type, data, dropCallback) - starts item drag (data is just a void user an cast based on type)
- - while something is being dragged GUIManager sends ObjectDragged events to all GUI elements under the mouse
-   - (normally GUIManager only sends MouseDrag to the element that initiated the drag)
- - when mouse button is released GUIManager sends ObjectDropped to the GUIElement under the cursor
- - manager is reponsible for drawing the provided icon while the object is being dragged
- - "dropCallback" is called when the object is dropped. Most useful to determine if the object is dropped in an unsupported area in which case we need to do some special action.
-
 DockManager
  - DOCKING: When user drags a window, EditorWidgetContainer detects that and reacts accordingly
    - For title bar it draws the drop locations, and does the same for content
@@ -23,19 +14,35 @@ DockManager
 
 TODO - Possibly add a way to have hidden widgets in the EditorWidgetContainer (like side-bars that pop on mouse over in Visual Studio)
 TODO - A way to persist window states
+  - Also a way to reset all widgets to original locations
 
 ------------------------
 
-Implementation plan:
- - Split EditorWindow, EditorWidget and EditorWidgetContainer
- - Implement a couple of debug EditorWidgets and set them up in a single container and a window
-  - Hook up the buttons so clicking them switches the active widget
- - Implement basic DragAndDropManager (without special icon yet)
-  - Attemp to drag and drop a single item from and to the title bar
-   - Will require implementing most of the DragAndDropManager and improve GUIManager
- - Continue with DockManager (flesh it out later)
-
-Test tab switch/tab close/window close
+DockManager implementation plan:
+ - DockManager main class
+   - When empty make sure it has a GUIElement that covers its entire space so it can catch and drop events. Will likely need a special transparent GUIElement?
+   - Has a reference to one DockContainer, which is initially empty
+      - DockContainer can have two DockContainer children, or one EditorWidgetContainer child (maybe make a container base class? - optional)
+	  - DockContainer should probably contain a GUIElement which can receieve events
+	     - This would mean extending GUIManager so it can send events to top level elements, and if they don't process them, send them one level lower?
+	  - Resizing a DockContainer resizes all child DockContainers recursively (and EditorWidgetContainers)
+	  - If DockContainer has DockContainer children then it also contains a  GUIElement resizer (just an empty space, in the direction of the split)
+	    - Moving the element allows you to resize the two child DockContainers
+ - When last element is removed from EditorWidgetContainer make sure to notify the parent
+ - Make main render window frameless
+   - Implement MainEditorWindow from EditorWindowBase
+   - Make sure MainEditorWindow holds a DockManager reference and resizes it with the window
+
+DockContainer biggest issues:
+ - How do I draw the drag and drop overlay??
+ - How do I detect mouse input yet still let it through to child widget
+
+FIRST CREATE DOCK CONTAINER WITHOUT DRAG AND DROP SUPPORT
+
+Make sure to test everything thoroughly - right now I have tested very little
+Drag and drop manager currently ignores the provided icon, but it should use it as a cursor
+
+TODO - Prevent docking if available size is less than 20 pixels, otherwise there might be some weirdness
 
 ------------------------