Browse Source

Starting work on GUILayout

Marko Pintera 12 years ago
parent
commit
28f25fa239

+ 7 - 0
BansheeEngine/BansheeEngine.vcxproj

@@ -149,6 +149,11 @@
     <ClInclude Include="Include\BsApplication.h" />
     <ClInclude Include="Include\BsDebugDraw.h" />
     <ClInclude Include="Include\BsEngineGUI.h" />
+    <ClInclude Include="Include\BsGUIArea.h" />
+    <ClInclude Include="Include\BsGUILayoutOptions.h" />
+    <ClInclude Include="Include\BsGUILayoutX.h" />
+    <ClInclude Include="Include\BsGUILayout.h" />
+    <ClInclude Include="Include\BsGUILayoutY.h" />
     <ClInclude Include="Include\BsPrerequisites.h" />
     <ClInclude Include="Include\BsGUIElement.h" />
     <ClInclude Include="Include\BsGUIElementStyle.h" />
@@ -180,8 +185,10 @@
     <ClCompile Include="Source\BsApplication.cpp" />
     <ClCompile Include="Source\BsDebugDraw.cpp" />
     <ClCompile Include="Source\BsEngineGUI.cpp" />
+    <ClCompile Include="Source\BsGUIArea.cpp" />
     <ClCompile Include="Source\BsGUIElement.cpp" />
     <ClCompile Include="Source\BsGUILabel.cpp" />
+    <ClCompile Include="Source\BsGUILayout.cpp" />
     <ClCompile Include="Source\BsGUIManager.cpp" />
     <ClCompile Include="Source\BsGUIMaterialManager.cpp" />
     <ClCompile Include="Source\BsGUISkin.cpp" />

+ 21 - 0
BansheeEngine/BansheeEngine.vcxproj.filters

@@ -123,6 +123,21 @@
     <ClInclude Include="Include\BsDebugDraw.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsGUIArea.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsGUILayout.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsGUILayoutX.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsGUILayoutY.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsGUILayoutOptions.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsGUIElement.cpp">
@@ -197,5 +212,11 @@
     <ClCompile Include="Source\BsDebugDraw.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsGUIArea.cpp">
+      <Filter>Source Files\GUI</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsGUILayout.cpp">
+      <Filter>Source Files\GUI</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 32 - 0
BansheeEngine/Include/BsGUIArea.h

@@ -0,0 +1,32 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+
+namespace BansheeEngine
+{
+	class BS_EXPORT GUIArea
+	{
+	public:
+		/**
+		 * @brief	Sets up a new GUI area. All the layouts used in the area will be placed
+		 * 			within the specified bounds.
+		 * 			
+		 *			If you want the area to expand vertically or horizontally, together with its parent
+		 *			widget, set height or width to 0, respectively.
+		 */
+		GUIArea(const HGUIWidget& widget, UINT32 x, UINT32 y, UINT32 width = 0, UINT32 height = 0);
+		~GUIArea();
+
+		GUILayout* getLayout() const { return mLayout; }
+
+		UINT32 getDepth() const { return mDepth; }
+		void setDepth(UINT32 depth) { mDepth = depth; }
+
+	private:
+		const HGUIWidget& mWidget;
+		UINT32 mX, mY, mWidth, mHeight;
+		UINT32 mDepth;
+
+		GUILayout* mLayout;
+	};
+}

+ 5 - 0
BansheeEngine/Include/BsGUIElement.h

@@ -82,10 +82,15 @@ namespace BansheeEngine
 		//	onKeyReleased
 	protected:
 		friend class GUIWidget;
+		friend class GUILayout;
 
 		virtual ~GUIElement();
 
+		GUILayout* getParentLayout() const { return mParentLayout; }
+		void setParentLayout(GUILayout* layout) { mParentLayout = layout; }
+
 		GUIWidget* mParent;
+		GUILayout* mParentLayout;
 		CM::Rect mBounds;
 		INT32 mDepth;
 		bool mIsDirty;

+ 44 - 0
BansheeEngine/Include/BsGUILayout.h

@@ -0,0 +1,44 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+
+namespace BansheeEngine
+{
+	class BS_EXPORT GUILayout
+	{
+		struct GUILayoutEntry
+		{
+			union
+			{
+				GUIElement* element;
+				GUILayout* layout;
+			};
+
+			bool isLayout;
+		};
+
+	public:
+		GUILayout();
+		virtual ~GUILayout();
+
+		void addElement(GUIElement* element);
+		void removeElement(GUIElement* element);
+		void insertElement(UINT32 idx, GUIElement* element);
+
+		void addLayout(GUILayout* layout);
+		void removeLayout(GUILayout* layout);
+		void insertLayout(UINT32 idx, GUILayout* layout);
+
+		/**
+		 * @brief	Returns a combined number of child elements and layouts.
+		 */
+		UINT32 getNumChildren() const;
+
+	private:
+		std::vector<GUILayoutEntry> mChildren;
+		GUILayout* mParentLayout;
+
+		GUILayout* getParentLayout() const { return mParentLayout; }
+		void setParentLayout(GUILayout* layout) { mParentLayout = layout; }
+	};
+}

+ 27 - 0
BansheeEngine/Include/BsGUILayoutOptions.h

@@ -0,0 +1,27 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+
+namespace BansheeEngine
+{
+	struct GUI_LAYOUT_OPTIONS
+	{
+		GUI_LAYOUT_OPTIONS()
+			:width(0), height(0), minWidth(0), maxWidth(0),
+			minHeight(0), maxHeight(0), expandWidth(true), expandHeight(true)
+		{
+
+		}
+
+		GUI_LAYOUT_OPTIONS(UINT32 _width, UINT32 _height)
+			:width(_width), height(_height), minWidth(0), maxWidth(0),
+			minHeight(0), maxHeight(0), expandWidth(false), expandHeight(false)
+		{
+
+		}
+
+		UINT32 width, height;
+		UINT32 minWidth, maxWidth, minHeight, maxHeight;
+		bool expandWidth, expandHeight;
+	};
+}

+ 14 - 0
BansheeEngine/Include/BsGUILayoutX.h

@@ -0,0 +1,14 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsGUILayout.h"
+
+namespace BansheeEngine
+{
+	class BS_EXPORT GUILayoutX : public GUILayout
+	{
+	public:
+		GUILayoutX() {};
+		~GUILayoutX() {};
+	};
+}

+ 14 - 0
BansheeEngine/Include/BsGUILayoutY.h

@@ -0,0 +1,14 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsGUILayout.h"
+
+namespace BansheeEngine
+{
+	class BS_EXPORT GUILayoutY : public GUILayout
+	{
+	public:
+		GUILayoutY() {};
+		~GUILayoutY() {};
+	};
+}

+ 5 - 0
BansheeEngine/Include/BsPrerequisites.h

@@ -49,6 +49,11 @@ namespace BansheeEngine
 	class GUISkin;
 	struct GUIElementStyle;
 	class GUIMouseEvent;
+	class GUIArea;
+	class GUILayout;
+	class GUILayoutX;
+	class GUILayoutY;
+	class GUI_LAYOUT_OPTIONS;
 
 	// 2D
 	class TextSprite;

+ 18 - 0
BansheeEngine/Source/BsGUIArea.cpp

@@ -0,0 +1,18 @@
+#include "BsGUIArea.h"
+#include "BsGUILayoutX.h"
+
+using namespace CamelotFramework;
+
+namespace BansheeEngine
+{
+	GUIArea::GUIArea(const HGUIWidget& widget, UINT32 x, UINT32 y, UINT32 width, UINT32 height)
+		:mWidget(widget), mX(x), mY(y), mWidth(width), mHeight(height), mDepth(0)
+	{
+		mLayout = new GUILayoutX();
+	}
+
+	GUIArea::~GUIArea() 
+	{
+
+	}
+}

+ 1 - 1
BansheeEngine/Source/BsGUIElement.cpp

@@ -8,7 +8,7 @@ using namespace CamelotFramework;
 namespace BansheeEngine
 {
 	GUIElement::GUIElement(GUIWidget* parent)
-		:mParent(parent), mIsDirty(true)
+		:mParent(parent), mIsDirty(true), mParentLayout(nullptr)
 	{
 		if(parent == nullptr)
 			CM_EXCEPT(InvalidParametersException, "Cannot create GUI element without providing a parent!");

+ 120 - 0
BansheeEngine/Source/BsGUILayout.cpp

@@ -0,0 +1,120 @@
+#include "BsGUILayout.h"
+#include "BsGUIElement.h"
+#include "CmException.h"
+
+using namespace CamelotFramework;
+
+namespace BansheeEngine
+{
+	GUILayout::GUILayout()
+		:mParentLayout(nullptr)
+	{
+
+	}
+
+	GUILayout::~GUILayout() 
+	{
+
+	}
+
+	void GUILayout::addElement(GUIElement* element)
+	{
+		if(element->getParentLayout() != nullptr)
+			element->getParentLayout()->removeElement(element);
+
+		GUILayoutEntry entry;
+		entry.element = element;
+		entry.isLayout = false;
+
+		element->setParentLayout(this);
+		mChildren.push_back(entry);
+	}
+
+	void GUILayout::removeElement(GUIElement* element)
+	{
+		bool foundElem = false;
+		for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
+		{
+			GUILayoutEntry& child = *iter;
+
+			if(!child.isLayout && child.element == element)
+			{
+				mChildren.erase(iter);
+				foundElem = true;
+				break;
+			}
+		}
+
+		if(!foundElem)
+			CM_EXCEPT(InvalidParametersException, "Provided element is not a part of this layout.");
+	}
+
+	void GUILayout::insertElement(UINT32 idx, GUIElement* element)
+	{
+		if(idx < 0 || idx >= (UINT32)mChildren.size())
+			CM_EXCEPT(InvalidParametersException, "Index out of range: " + toString(idx) + ". Valid range: 0 .. " + toString((UINT32)mChildren.size()));
+
+		if(element->getParentLayout() != nullptr)
+			element->getParentLayout()->removeElement(element);
+
+		GUILayoutEntry entry;
+		entry.element = element;
+		entry.isLayout = false;
+
+		element->setParentLayout(this);
+		mChildren.insert(mChildren.begin() + idx, entry);
+	}
+
+	void GUILayout::addLayout(GUILayout* layout)
+	{
+		if(layout->getParentLayout() != nullptr)
+			layout->getParentLayout()->removeLayout(layout);
+
+		GUILayoutEntry entry;
+		entry.layout = layout;
+		entry.isLayout = true;
+
+		layout->setParentLayout(this);
+		mChildren.push_back(entry);
+	}
+
+	void GUILayout::removeLayout(GUILayout* layout)
+	{
+		bool foundElem = false;
+		for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
+		{
+			GUILayoutEntry& child = *iter;
+
+			if(child.isLayout && child.layout == layout)
+			{
+				mChildren.erase(iter);
+				foundElem = true;
+				break;
+			}
+		}
+
+		if(!foundElem)
+			CM_EXCEPT(InvalidParametersException, "Provided element is not a part of this layout.");
+	}
+
+	void GUILayout::insertLayout(UINT32 idx, GUILayout* layout)
+	{
+		if(idx < 0 || idx >= (UINT32)mChildren.size())
+			CM_EXCEPT(InvalidParametersException, "Index out of range: " + toString(idx) + ". Valid range: 0 .. " + toString((UINT32)mChildren.size()));
+
+		if(layout->getParentLayout() != nullptr)
+			layout->getParentLayout()->removeLayout(layout);
+
+		GUILayoutEntry entry;
+		entry.layout = layout;
+		entry.isLayout = false;
+
+		layout->setParentLayout(this);
+		mChildren.insert(mChildren.begin() + idx, entry);
+	}
+
+	UINT32 GUILayout::getNumChildren() const
+	{
+		return (UINT32)mChildren.size();
+	}
+}

+ 12 - 0
TODO.txt

@@ -22,6 +22,18 @@ GUIWidget::updateMeshes leaks. If I leave the game running I can see memory cont
 GUI element grouping is wrong as it doesn't account for transparency
  - Elements sharing same material cannot be batched unless they are at a nearby depth with no elements between them. I need an algorithm to handle that.
 
+Finish GUILayoutOptions and integrate them with GUIElement
+Add GUIArea to GUIWidget
+Hide GUIElement depth and use depth from GUIArea instead
+Implement GUILayoutX, GUILayoutY so they properly set up GUIElement offsets and size
+Make sure GUIWidget only renders objects belonging to an GUILayout
+Setup callbacks from RenderWindow so layouts change when window changes
+ - Also GUIArea needs different behaviour whether its fixed size or whether is scales
+
+Figure out how to deal with callbacks properly. I recently eliminated them from Input but I'll need them for my GUI elements...
+ - How do I implement them? I really don't want to do Unitys approach to GUI
+ - If I do figure out a good way to keep callbacks, maybe rethink Input and re-add them?
+
  - My test model is rendering back faces. I need to flip them.
   - Although more than likely I am loading the model incorrectly since it works in Unity?
   - I probably want to determine front faces based on normals