Marko Pintera 12 лет назад
Родитель
Сommit
b5fd01d86c

+ 5 - 1
BansheeEngine/Include/BsGUIArea.h

@@ -22,19 +22,23 @@ namespace BansheeEngine
 		UINT16 getDepth() const { return mDepth; }
 		void setDepth(UINT16 depth) { mDepth = depth; }
 
+		void _update();
 	private:
 		friend class GUIWidget;
 
 		GUIWidget& mWidget;
 		UINT32 mX, mY, mWidth, mHeight;
 		UINT16 mDepth;
-		bool resizeWidthWithWindow, resizeHeightWithWindow;
+		bool mResizeWidthWithWindow, mResizeHeightWithWindow;
+		bool mIsDirty;
 
 		GUILayout* mLayout;
 
 		GUIArea(GUIWidget& widget, UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT16 depth);
 		~GUIArea();
 
+		bool isDirty() const;
+
 		void notifyWindowResized(UINT32 newWidth, UINT32 newHeight);
 
 		static void destroyInternal(GUIArea* area);

+ 6 - 1
BansheeEngine/Include/BsGUILayout.h

@@ -86,9 +86,14 @@ namespace BansheeEngine
 		/**
 		 * @brief	Re-arranges the elements to fit the layout. You shouldn't need to call this manually
 		 */
-		virtual void _update(UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT32 depth) = 0;
+		void _update(UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT32 depth);
+
+		bool _isDirty();
 
 	protected:
 		std::vector<GUILayoutEntry> mChildren;		
+		bool mIsDirty;
+
+		virtual void updateInternal(UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT32 depth) = 0;
 	};
 }

+ 1 - 1
BansheeEngine/Include/BsGUILayoutX.h

@@ -12,6 +12,6 @@ namespace BansheeEngine
 		~GUILayoutX() {};
 
 	protected:
-		void _update(UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT32 depth);
+		void updateInternal(UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT32 depth);
 	};
 }

+ 1 - 1
BansheeEngine/Include/BsGUILayoutY.h

@@ -12,6 +12,6 @@ namespace BansheeEngine
 		~GUILayoutY() {};
 
 	protected:
-		virtual void _update(UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT32 depth);
+		void updateInternal(UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT32 depth);
 	};
 }

+ 26 - 9
BansheeEngine/Source/BsGUIArea.cpp

@@ -7,12 +7,12 @@ using namespace CamelotFramework;
 namespace BansheeEngine
 {
 	GUIArea::GUIArea(GUIWidget& widget, UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT16 depth)
-		:mWidget(widget), mX(x), mY(y), mWidth(width), mHeight(height), mDepth(depth)
+		:mWidget(widget), mX(x), mY(y), mWidth(width), mHeight(height), mDepth(depth), mIsDirty(true)
 	{
 		mLayout = CM_NEW(GUILayoutX, PoolAlloc) GUILayoutX();
 
-		resizeWidthWithWindow = width == 0;
-		resizeHeightWithWindow = height == 0;
+		mResizeWidthWithWindow = width == 0;
+		mResizeHeightWithWindow = height == 0;
 
 		mWidget.registerArea(this);
 	}
@@ -39,19 +39,36 @@ namespace BansheeEngine
 		CM_DELETE(area, GUIArea, PoolAlloc);
 	}
 
+	void GUIArea::_update()
+	{
+		if(isDirty())
+		{
+			UINT32 combinedDepth = UINT32(mWidget.getDepth()) << 16 | UINT32(mDepth);
+
+			mLayout->_update(mX, mY, mWidth, mHeight, combinedDepth);
+			mIsDirty = false;
+		}
+	}
+
+	bool GUIArea::isDirty() const
+	{
+		if(mIsDirty)
+			return true;
+
+		return mLayout->_isDirty();
+	}
+
 	void GUIArea::notifyWindowResized(UINT32 newWidth, UINT32 newHeight)
 	{
-		if(resizeWidthWithWindow)
+		if(mResizeWidthWithWindow)
 			mWidth = newWidth;
 
-		if(resizeHeightWithWindow)
+		if(mResizeHeightWithWindow)
 			mHeight = newHeight;
 
-		if(resizeWidthWithWindow || resizeHeightWithWindow)
+		if(mResizeWidthWithWindow || mResizeHeightWithWindow)
 		{
-			UINT32 combinedDepth = UINT32(mWidget.getDepth()) << 16 | UINT32(mDepth);
-
-			mLayout->_update(mX, mY, mWidth, mHeight, combinedDepth);
+			mIsDirty = true;
 		}
 	}
 }

+ 38 - 0
BansheeEngine/Source/BsGUILayout.cpp

@@ -10,6 +10,7 @@ using namespace CamelotFramework;
 namespace BansheeEngine
 {
 	GUILayout::GUILayout()
+		:mIsDirty(false)
 	{
 
 	}
@@ -48,6 +49,7 @@ namespace BansheeEngine
 
 		element->_setParentLayout(this);
 		mChildren.push_back(entry);
+		mIsDirty = true;
 	}
 
 	void GUILayout::removeElement(GUIElement* element)
@@ -61,6 +63,7 @@ namespace BansheeEngine
 			{
 				mChildren.erase(iter);
 				foundElem = true;
+				mIsDirty = true;
 				break;
 			}
 		}
@@ -82,6 +85,7 @@ namespace BansheeEngine
 
 		element->_setParentLayout(this);
 		mChildren.insert(mChildren.begin() + idx, entry);
+		mIsDirty = true;
 	}
 
 	GUILayout& GUILayout::addLayoutX()
@@ -90,6 +94,7 @@ namespace BansheeEngine
 		entry.setLayout(CM_NEW(GUILayoutX, PoolAlloc) GUILayoutX());
 
 		mChildren.push_back(entry);
+		mIsDirty = true;
 
 		return *entry.layout;
 	}
@@ -100,6 +105,7 @@ namespace BansheeEngine
 		entry.setLayout(CM_NEW(GUILayoutY, PoolAlloc) GUILayoutY());
 
 		mChildren.push_back(entry);
+		mIsDirty = true;
 
 		return *entry.layout;
 	}
@@ -117,6 +123,7 @@ namespace BansheeEngine
 
 				mChildren.erase(iter);
 				foundElem = true;
+				mIsDirty = true;
 				break;
 			}
 		}
@@ -134,6 +141,7 @@ namespace BansheeEngine
 		entry.setLayout(CM_NEW(GUILayoutX, PoolAlloc) GUILayoutX());
 
 		mChildren.insert(mChildren.begin() + idx, entry);
+		mIsDirty = true;
 
 		return *entry.layout;
 	}
@@ -147,6 +155,7 @@ namespace BansheeEngine
 		entry.setLayout(CM_NEW(GUILayoutY, PoolAlloc) GUILayoutY());;
 
 		mChildren.insert(mChildren.begin() + idx, entry);
+		mIsDirty = true;
 
 		return *entry.layout;
 	}
@@ -157,6 +166,7 @@ namespace BansheeEngine
 		entry.setSpace(CM_NEW(GUIFixedSpace, PoolAlloc) GUIFixedSpace(size));
 
 		mChildren.push_back(entry);
+		mIsDirty = true;
 
 		return *entry.space;
 	}
@@ -174,6 +184,7 @@ namespace BansheeEngine
 
 				mChildren.erase(iter);
 				foundElem = true;
+				mIsDirty = true;
 				break;
 			}
 		}
@@ -191,6 +202,7 @@ namespace BansheeEngine
 		entry.setSpace(CM_NEW(GUIFixedSpace, PoolAlloc) GUIFixedSpace(size));
 
 		mChildren.insert(mChildren.begin() + idx, entry);
+		mIsDirty = true;
 
 		return *entry.space;
 	}
@@ -201,6 +213,7 @@ namespace BansheeEngine
 		entry.setFlexibleSpace(CM_NEW(GUIFlexibleSpace, PoolAlloc) GUIFlexibleSpace());
 
 		mChildren.push_back(entry);
+		mIsDirty = true;
 
 		return *entry.flexibleSpace;
 	}
@@ -218,6 +231,7 @@ namespace BansheeEngine
 
 				mChildren.erase(iter);
 				foundElem = true;
+				mIsDirty = true;
 				break;
 			}
 		}
@@ -235,6 +249,7 @@ namespace BansheeEngine
 		entry.setFlexibleSpace(CM_NEW(GUIFlexibleSpace, PoolAlloc) GUIFlexibleSpace());
 
 		mChildren.insert(mChildren.begin() + idx, entry);
+		mIsDirty = true;
 
 		return *entry.flexibleSpace;
 	}
@@ -243,4 +258,27 @@ namespace BansheeEngine
 	{
 		return (UINT32)mChildren.size();
 	}
+
+	void GUILayout::_update(UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT32 depth)
+	{
+		updateInternal(x, y, width, height, depth);
+		mIsDirty = false;
+	}
+
+	bool GUILayout::_isDirty()
+	{
+		if(mIsDirty)
+			return true;
+
+		for(auto& child : mChildren)
+		{
+			if(child.isLayout())
+			{
+				if(child.layout->_isDirty())
+					return true;
+			}
+		}
+
+		return false;
+	}
 }

+ 1 - 1
BansheeEngine/Source/BsGUILayoutX.cpp

@@ -8,7 +8,7 @@ using namespace CamelotFramework;
 
 namespace BansheeEngine
 {
-	void GUILayoutX::_update(UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT32 depth)
+	void GUILayoutX::updateInternal(UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT32 depth)
 	{
 		std::vector<UINT32> flexibleSpaceSizes;
 		for(auto& child : mChildren)

+ 1 - 1
BansheeEngine/Source/BsGUILayoutY.cpp

@@ -2,7 +2,7 @@
 
 namespace BansheeEngine
 {
-	void GUILayoutY::_update(UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT32 depth)
+	void GUILayoutY::updateInternal(UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT32 depth)
 	{
 
 	}

+ 2 - 3
TODO.txt

@@ -24,11 +24,10 @@ GUIWidget::updateMeshes leaks. If I leave the game running I can see memory cont
 IMMEDIATE:
  - I'm not setting worldTransform of GUI material in GUIManager::render
    - I need to separate meshes per-widget and later implement some kind of smart batching using multiple transforms per mesh
- - Widgets should probably have their own depth. Make widget and area depths UINT16, and element depth UINT32, a combination of those two.
  - On content change I need to notify parent layout
- - Do layouts have isDirty flag? They probably should
-   - GUIArea updates on every window resize event. I should instead just make it dirty and make the update during GUIManager::update
  - Add clip rectangles on GUILayoutX
+ - Calculate flexible spaces in GUILyoutX
+ - Call layout update before remesh and input in GUIManager
  - Implement GUILayoutY
 
 Figure out how to deal with callbacks properly. I recently eliminated them from Input but I'll need them for my GUI elements...