Răsfoiți Sursa

More optimized GUI element bound calculations (WIP)
Refactored GUI layout updates to be cleaner (WIP)

Marko Pintera 10 ani în urmă
părinte
comite
22cf8a4b76
68 a modificat fișierele cu 867 adăugiri și 1121 ștergeri
  1. 1 2
      BansheeEditor/Include/BsGUIComponentFoldout.h
  2. 1 2
      BansheeEditor/Include/BsGUIFieldBase.h
  3. 1 2
      BansheeEditor/Include/BsGUIFoldout.h
  4. 1 2
      BansheeEditor/Include/BsGUIResourceTreeView.h
  5. 1 2
      BansheeEditor/Include/BsGUITabbedTitleBar.h
  6. 1 2
      BansheeEditor/Include/BsGUITextField.h
  7. 1 2
      BansheeEditor/Include/BsGUITreeView.h
  8. 29 16
      BansheeEditor/Source/BsDockManager.cpp
  9. 16 15
      BansheeEditor/Source/BsGUIColor.cpp
  10. 12 14
      BansheeEditor/Source/BsGUIComponentFoldout.cpp
  11. 8 11
      BansheeEditor/Source/BsGUIFieldBase.cpp
  12. 3 4
      BansheeEditor/Source/BsGUIFloatField.cpp
  13. 22 22
      BansheeEditor/Source/BsGUIFoldout.cpp
  14. 3 4
      BansheeEditor/Source/BsGUIIntField.cpp
  15. 1 1
      BansheeEditor/Source/BsGUIMenuBar.cpp
  16. 10 12
      BansheeEditor/Source/BsGUIResourceTreeView.cpp
  17. 1 1
      BansheeEditor/Source/BsGUISceneTreeView.cpp
  18. 59 55
      BansheeEditor/Source/BsGUITabbedTitleBar.cpp
  19. 8 11
      BansheeEditor/Source/BsGUITextField.cpp
  20. 69 79
      BansheeEditor/Source/BsGUITreeView.cpp
  21. 1 1
      BansheeEditor/Source/BsGUIWindowDropArea.cpp
  22. 1 1
      BansheeEditor/Source/BsGUIWindowFrame.cpp
  23. 1 0
      BansheeEngine/BansheeEngine.vcxproj
  24. 3 0
      BansheeEngine/BansheeEngine.vcxproj.filters
  25. 1 2
      BansheeEngine/Include/BsGUIDropDownContent.h
  26. 4 13
      BansheeEngine/Include/BsGUIElement.h
  27. 24 130
      BansheeEngine/Include/BsGUIElementBase.h
  28. 51 0
      BansheeEngine/Include/BsGUILayoutData.h
  29. 0 15
      BansheeEngine/Include/BsGUILayoutUtility.h
  30. 3 16
      BansheeEngine/Include/BsGUILayoutX.h
  31. 3 16
      BansheeEngine/Include/BsGUILayoutY.h
  32. 5 19
      BansheeEngine/Include/BsGUIPanel.h
  33. 1 2
      BansheeEngine/Include/BsGUIProgressBar.h
  34. 4 5
      BansheeEngine/Include/BsGUIScrollArea.h
  35. 1 2
      BansheeEngine/Include/BsGUISlider.h
  36. 1 1
      BansheeEngine/Include/BsGUISpace.h
  37. 6 1
      BansheeEngine/Include/BsGUIWidget.h
  38. 14 11
      BansheeEngine/Source/BsGUIButtonBase.cpp
  39. 10 6
      BansheeEngine/Source/BsGUIDropDownBox.cpp
  40. 21 28
      BansheeEngine/Source/BsGUIDropDownContent.cpp
  41. 15 23
      BansheeEngine/Source/BsGUIElement.cpp
  42. 56 83
      BansheeEngine/Source/BsGUIElementBase.cpp
  43. 42 40
      BansheeEngine/Source/BsGUIInputBox.cpp
  44. 3 1
      BansheeEngine/Source/BsGUIInputCaret.cpp
  45. 3 1
      BansheeEngine/Source/BsGUIInputTool.cpp
  46. 14 10
      BansheeEngine/Source/BsGUILabel.cpp
  47. 2 2
      BansheeEngine/Source/BsGUILayout.cpp
  48. 5 58
      BansheeEngine/Source/BsGUILayoutUtility.cpp
  49. 26 34
      BansheeEngine/Source/BsGUILayoutX.cpp
  50. 23 31
      BansheeEngine/Source/BsGUILayoutY.cpp
  51. 1 1
      BansheeEngine/Source/BsGUIListBox.cpp
  52. 1 1
      BansheeEngine/Source/BsGUIManager.cpp
  53. 34 39
      BansheeEngine/Source/BsGUIPanel.cpp
  54. 20 23
      BansheeEngine/Source/BsGUIProgressBar.cpp
  55. 3 3
      BansheeEngine/Source/BsGUIRenderTexture.cpp
  56. 57 67
      BansheeEngine/Source/BsGUIScrollArea.cpp
  57. 7 5
      BansheeEngine/Source/BsGUIScrollBar.cpp
  58. 7 17
      BansheeEngine/Source/BsGUISlider.cpp
  59. 28 26
      BansheeEngine/Source/BsGUISliderHandle.cpp
  60. 19 16
      BansheeEngine/Source/BsGUITexture.cpp
  61. 9 9
      BansheeEngine/Source/BsGUIViewport.cpp
  62. 60 61
      BansheeEngine/Source/BsGUIWidget.cpp
  63. 1 2
      SBansheeEditor/Include/BsGUIGameObjectField.h
  64. 1 2
      SBansheeEditor/Include/BsGUIResourceField.h
  65. 8 11
      SBansheeEditor/Source/BsGUIGameObjectField.cpp
  66. 10 14
      SBansheeEditor/Source/BsGUIResourceField.cpp
  67. 1 1
      SBansheeEngine/Source/BsScriptGUILayoutUtility.cpp
  68. 8 12
      TODO.txt

+ 1 - 2
BansheeEditor/Include/BsGUIComponentFoldout.h

@@ -31,8 +31,7 @@ namespace BansheeEngine
 		 */
 		virtual void setTint(const Color& color);
 
-		void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		void _updateLayoutInternal(const GUILayoutData& data);
 
 		Vector2I _getOptimalSize() const;
 

+ 1 - 2
BansheeEditor/Include/BsGUIFieldBase.h

@@ -14,8 +14,7 @@ namespace BansheeEngine
 		GUIFieldBase(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
 			const String& labelStyle, const GUIDimensions& dimensions, bool withLabel);
 
-		void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		void _updateLayoutInternal(const GUILayoutData& data);
 
 		virtual Vector2I _getOptimalSize() const;
 

+ 1 - 2
BansheeEditor/Include/BsGUIFoldout.h

@@ -32,8 +32,7 @@ namespace BansheeEngine
 		 */
 		virtual void setTint(const Color& color);
 
-		void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		void _updateLayoutInternal(const GUILayoutData& data);
 
 		Vector2I _getOptimalSize() const;
 

+ 1 - 2
BansheeEditor/Include/BsGUIResourceTreeView.h

@@ -70,8 +70,7 @@ namespace BansheeEngine
 			const String& foldoutBtnStyle, const String& selectionBackgroundStyle, const String& editBoxStyle, 
 			const String& dragHighlightStyle, const String& dragSepHighlightStyle, const GUIDimensions& dimensions);
 
-		virtual void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		virtual void _updateLayoutInternal(const GUILayoutData& data);
 
 		virtual TreeElement& getRootElement() { return mRootElement; }
 		virtual const TreeElement& getRootElementConst() const { return mRootElement; }

+ 1 - 2
BansheeEditor/Include/BsGUITabbedTitleBar.h

@@ -38,8 +38,7 @@ namespace BansheeEngine
 
 		void updateClippedBounds();
 
-		void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		void _updateLayoutInternal(const GUILayoutData& data);
 	protected:
 		static const UINT32 TAB_SPACING;
 		static const UINT32 OPTION_BTN_SPACING;

+ 1 - 2
BansheeEditor/Include/BsGUITextField.h

@@ -45,8 +45,7 @@ namespace BansheeEngine
 		GUITextField(const PrivatelyConstruct& dummy, bool multiline, const GUIContent& labelContent, UINT32 labelWidth,
 			const String& style, const GUIDimensions& dimensions, bool withLabel);
 
-		void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		void _updateLayoutInternal(const GUILayoutData& data);
 
 		Vector2I _getOptimalSize() const;
 

+ 1 - 2
BansheeEditor/Include/BsGUITreeView.h

@@ -75,8 +75,7 @@ namespace BansheeEngine
 		Vector2I _getOptimalSize() const;
 		void updateClippedBounds();
 
-		virtual void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		virtual void _updateLayoutInternal(const GUILayoutData& data);
 	protected:
 		static const UINT32 ELEMENT_EXTRA_SPACING;
 		static const UINT32 INDENT_SIZE;

+ 29 - 16
BansheeEditor/Source/BsDockManager.cpp

@@ -107,13 +107,17 @@ namespace BansheeEngine
 				mChildren[0]->setArea(mArea.x, mArea.y, mArea.width, sizeTop);
 				mChildren[1]->setArea(mArea.x, mArea.y + sizeTop + SLIDER_SIZE, mArea.width, sizeBottom);
 
-				mSlider->_setPosition(Vector2I(mArea.x, mArea.y + sizeTop));
-				mSlider->_setWidth(mArea.width);
-				mSlider->_setHeight(SLIDER_SIZE);
+				GUILayoutData layoutData = mSlider->_getLayoutData();
+				layoutData.area = mArea;
+				layoutData.area.y += sizeTop;
+				layoutData.area.height = SLIDER_SIZE;
 
-				Rect2I elemClipRect(clipRect.x - mArea.x, clipRect.y - mArea.y, clipRect.width, clipRect.height);
-				mSlider->_setClipRect(elemClipRect);
-				mSlider->markContentAsDirty();
+				layoutData.clipRect = clipRect;
+				layoutData.clipRect.x -= mArea.x;
+				layoutData.clipRect.y -= mArea.y;
+
+				mSlider->_setLayoutData(layoutData);
+				mSlider->_markContentAsDirty();
 			}
 			else
 			{
@@ -124,13 +128,17 @@ namespace BansheeEngine
 				mChildren[0]->setArea(mArea.x, mArea.y, sizeLeft, mArea.height);
 				mChildren[1]->setArea(mArea.x + sizeLeft + SLIDER_SIZE, mArea.y, sizeRight, mArea.height);
 
-				mSlider->_setPosition(Vector2I(mArea.x + sizeLeft, mArea.y));
-				mSlider->_setWidth(SLIDER_SIZE);
-				mSlider->_setHeight(mArea.height);
+				GUILayoutData layoutData = mSlider->_getLayoutData();
+				layoutData.area = mArea;
+				layoutData.area.x += sizeLeft;
+				layoutData.area.width = SLIDER_SIZE;
+
+				layoutData.clipRect = clipRect;
+				layoutData.clipRect.x -= mArea.x;
+				layoutData.clipRect.y -= mArea.y;
 
-				Rect2I elemClipRect(clipRect.x - mArea.x, clipRect.y - mArea.y, clipRect.width, clipRect.height);
-				mSlider->_setClipRect(elemClipRect);
-				mSlider->markContentAsDirty();
+				mSlider->_setLayoutData(layoutData);
+				mSlider->_markContentAsDirty();
 			}
 		}
 	}
@@ -244,14 +252,19 @@ namespace BansheeEngine
 		if (horizontal)
 		{
 			mSlider = GUIDockSlider::create(true, "DockSliderBtn");
-			mSlider->_setWidgetDepth(widgetParent->getDepth());
-			mSlider->markMeshAsDirty();
+
+			GUILayoutData layoutData = mSlider->_getLayoutData();
+			layoutData.setWidgetDepth(widgetParent->getDepth());
+			mSlider->_setLayoutData(layoutData);
+			mSlider->_markMeshAsDirty();
 		}
 		else
 		{
 			mSlider = GUIDockSlider::create(false, "DockSliderBtn");
-			mSlider->_setWidgetDepth(widgetParent->getDepth());
-			mSlider->markMeshAsDirty();
+			GUILayoutData layoutData = mSlider->_getLayoutData();
+			layoutData.setWidgetDepth(widgetParent->getDepth());
+			mSlider->_setLayoutData(layoutData);
+			mSlider->_markMeshAsDirty();
 		}
 
 		mSlider->_changeParentWidget(widgetParent);

+ 16 - 15
BansheeEditor/Source/BsGUIColor.cpp

@@ -49,14 +49,14 @@ namespace BansheeEngine
 	{
 		mColor = color;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIColor::setTint(const Color& color)
 	{
 		mTint = color;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	UINT32 GUIColor::_getNumRenderElements() const
@@ -100,11 +100,11 @@ namespace BansheeEngine
 		mAlphaImageDesc.color = Color::White * color.a;
 		mAlphaImageDesc.color.a = 1.0f;
 
-		mColorImageDesc.width = (UINT32)(mWidth * ALPHA_SPLIT_POSITION);
-		mColorImageDesc.height = mHeight;
+		mColorImageDesc.width = (UINT32)(mLayoutData.area.width * ALPHA_SPLIT_POSITION);
+		mColorImageDesc.height = mLayoutData.area.height;
 
-		mAlphaImageDesc.width = mWidth - mColorImageDesc.width;
-		mAlphaImageDesc.height = mHeight;
+		mAlphaImageDesc.width = mLayoutData.area.width - mColorImageDesc.width;
+		mAlphaImageDesc.height = mLayoutData.area.height;
 
 		mColorSprite->update(mColorImageDesc, (UINT64)_getParentWidget());
 		mAlphaSprite->update(mAlphaImageDesc, (UINT64)_getParentWidget());
@@ -114,13 +114,13 @@ namespace BansheeEngine
 
 	void GUIColor::updateClippedBounds()
 	{
-		mClippedBounds = Rect2I(0, 0, mWidth, mHeight);
+		mClippedBounds = Rect2I(0, 0, mLayoutData.area.width, mLayoutData.area.height);
 
-		if(mClipRect.width > 0 && mClipRect.height > 0)
-			mClippedBounds.clip(mClipRect);
+		if (mLayoutData.clipRect.width > 0 && mLayoutData.clipRect.height > 0)
+			mClippedBounds.clip(mLayoutData.clipRect);
 
-		mClippedBounds.x += mOffset.x;
-		mClippedBounds.y += mOffset.y;
+		mClippedBounds.x += mLayoutData.area.x;
+		mClippedBounds.y += mLayoutData.area.y;
 	}
 
 	Vector2I GUIColor::_getOptimalSize() const
@@ -133,20 +133,21 @@ namespace BansheeEngine
 	{
 		UINT32 alphaSpriteIdx = mColorSprite->getNumRenderElements();
 
+		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
 		if(renderElementIdx < alphaSpriteIdx)
 		{
 			mColorSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, 
-				vertexStride, indexStride, renderElementIdx, mOffset, mClipRect);
+				vertexStride, indexStride, renderElementIdx, offset, mLayoutData.clipRect);
 
 			return;
 		}
 		else if(renderElementIdx >= alphaSpriteIdx)
 		{
-			Vector2I alphaOffset = mOffset;
-			UINT32 xOffset = (UINT32)(mWidth * ALPHA_SPLIT_POSITION);
+			Vector2I alphaOffset = offset;
+			UINT32 xOffset = (UINT32)(mLayoutData.area.width * ALPHA_SPLIT_POSITION);
 			alphaOffset.x += xOffset;
 
-			Rect2I alphaClipRect = mClipRect;
+			Rect2I alphaClipRect = mLayoutData.clipRect;
 			alphaClipRect.x -= xOffset;
 
 			mAlphaSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, 

+ 12 - 14
BansheeEditor/Source/BsGUIComponentFoldout.cpp

@@ -57,7 +57,7 @@ namespace BansheeEngine
 			else
 				mToggle->toggleOff();
 
-			markContentAsDirty();
+			_markContentAsDirty();
 
 			if(!onStateChanged.empty())
 				onStateChanged(mIsExpanded);
@@ -78,29 +78,27 @@ namespace BansheeEngine
 	{
 		mIsExpanded = value;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 
 		onStateChanged(value);
 	}
 
-	void GUIComponentFoldout::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-		Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUIComponentFoldout::_updateLayoutInternal(const GUILayoutData& data)
 	{
 		UINT32 toggleOffset = 0;
-
+		
 		{
 			Vector2I optimalSize = mToggle->_getOptimalSize();
-			INT32 yOffset = Math::roundToInt(((INT32)height - optimalSize.y) * 0.5f);
+			INT32 yOffset = Math::roundToInt(((INT32)data.area.height - optimalSize.y) * 0.5f);
+
+			GUILayoutData childData = data;
+			childData.area.y += yOffset;
+			childData.area.height = optimalSize.y;
 
-			Vector2I offset(x, y + yOffset);
-			mToggle->_setPosition(offset);
-			mToggle->_setWidth(width);
-			mToggle->_setHeight(optimalSize.y);
-			mToggle->_setAreaDepth(panelDepth);
-			mToggle->_setWidgetDepth(widgetDepth);
+			childData.clipRect.x -= childData.area.x;
+			childData.clipRect.y -= childData.area.y;
 
-			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-			mToggle->_setClipRect(elemClipRect);
+			mToggle->_setLayoutData(childData);
 
 			toggleOffset = optimalSize.x;
 		}

+ 8 - 11
BansheeEditor/Source/BsGUIFieldBase.cpp

@@ -23,20 +23,17 @@ namespace BansheeEngine
 		}
 	}
 
-	void GUIFieldBase::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-		Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUIFieldBase::_updateLayoutInternal(const GUILayoutData& data)
 	{
-		mLayout->_setPosition(Vector2I(x, y));
-		mLayout->_setWidth(width);
-		mLayout->_setHeight(height);
-		mLayout->_setWidgetDepth(widgetDepth);
-		mLayout->_setAreaDepth(panelDepth);
-		mLayout->_setPanelDepthRange(panelDepthRangeMin, panelDepthRangeMax);
+		GUILayoutData childData = data;
+		childData.clipRect.x -= data.area.x;
+		childData.clipRect.y -= data.area.y;
 
-		Rect2I elemClipRect(clipRect.x - x, clipRect.y - y, clipRect.width, clipRect.height);
-		mLayout->_setClipRect(elemClipRect);
+		mLayout->_setLayoutData(childData);
 
-		mLayout->_updateLayoutInternal(x, y, width, height, clipRect, widgetDepth, panelDepth, panelDepthRangeMin, panelDepthRangeMax);
+		childData.clipRect = data.clipRect;
+
+		mLayout->_updateLayoutInternal(childData);
 	}
 
 	Vector2I GUIFieldBase::_getOptimalSize() const

+ 3 - 4
BansheeEditor/Source/BsGUIFloatField.cpp

@@ -46,7 +46,7 @@ namespace BansheeEngine
 		Rect2I draggableArea;
 
 		if(mLabel != nullptr)
-			draggableArea = mLabel->_getCachedBounds();
+			draggableArea = mLabel->_getLayoutData().area;
 
 		if(draggableArea.contains(position))
 		{
@@ -64,7 +64,7 @@ namespace BansheeEngine
 		Rect2I draggableArea;
 
 		if(mLabel != nullptr)
-			draggableArea = mLabel->_getCachedBounds();
+			draggableArea = mLabel->_getLayoutData().area;
 
 		if(event.getType() == GUIMouseEventType::MouseDragStart)
 		{
@@ -143,8 +143,7 @@ namespace BansheeEngine
 
 	void GUIFloatField::updateClippedBounds()
 	{
-		Vector2I offset = _getOffset();
-		mClippedBounds = Rect2I(offset.x, offset.y, _getWidth(), _getHeight());
+		mClippedBounds = mLayoutData.area;
 	}
 
 	const String& GUIFloatField::getGUITypeName()

+ 22 - 22
BansheeEditor/Source/BsGUIFoldout.cpp

@@ -59,7 +59,7 @@ namespace BansheeEngine
 			else
 				mToggle->toggleOff();
 
-			markContentAsDirty();
+			_markContentAsDirty();
 
 			if (!onStateChanged.empty())
 				onStateChanged(mIsExpanded);
@@ -81,46 +81,46 @@ namespace BansheeEngine
 	{
 		mIsExpanded = value;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 
 		onStateChanged(value);
 	}
 
-	void GUIFoldout::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-		Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUIFoldout::_updateLayoutInternal(const GUILayoutData& data)
 	{
 		UINT32 toggleOffset = 0;
 
 		{
 			Vector2I optimalSize = mToggle->_getOptimalSize();
-			INT32 yOffset = Math::roundToInt(((INT32)height - optimalSize.y) * 0.5f);
+			INT32 yOffset = Math::roundToInt(((INT32)data.area.height - optimalSize.y) * 0.5f);
 
-			Vector2I offset(x, y + yOffset);
-			mToggle->_setPosition(offset);
-			mToggle->_setWidth(optimalSize.x);
-			mToggle->_setHeight(optimalSize.y);
-			mToggle->_setAreaDepth(panelDepth);
-			mToggle->_setWidgetDepth(widgetDepth);
+			GUILayoutData childData = data;
+			childData.area.y += yOffset;
+			childData.area.width = optimalSize.x;
+			childData.area.height = optimalSize.y;
 
-			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-			mToggle->_setClipRect(elemClipRect);
+			childData.clipRect.x -= childData.area.x;
+			childData.clipRect.y -= childData.area.y;
+
+			mToggle->_setLayoutData(childData);
 
 			toggleOffset = optimalSize.x;
 		}
 
 		{
 			Vector2I optimalSize = mLabel->_getOptimalSize();
-			INT32 yOffset = Math::roundToInt(((INT32)height - optimalSize.y) * 0.5f);
+			INT32 yOffset = Math::roundToInt(((INT32)data.area.height - optimalSize.y) * 0.5f);
+
+			GUILayoutData childData = data;
+			childData.area.x += toggleOffset;
+			childData.area.y += yOffset;
+			childData.area.width = optimalSize.x;
+			childData.area.height = optimalSize.y;
 
-			Vector2I offset(x + toggleOffset, y + yOffset);
-			mLabel->_setPosition(offset);
-			mLabel->_setWidth(optimalSize.x);
-			mLabel->_setHeight(optimalSize.y);
-			mLabel->_setAreaDepth(panelDepth);
-			mLabel->_setWidgetDepth(widgetDepth);
+			childData.clipRect.x -= childData.area.x;
+			childData.clipRect.y -= childData.area.y;
 
-			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-			mLabel->_setClipRect(elemClipRect);
+			mLabel->_setLayoutData(childData);
 		}
 	}
 

+ 3 - 4
BansheeEditor/Source/BsGUIIntField.cpp

@@ -48,7 +48,7 @@ namespace BansheeEngine
 		Rect2I draggableArea;
 
 		if(mLabel != nullptr)
-			draggableArea = mLabel->_getCachedBounds();
+			draggableArea = mLabel->_getLayoutData().area;
 
 		if(draggableArea.contains(position))
 		{
@@ -66,7 +66,7 @@ namespace BansheeEngine
 		Rect2I draggableArea;
 
 		if(mLabel != nullptr)
-			draggableArea = mLabel->_getCachedBounds();
+			draggableArea = mLabel->_getLayoutData().area;
 
 		if(event.getType() == GUIMouseEventType::MouseDragStart)
 		{
@@ -176,8 +176,7 @@ namespace BansheeEngine
 
 	void GUIIntField::updateClippedBounds()
 	{
-		Vector2I offset = _getOffset();
-		mClippedBounds = Rect2I(offset.x, offset.y, _getWidth(), _getHeight());
+		mClippedBounds = mLayoutData.area;
 	}
 
 	const String& GUIIntField::getGUITypeName()

+ 1 - 1
BansheeEditor/Source/BsGUIMenuBar.cpp

@@ -253,7 +253,7 @@ namespace BansheeEngine
 		GUIDropDownData dropDownData = subMenu->menu->getDropDownData();
 		GUIWidget* widget = subMenu->button->_getParentWidget();
 
-		GUIDropDownAreaPlacement placement = GUIDropDownAreaPlacement::aroundBoundsHorz(subMenu->button->_getCachedBounds());
+		GUIDropDownAreaPlacement placement = GUIDropDownAreaPlacement::aroundBoundsHorz(subMenu->button->_getLayoutData().area);
 
 		GameObjectHandle<GUIDropDownBox> dropDownBox = GUIDropDownBoxManager::instance().openDropDownBox(widget->getTarget(), 
 			placement, dropDownData, widget->getSkinResource(), GUIDropDownType::MenuBar, std::bind(&GUIMenuBar::onSubMenuClosed, this));

+ 10 - 12
BansheeEditor/Source/BsGUIResourceTreeView.cpp

@@ -74,15 +74,13 @@ namespace BansheeEngine
 			foldoutBtnStyle, selectionBackgroundStyle, editBoxStyle, dragHighlightStyle, dragSepHighlightStyle, GUIDimensions::create(options));
 	}
 
-	void GUIResourceTreeView::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I clipRect, 
-		UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUIResourceTreeView::_updateLayoutInternal(const GUILayoutData& data)
 	{
-		GUITreeView::_updateLayoutInternal(x, y, width, height, clipRect, widgetDepth, 
-			panelDepth, panelDepthRangeMin, panelDepthRangeMax);
+		GUITreeView::_updateLayoutInternal(data);
 
 		if(mDropTarget != nullptr)
 		{
-			mDropTarget->setArea(x, y, width, height);
+			mDropTarget->setArea(data.area.x, data.area.y, data.area.width, data.area.height);
 		}
 	}
 
@@ -258,7 +256,7 @@ namespace BansheeEngine
 		assert(libEntry != nullptr);
 		updateFromProjectLibraryEntry(newElement, libEntry);
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIResourceTreeView::entryRemoved(const Path& path)
@@ -284,7 +282,7 @@ namespace BansheeEngine
 		if(parentWindow != nullptr)
 		{
 			mCurrentWindow = parentWindow;
-			mDropTarget = &Platform::createDropTarget(mCurrentWindow, _getOffset().x, _getOffset().y, _getWidth(), _getHeight());
+			mDropTarget = &Platform::createDropTarget(mCurrentWindow, mLayoutData.area.x, mLayoutData.area.y, mLayoutData.area.width, mLayoutData.area.height);
 
 			mDropTargetEnterConn = mDropTarget->onEnter.connect(std::bind(&GUIResourceTreeView::dropTargetDragMove, this, _1, _2));
 			mDropTargetMoveConn = mDropTarget->onDragOver.connect(std::bind(&GUIResourceTreeView::dropTargetDragMove, this, _1, _2));
@@ -305,7 +303,7 @@ namespace BansheeEngine
 		mDragPosition = Vector2I(x, y);
 		mDragInProgress = true;
 		mDropTargetDragActive = true;
-		markContentAsDirty();
+		_markContentAsDirty();
 
 		if(mBottomScrollBounds.contains(mDragPosition))
 		{
@@ -325,7 +323,7 @@ namespace BansheeEngine
 	{
 		mDragInProgress = false;
 		mDropTargetDragActive = false;
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIResourceTreeView::dropTargetDragDropped(INT32 x, INT32 y)
@@ -359,7 +357,7 @@ namespace BansheeEngine
 
 		mDragInProgress = false;
 		mDropTargetDragActive = false;
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	Path GUIResourceTreeView::findUniquePath(const Path& path)
@@ -438,7 +436,7 @@ namespace BansheeEngine
 	void GUIResourceTreeView::dragAndDropFinalize()
 	{
 		mDragInProgress = false;
-		markContentAsDirty();
+		_markContentAsDirty();
 
 		DraggedResources* draggedResources = reinterpret_cast<DraggedResources*>(DragAndDropManager::instance().getDragData());
 		bs_delete(draggedResources);
@@ -457,7 +455,7 @@ namespace BansheeEngine
 		if (widget != nullptr && widget->getTarget()->getTarget()->getProperties().isWindow())
 		{
 			RenderWindow* parentWindow = static_cast<RenderWindow*>(widget->getTarget()->getTarget().get());
-			setDropTarget(parentWindow, _getOffset().x, _getOffset().y, _getWidth(), _getHeight());
+			setDropTarget(parentWindow, mLayoutData.area.x, mLayoutData.area.y, mLayoutData.area.width, mLayoutData.area.height);
 		}
 		else
 			clearDropTarget();

+ 1 - 1
BansheeEditor/Source/BsGUISceneTreeView.cpp

@@ -252,7 +252,7 @@ namespace BansheeEngine
 	void GUISceneTreeView::dragAndDropFinalize()
 	{
 		mDragInProgress = false;
-		markContentAsDirty();
+		_markContentAsDirty();
 
 		DraggedSceneObjects* draggedSceneObjects = reinterpret_cast<DraggedSceneObjects*>(DragAndDropManager::instance().getDragData());
 		bs_delete(draggedSceneObjects);

+ 59 - 55
BansheeEditor/Source/BsGUITabbedTitleBar.cpp

@@ -138,8 +138,8 @@ namespace BansheeEngine
 				UINT32 numTabButtons = (UINT32)mTabButtons.size();
 				for(UINT32 i = 0; i < numTabButtons; i++)
 				{
-					UINT32 width = mTabButtons[i]->_getWidth();
-					INT32 centerX = mTabButtons[i]->_getOffset().x + width / 2;
+					UINT32 width = mTabButtons[i]->_getLayoutData().area.width;
+					INT32 centerX = mTabButtons[i]->_getLayoutData().area.x + width / 2;
 
 					if((i + 1) == numTabButtons)
 					{
@@ -169,8 +169,8 @@ namespace BansheeEngine
 						}
 						else
 						{
-							UINT32 nextWidth = mTabButtons[i + 1]->_getWidth();
-							INT32 nextCenterX = mTabButtons[i + 1]->_getOffset().x + nextWidth / 2;
+							UINT32 nextWidth = mTabButtons[i + 1]->_getLayoutData().area.width;
+							INT32 nextCenterX = mTabButtons[i + 1]->_getLayoutData().area.x + nextWidth / 2;
 
 							if(widgetRelPos.x > centerX && widgetRelPos.x < nextCenterX)
 							{
@@ -229,36 +229,35 @@ namespace BansheeEngine
 
 	void GUITabbedTitleBar::updateClippedBounds()
 	{
-		Vector2I offset = _getOffset();
-		mClippedBounds = Rect2I(offset.x, offset.y, _getWidth(), _getHeight());
+		mClippedBounds = mLayoutData.area;
 	}
 
-	void GUITabbedTitleBar::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-		Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUITabbedTitleBar::_updateLayoutInternal(const GUILayoutData& data)
 	{
 		Vector2I minBtnOptimalSize = mMinBtn->_getOptimalSize();
 		Vector2I closeBtnOptimalSize = mCloseBtn->_getOptimalSize();
 
 		UINT32 endButtonWidth = minBtnOptimalSize.x + closeBtnOptimalSize.x + OPTION_BTN_SPACING;
 
-		Rect2I tabClipRect = clipRect;
+		Rect2I tabClipRect = data.clipRect;
 		tabClipRect.width -= endButtonWidth;
 
 		{
 			Vector2I optimalSize = mBackgroundImage->_getOptimalSize();
-			Vector2I offset(x + 1, y + 1);
-			mBackgroundImage->_setPosition(offset);
-			mBackgroundImage->_setWidth(width - 2);
-			mBackgroundImage->_setHeight(optimalSize.y);
-			mBackgroundImage->_setAreaDepth(panelDepth);
-			mBackgroundImage->_setWidgetDepth(widgetDepth);
-
-			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-			mBackgroundImage->_setClipRect(elemClipRect);
+
+			GUILayoutData childData = data;
+			childData.area.x += 1;
+			childData.area.y += 1;
+			childData.area.width -= 2;
+			childData.area.height = optimalSize.y;
+			childData.clipRect.x -= childData.area.x;
+			childData.clipRect.y -= childData.area.y;
+
+			mBackgroundImage->_setLayoutData(childData);
 		}
 
-		UINT32 curX = x + 1;
-		UINT32 curY = y;
+		UINT32 curX = data.area.x + 1;
+		UINT32 curY = data.area.y;
 		UINT32 tabBtnHeight = 0;
 		for(UINT32 i = 0; i < (UINT32)mTabButtons.size(); i++)
 		{
@@ -275,35 +274,39 @@ namespace BansheeEngine
 			}
 			else if(mDragInProgress && mDraggedBtn == btn)
 			{
-				offset = btn->_getOffset();
 				offset.x = mDragBtnOffset;
+				offset.y = btn->_getLayoutData().area.y;
 			}
 
-			btn->_setPosition(offset);
-			btn->_setWidth(optimalSize.x);
-			btn->_setHeight(optimalSize.y);
-			btn->_setAreaDepth(panelDepth);
-			btn->_setWidgetDepth(widgetDepth);
+			GUILayoutData childData = data;
+			childData.area.x = offset.x;
+			childData.area.y = offset.y;
+			childData.area.width = optimalSize.x;
+			childData.area.height = optimalSize.y;
+			childData.clipRect = tabClipRect;
+			childData.clipRect.x -= childData.area.x;
+			childData.clipRect.y -= childData.area.y;
 
-			Rect2I elemClipRect(tabClipRect.x - offset.x, tabClipRect.y - offset.y, tabClipRect.width, tabClipRect.height);
-			btn->_setClipRect(elemClipRect);
+			btn->_setLayoutData(childData);
 
 			curX += optimalSize.x;
 		}
 
-		INT32 optionBtnXPos = x + width - endButtonWidth - 1;
+		INT32 optionBtnXPos = data.area.x + data.area.width - endButtonWidth - 1;
 		{
 			INT32 optionBtnYPos = curY + Math::floorToInt((tabBtnHeight - minBtnOptimalSize.y) * 0.5f);
 
 			Vector2I offset(optionBtnXPos, optionBtnYPos);
-			mMinBtn->_setPosition(offset);
-			mMinBtn->_setWidth(minBtnOptimalSize.x);
-			mMinBtn->_setHeight(minBtnOptimalSize.y);
-			mMinBtn->_setAreaDepth(panelDepth);
-			mMinBtn->_setWidgetDepth(widgetDepth);
-
-			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-			mMinBtn->_setClipRect(elemClipRect);
+
+			GUILayoutData childData = data;
+			childData.area.x = offset.x;
+			childData.area.y = offset.y;
+			childData.area.width = minBtnOptimalSize.x;
+			childData.area.height = minBtnOptimalSize.y;
+			childData.clipRect.x -= childData.area.x;
+			childData.clipRect.y -= childData.area.y;
+
+			mMinBtn->_setLayoutData(childData);
 		}
 
 		optionBtnXPos += minBtnOptimalSize.x + OPTION_BTN_SPACING;
@@ -311,14 +314,16 @@ namespace BansheeEngine
 			INT32 optionBtnYPos = curY + Math::floorToInt((tabBtnHeight - closeBtnOptimalSize.y) * 0.5f);
 
 			Vector2I offset(optionBtnXPos, optionBtnYPos);
-			mCloseBtn->_setPosition(offset);
-			mCloseBtn->_setWidth(closeBtnOptimalSize.x);
-			mCloseBtn->_setHeight(closeBtnOptimalSize.y);
-			mCloseBtn->_setAreaDepth(panelDepth);
-			mCloseBtn->_setWidgetDepth(widgetDepth);
-
-			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-			mCloseBtn->_setClipRect(elemClipRect);
+
+			GUILayoutData childData = data;
+			childData.area.x = offset.x;
+			childData.area.y = offset.y;
+			childData.area.width = closeBtnOptimalSize.x;
+			childData.area.height = closeBtnOptimalSize.y;
+			childData.clipRect.x -= childData.area.x;
+			childData.clipRect.y -= childData.area.y;
+
+			mCloseBtn->_setLayoutData(childData);
 		}
 	}
 
@@ -381,8 +386,7 @@ namespace BansheeEngine
 
 			mDraggedBtn = mTabButtons[seqIdx];
 
-			Vector2I offset = mDraggedBtn->_getOffset();
-			mInitialDragOffset = (startDragPos.x - offset.x);
+			mInitialDragOffset = (startDragPos.x - mDraggedBtn->_getLayoutData().area.x);
 
 			mDragInProgress = true;
 		}
@@ -403,7 +407,7 @@ namespace BansheeEngine
 		INT32 idx = uniqueIdxToSeqIdx(tabIdx);
 		if(idx != -1)
 		{
-			Rect2I bounds = _getCachedBounds();
+			Rect2I bounds = _getLayoutData().area;
 			if(bounds.contains(dragPos))
 			{
 				if(!mDragInProgress)
@@ -413,8 +417,8 @@ namespace BansheeEngine
 
 				for(INT32 i = 0; i < idx; i++)
 				{
-					UINT32 width = mTabButtons[i]->_getWidth();
-					INT32 centerX = mTabButtons[i]->_getOffset().x + width / 2;
+					UINT32 width = mTabButtons[i]->_getLayoutData().area.width;
+					INT32 centerX = mTabButtons[i]->_getLayoutData().area.x + width / 2;
 
 					if(dragPos.x < centerX)
 					{
@@ -428,8 +432,8 @@ namespace BansheeEngine
 
 				for(UINT32 i = idx + 1; i < (UINT32)mTabButtons.size(); i++)
 				{
-					UINT32 width = mTabButtons[i]->_getWidth();
-					INT32 centerX = mTabButtons[i]->_getOffset().x + width / 2;
+					UINT32 width = mTabButtons[i]->_getLayoutData().area.width;
+					INT32 centerX = mTabButtons[i]->_getLayoutData().area.x + width / 2;
 
 					if(dragPos.x > centerX)
 					{
@@ -441,12 +445,12 @@ namespace BansheeEngine
 					}
 				}
 
-				markContentAsDirty();
+				_markContentAsDirty();
 			}
 			else
 			{
 				endDrag();
-				markContentAsDirty();
+				_markContentAsDirty();
 
 				if(!onTabDraggedOff.empty())
 					onTabDraggedOff(tabIdx);
@@ -461,7 +465,7 @@ namespace BansheeEngine
 		if(mActiveTabIdx != tabIdx)
 			tabToggled(tabIdx, true);
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	INT32 GUITabbedTitleBar::uniqueIdxToSeqIdx(UINT32 uniqueIdx) const

+ 8 - 11
BansheeEditor/Source/BsGUITextField.cpp

@@ -163,20 +163,17 @@ namespace BansheeEngine
 		mInputBox->setTint(color);
 	}
 
-	void GUITextField::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-		Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUITextField::_updateLayoutInternal(const GUILayoutData& data)
 	{
-		mLayout->_setPosition(Vector2I(x, y));
-		mLayout->_setWidth(width);
-		mLayout->_setHeight(height);
-		mLayout->_setWidgetDepth(widgetDepth);
-		mLayout->_setAreaDepth(panelDepth);
-		mLayout->_setPanelDepthRange(panelDepthRangeMin, panelDepthRangeMax);
+		GUILayoutData childData = data;
+		childData.clipRect.x -= data.area.x;
+		childData.clipRect.y -= data.area.y;
 
-		Rect2I elemClipRect(clipRect.x - x, clipRect.y - y, clipRect.width, clipRect.height);
-		mLayout->_setClipRect(elemClipRect);
+		mLayout->_setLayoutData(childData);
 
-		mLayout->_updateLayoutInternal(x, y, width, height, clipRect, widgetDepth, panelDepth, panelDepthRangeMin, panelDepthRangeMax);
+		childData.clipRect = data.clipRect;
+
+		mLayout->_updateLayoutInternal(childData);
 	}
 
 	Vector2I GUITextField::_getOptimalSize() const

+ 69 - 79
BansheeEditor/Source/BsGUITreeView.cpp

@@ -207,7 +207,7 @@ namespace BansheeEngine
 				treeElement = element->getTreeElement();
 			}
 
-			if(treeElement != nullptr && event.getPosition().x >= treeElement->mElement->_getCachedBounds().x)
+			if(treeElement != nullptr && event.getPosition().x >= treeElement->mElement->_getLayoutData().area.x)
 			{
 				if(event.isCtrlDown())
 				{
@@ -280,7 +280,7 @@ namespace BansheeEngine
 					selectElement(treeElement);
 				}
 
-				markContentAsDirty();
+				_markContentAsDirty();
 
 				return true;
 			}
@@ -319,7 +319,7 @@ namespace BansheeEngine
 					mDragPosition = event.getPosition();
 					mDragInProgress = true;
 					mScrollState = ScrollState::None;
-					markContentAsDirty();
+					_markContentAsDirty();
 				}
 			}
 		}
@@ -329,7 +329,7 @@ namespace BansheeEngine
 			{
 				mDragPosition = event.getPosition();
 				mDragInProgress = true;
-				markContentAsDirty();
+				_markContentAsDirty();
 
 				if(mBottomScrollBounds.contains(mDragPosition))
 				{
@@ -371,7 +371,7 @@ namespace BansheeEngine
 		else if(event.getType() == GUIMouseEventType::MouseOut)
 		{
 			mDragInProgress = false;
-			markContentAsDirty();
+			_markContentAsDirty();
 		}
 
 		return false;
@@ -522,7 +522,7 @@ namespace BansheeEngine
 			GUIElement::destroy(iterFind->background);
 
 			mSelectedElements.erase(iterFind);
-			markContentAsDirty();
+			_markContentAsDirty();
 
 			selectionChanged();
 		}
@@ -541,7 +541,7 @@ namespace BansheeEngine
 		mSelectedElements.clear();
 		mIsElementSelected = false;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 
 		selectionChanged();
 	}
@@ -691,7 +691,7 @@ namespace BansheeEngine
 				unselectElement(element);
 		}
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUITreeView::elementToggled(TreeElement* element, bool toggled)
@@ -820,15 +820,16 @@ namespace BansheeEngine
 
 	void GUITreeView::updateClippedBounds()
 	{
-		Vector2I offset = _getOffset();
-		mClippedBounds = Rect2I(offset.x, offset.y, _getWidth(), _getHeight());
+		mClippedBounds = mLayoutData.area;
+
+		Rect2I localClipRect = mLayoutData.clipRect;
+		localClipRect.x += mLayoutData.area.x;
+		localClipRect.y += mLayoutData.area.y;
 
-		Rect2I localClipRect(mClipRect.x + mOffset.x, mClipRect.y + mOffset.y, mClipRect.width, mClipRect.height);
 		mClippedBounds.clip(localClipRect);
 	}
 
-	void GUITreeView::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-		Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUITreeView::_updateLayoutInternal(const GUILayoutData& data)
 	{
 		struct UpdateTreeElement
 		{
@@ -850,7 +851,7 @@ namespace BansheeEngine
 
 		Vector<TreeElement*> tempOrderedElements;
 
-		Vector2I offset(x, y);
+		Vector2I offset(data.area.x, data.area.y);
 
 		while(!todo.empty())
 		{
@@ -866,20 +867,21 @@ namespace BansheeEngine
 				Vector2I elementSize = current->mElement->_getOptimalSize();
 				btnHeight = elementSize.y;
 
-				mVisibleElements.push_back(InteractableElement(current->mParent, current->mSortedIdx * 2 + 0, Rect2I(x, offset.y, width, ELEMENT_EXTRA_SPACING)));
-				mVisibleElements.push_back(InteractableElement(current->mParent, current->mSortedIdx * 2 + 1, Rect2I(x, offset.y + ELEMENT_EXTRA_SPACING, width, btnHeight)));
+				mVisibleElements.push_back(InteractableElement(current->mParent, current->mSortedIdx * 2 + 0, Rect2I(data.area.x, offset.y, data.area.width, ELEMENT_EXTRA_SPACING)));
+				mVisibleElements.push_back(InteractableElement(current->mParent, current->mSortedIdx * 2 + 1, Rect2I(data.area.x, offset.y + ELEMENT_EXTRA_SPACING, data.area.width, btnHeight)));
 
-				offset.x = x + INITIAL_INDENT_OFFSET + indent * INDENT_SIZE;
+				offset.x = data.area.x + INITIAL_INDENT_OFFSET + indent * INDENT_SIZE;
 				offset.y += ELEMENT_EXTRA_SPACING;
 
-				current->mElement->_setPosition(offset);
-				current->mElement->_setWidth(elementSize.x);
-				current->mElement->_setHeight(elementSize.y);
-				current->mElement->_setAreaDepth(panelDepth);
-				current->mElement->_setWidgetDepth(widgetDepth);
+				GUILayoutData childData = data;
+				childData.area.x = offset.x;
+				childData.area.y = offset.y;
+				childData.area.width = elementSize.x;
+				childData.area.height = elementSize.y;
+				childData.clipRect.x -= offset.x;
+				childData.clipRect.y -= offset.y;
 
-				Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-				current->mElement->_setClipRect(elemClipRect);
+				current->mElement->_setLayoutData(childData);
 
 				yOffset = btnHeight;
 			}
@@ -900,14 +902,15 @@ namespace BansheeEngine
 					myOffset.y -= Math::floorToInt(half);
 				}
 
-				current->mFoldoutBtn->_setPosition(myOffset);
-				current->mFoldoutBtn->_setWidth(elementSize.x);
-				current->mFoldoutBtn->_setHeight(elementSize.y);
-				current->mFoldoutBtn->_setAreaDepth(panelDepth);
-				current->mFoldoutBtn->_setWidgetDepth(widgetDepth);
+				GUILayoutData childData = data;
+				childData.area.x = myOffset.x;
+				childData.area.y = myOffset.y;
+				childData.area.width = elementSize.x;
+				childData.area.height = elementSize.y;
+				childData.clipRect.x -= myOffset.x;
+				childData.clipRect.y -= myOffset.y;
 
-				Rect2I elemClipRect(clipRect.x - myOffset.x, clipRect.y - myOffset.y, clipRect.width, clipRect.height);
-				current->mFoldoutBtn->_setClipRect(elemClipRect);
+				current->mFoldoutBtn->_setLayoutData(childData);
 			}
 
 			offset.y += yOffset;
@@ -929,44 +932,37 @@ namespace BansheeEngine
 			}
 		}
 
-		UINT32 remainingHeight = (UINT32)std::max(0, (INT32)height - (offset.y - y));
+		UINT32 remainingHeight = (UINT32)std::max(0, (INT32)data.area.height - (offset.y - data.area.y));
 
 		if(remainingHeight > 0)
-			mVisibleElements.push_back(InteractableElement(&getRootElement(), (UINT32)getRootElement().mChildren.size() * 2, Rect2I(x, offset.y, width, remainingHeight)));
+			mVisibleElements.push_back(InteractableElement(&getRootElement(), (UINT32)getRootElement().mChildren.size() * 2, Rect2I(data.area.x, offset.y, data.area.width, remainingHeight)));
 
 		for(auto selectedElem : mSelectedElements)
 		{
 			GUILabel* targetElement = selectedElem.element->mElement;
 
-			Vector2I offset = targetElement->_getOffset();
-			offset.x = x;
-
-			selectedElem.background->_setPosition(offset);
-			selectedElem.background->_setWidth(width);
-			selectedElem.background->_setHeight(targetElement->_getHeight());
-			selectedElem.background->_setAreaDepth(panelDepth);
-			selectedElem.background->_setWidgetDepth(widgetDepth);
+			GUILayoutData childData = data;
+			childData.area.y = targetElement->_getLayoutData().area.y;
+			childData.area.height = targetElement->_getLayoutData().area.height;
+			childData.clipRect.x -= childData.area.x;
+			childData.clipRect.y -= childData.area.y;
 
-			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-			selectedElem.background->_setClipRect(elemClipRect);
+			selectedElem.background->_setLayoutData(childData);
 		}
 
 		if(mEditElement != nullptr)
 		{
 			GUILabel* targetElement = mEditElement->mElement;
 
-			Vector2I offset = targetElement->_getOffset();
-			UINT32 remainingWidth = (UINT32)std::max(0, (((INT32)width) - (offset.x - x)));
-
-			mNameEditBox->_setPosition(offset);
-			mNameEditBox->_setWidth(remainingWidth);
-			mNameEditBox->_setHeight(targetElement->_getHeight());
-			mNameEditBox->_setAreaDepth(panelDepth);
-			mNameEditBox->_setWidgetDepth(widgetDepth);
+			UINT32 remainingWidth = (UINT32)std::max(0, (((INT32)data.area.width) - (offset.x - data.area.x)));
 
-			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-			mNameEditBox->_setClipRect(elemClipRect);
+			GUILayoutData childData = data;
+			childData.area = targetElement->_getLayoutData().area;
+			childData.area.width = remainingWidth;
+			childData.clipRect.x -= childData.area.x;
+			childData.clipRect.y -= childData.area.y;
 
+			mNameEditBox->_setLayoutData(childData);
 		}
 
 		if(mDragInProgress)
@@ -991,15 +987,12 @@ namespace BansheeEngine
 					if(mDragHighlight->_isDisabled())
 						mDragHighlight->enableRecursively();
 
-					Vector2I offset(interactableElement->bounds.x, interactableElement->bounds.y);
-					mDragHighlight->_setPosition(offset);
-					mDragHighlight->_setWidth(interactableElement->bounds.width);
-					mDragHighlight->_setHeight(interactableElement->bounds.height);
-					mDragHighlight->_setAreaDepth(panelDepth);
-					mDragHighlight->_setWidgetDepth(widgetDepth);
+					GUILayoutData childData = data;
+					childData.area = interactableElement->bounds;
+					childData.clipRect.x -= childData.area.x;
+					childData.clipRect.y -= childData.area.y;
 
-					Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-					mDragHighlight->_setClipRect(elemClipRect);
+					mDragHighlight->_setLayoutData(childData);
 				}
 				else
 				{
@@ -1009,15 +1002,12 @@ namespace BansheeEngine
 					if(mDragSepHighlight->_isDisabled())
 						mDragSepHighlight->enableRecursively();
 
-					Vector2I offset(interactableElement->bounds.x, interactableElement->bounds.y);
-					mDragSepHighlight->_setPosition(offset);
-					mDragSepHighlight->_setWidth(interactableElement->bounds.width);
-					mDragSepHighlight->_setHeight(interactableElement->bounds.height);
-					mDragSepHighlight->_setAreaDepth(panelDepth);
-					mDragSepHighlight->_setWidgetDepth(widgetDepth);
+					GUILayoutData childData = data;
+					childData.area = interactableElement->bounds;
+					childData.clipRect.x -= childData.area.x;
+					childData.clipRect.y -= childData.area.y;
 
-					Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-					mDragSepHighlight->_setClipRect(elemClipRect);
+					mDragSepHighlight->_setLayoutData(childData);
 				}
 			}
 		}
@@ -1031,16 +1021,16 @@ namespace BansheeEngine
 		}
 
 		// Update scroll bounds
-		UINT32 scrollHeight = (UINT32)Math::roundToInt(clipRect.height * SCROLL_AREA_HEIGHT_PCT);
+		UINT32 scrollHeight = (UINT32)Math::roundToInt(data.clipRect.height * SCROLL_AREA_HEIGHT_PCT);
 
-		mTopScrollBounds.x = clipRect.x;
-		mTopScrollBounds.y = clipRect.y;
-		mTopScrollBounds.width = clipRect.width;
+		mTopScrollBounds.x = data.clipRect.x;
+		mTopScrollBounds.y = data.clipRect.y;
+		mTopScrollBounds.width = data.clipRect.width;
 		mTopScrollBounds.height = scrollHeight;
 
-		mBottomScrollBounds.x = clipRect.x;
-		mBottomScrollBounds.y = clipRect.y + clipRect.height - scrollHeight;
-		mBottomScrollBounds.width = clipRect.width;
+		mBottomScrollBounds.x = data.clipRect.x;
+		mBottomScrollBounds.y = data.clipRect.y + data.clipRect.height - scrollHeight;
+		mBottomScrollBounds.width = data.clipRect.width;
 		mBottomScrollBounds.height = scrollHeight;
 	}
 
@@ -1183,7 +1173,7 @@ namespace BansheeEngine
 		{
 			Rect2I myBounds = _getClippedBounds();
 			INT32 clipVertCenter = myBounds.y + (INT32)Math::roundToInt(myBounds.height * 0.5f);
-			INT32 elemVertCenter = element->mElement->_getOffset().y + (INT32)Math::roundToInt(element->mElement->_getHeight() * 0.5f);
+			INT32 elemVertCenter = element->mElement->_getLayoutData().area.y + (INT32)Math::roundToInt(element->mElement->_getLayoutData().area.height * 0.5f);
 
 			if(elemVertCenter > clipVertCenter)
 				scrollArea->scrollUpPx(elemVertCenter - clipVertCenter);
@@ -1193,8 +1183,8 @@ namespace BansheeEngine
 		else
 		{
 			Rect2I myBounds = _getClippedBounds();
-			INT32 elemVertTop = element->mElement->_getOffset().y;
-			INT32 elemVertBottom = element->mElement->_getOffset().y + element->mElement->_getHeight();
+			INT32 elemVertTop = element->mElement->_getLayoutData().area.y;
+			INT32 elemVertBottom = element->mElement->_getLayoutData().area.y + element->mElement->_getLayoutData().area.height;
 
 			INT32 top = myBounds.y;
 			INT32 bottom = myBounds.y + myBounds.height;

+ 1 - 1
BansheeEditor/Source/BsGUIWindowDropArea.cpp

@@ -41,7 +41,7 @@ namespace BansheeEngine
 		else
 			mActiveTexture = _getStyle()->normal.texture;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	bool GUIWindowDropArea::_mouseEvent(const GUIMouseEvent& ev)

+ 1 - 1
BansheeEditor/Source/BsGUIWindowFrame.cpp

@@ -44,6 +44,6 @@ namespace BansheeEngine
 		else
 			mActiveTexture = _getStyle()->normal.texture;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 }

+ 1 - 0
BansheeEngine/BansheeEngine.vcxproj

@@ -263,6 +263,7 @@
     <ClInclude Include="Include\BsDrawHelper.h" />
     <ClInclude Include="Include\BsGUIDropDownContent.h" />
     <ClInclude Include="Include\BsGUIElementStyleRTTI.h" />
+    <ClInclude Include="Include\BsGUILayoutData.h" />
     <ClInclude Include="Include\BsGUIPanel.h" />
     <ClInclude Include="Include\BsGUIProgressBar.h" />
     <ClInclude Include="Include\BsGUISkinRTTI.h" />

+ 3 - 0
BansheeEngine/BansheeEngine.vcxproj.filters

@@ -329,6 +329,9 @@
     <ClInclude Include="Include\BsGUIPanel.h">
       <Filter>Header Files\GUI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsGUILayoutData.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsGUIElement.cpp">

+ 1 - 2
BansheeEngine/Include/BsGUIDropDownContent.h

@@ -98,8 +98,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	GUIElementContainer::_updateLayoutInternal
 		 */
-		void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax) override;
+		void _updateLayoutInternal(const GUILayoutData& data) override;
 
 		/**
 		 * @copydoc	GUIElementContainer::styleUpdated

+ 4 - 13
BansheeEngine/Include/BsGUIElement.h

@@ -58,7 +58,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	GUIElementBase::getVisibleBounds
 		 */
-		Rect2I getVisibleBounds() const override;
+		Rect2I getVisibleBounds() override;
 
 		/**
 		 * @brief	Destroy the element. Removes it from parent and widget, and queues
@@ -187,18 +187,9 @@ namespace BansheeEngine
 		void _setElementDepth(UINT8 depth);
 
 		/**
-		 * @copydoc GUIElementBase::_setClipRect
+		 * @copydoc	GUIElementBase::_setLayoutData
 		 */
-		void _setClipRect(const Rect2I& clipRect) override;
-
-		/**
-		 * @brief	Gets non-clipped bounds that were assigned to the element by the parent layout.
-		 *
-		 * @note	This value is updated during layout update which means it might be out of date
-		 *			if parent element bounds changed since.
-		 *			Internal method.
-		 */
-		Rect2I _getCachedBounds() const;
+		virtual void _setLayoutData(const GUILayoutData& data) override;
 
 		/**
 		 * @copydoc	GUIElementBase::_changeParentWidget
@@ -274,7 +265,7 @@ namespace BansheeEngine
 		 *
 		 * @note	Internal method.
 		 */
-		UINT32 _getDepth() const { return mDepth; }
+		UINT32 _getDepth() const { return mLayoutData.depth; }
 
 		/**
 		 * @brief	Checks is the specified position within GUI element bounds. Position is relative to

+ 24 - 130
BansheeEngine/Include/BsGUIElementBase.h

@@ -3,6 +3,7 @@
 #include "BsPrerequisites.h"
 #include "BsGUIMaterialInfo.h"
 #include "BsGUIDimensions.h"
+#include "BsGUILayoutData.h"
 #include "BsRect2I.h"
 #include "BsVector2I.h"
 #include "BsRectOffset.h"
@@ -82,42 +83,35 @@ namespace BansheeEngine
 		/**
 		 * @brief	Returns non-clipped bounds of the GUI element. Relative to the parent GUI panel.
 		 *
-		 * @note	This call can be potentially expensive as the bounds need to be calculated based on current GUI state.
+		 * @param	relativeTo	Parent panel of the provided element relative to which to return the
+		 *						bounds. If null the bounds relative to the first parent panel are returned.
+		 *						Behavior is undefined if provided panel is not a parent of the element.
+		 *
+		 * @note	This call can be potentially expensive if the GUI state is dirty.
 		 */
-		virtual Rect2I getBounds() const;
+		Rect2I getBounds(GUIPanel* relativeTo = nullptr);
 
 		/**
 		 * @brief	Returns non-clipped visible bounds of the GUI element (bounds exclude the margins). Relative to the parent GUI panel.
 		 *
 		 * @note	This call can be potentially expensive as the bounds need to be calculated based on current GUI state.
 		 */
-		virtual Rect2I getVisibleBounds() const;
+		virtual Rect2I getVisibleBounds();
 
 		/************************************************************************/
 		/* 							INTERNAL METHODS                      		*/
 		/************************************************************************/
 
 		/**
-		 * @brief	Updates child elements positions, sizes, clip rectanges and depths so they
+		 * @brief	Updates child elements positions, sizes, clip rectangles and depths so they
 		 *			fit into the provided bounds, while respecting their layout options. 
 		 *
-		 * @param	x					X position of the area to start laying out the elements. Relative to parent widget.
-		 * @param	y					Y position of the area to start laying out the elements. Relative to parent widget.
-		 * @param	width				Width of the area to lay out the elements, in pixels.
-		 * @param	height				Height of the area to lay out the elements, in pixels.
-		 * @param	clipRect			Rectangle to use for clipping of GUI elements. Any element outside of this rectangle will have its
-		 *								visible geometry clipped. In coordinates relative to parent widget.
-		 * @param	widgetDepth			Depth of the parent widget, will be set for all child elements.
-		 * @param	panelDepth			Depth of the parent panel, will be set for all child elements.
-		 * @param	panelDepthRangeMin  Minimum depth range that child GUI panels can have (relative to panelDepth).
-		 *								Values outside of the depth range will be clamped.
-		 * @param	panelDepthRangeMax	Maximum depth range that child GUI panels can have (relative to panelDepth).
-		 *								Values outside of the depth range will be clamped.
+		 * @param	data	Layout data containing the necessary bounds and restrictions
+		 *					to use for calculating the child element layout data.
 		 *
 		 * @note	Internal method.
 		 */
-		virtual void _updateLayout(INT32 x, INT32 y, UINT32 width, UINT32 height, 
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		virtual void _updateLayout(const GUILayoutData& data);
 
 		/**
 		 * @brief	Calculates optimal sizes of all child elements, as determined by their style and layout options.
@@ -131,129 +125,35 @@ namespace BansheeEngine
 		 *
 		 * @note	Internal method.
 		 */
-		virtual void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		virtual void _updateLayoutInternal(const GUILayoutData& data);
 
 		/**
 		 * @brief	Calculates positions & sizes of all elements in the layout. This method expects a pre-allocated array to store the data in.
 		 *
-		 * @brief	x				Start X coordinate of the layout area. First element will be placed here. Relative to parent widget.
-		 * @brief	y				Start Y coordinate of the layout area. First element will be placed here. Relative to parent widget.
-		 * @param	width			Available width for the layout elements.
-		 * @param	height			Available height for the layout elements.
+		 * @brief	layoutArea		Parent layout area to position the child elements in.
 		 * @param	elementAreas	Array to hold output areas. Must be the same size as the number of child elements.
 		 * @param	numElements		Size of the element areas array.
 		 * @param	sizeRanges		Ranges of possible sizes used for the child elements. Array must be same size as elements array.
 		 * @param	mySizeRange		Size range of this element.
 		 */
-		virtual void _getElementAreas(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I* elementAreas, UINT32 numElements, 
+		virtual void _getElementAreas(const Rect2I& layoutArea, Rect2I* elementAreas, UINT32 numElements,
 			const Vector<LayoutSizeRange>& sizeRanges, const LayoutSizeRange& mySizeRange) const;
 
 		/**
-		 * @brief	Sets element position relative to widget origin. This will be the position used directly for rendering.
-		 *
-		 * @note	Internal method.
-		 */
-		virtual void _setPosition(const Vector2I& offset);
-
-		/**
-		 * @brief	Sets element width in pixels. This will be the width used directly for rendering.
+		 * @brief	Updates layout data that determines GUI elements final position & depth 
+		 *			in the GUI widget.
 		 *
 		 * @note	Internal method.
 		 */
-		virtual void _setWidth(UINT32 width);
+		virtual void _setLayoutData(const GUILayoutData& data) { mLayoutData = data; }
 
 		/**
-		 * @brief	Sets element height in pixels. This will be the height used directly for rendering.
+		 * @brief	Retrieves layout data that determines GUI elements final position & depth
+		 *			in the GUI widget.
 		 *
 		 * @note	Internal method.
 		 */
-		virtual void _setHeight(UINT32 height);
-
-		/**
-		 * @brief	Set widget part of element depth. (Most significant part)
-		 *
-		 * @note	Internal method.
-		 */
-		void _setWidgetDepth(UINT8 depth);
-
-		/**
-		 * @brief	Set area part of element depth. Less significant than widget
-		 *			depth but more than custom element depth.
-		 *
-		 * @note	Internal method.
-		 */
-		void _setAreaDepth(INT16 depth);
-
-		/**
-		 * @brief	Sets a clip rectangle that GUI element sprite will be clipped to. 
-		 *			Rectangle is in local coordinates. (Relative to element position)
-		 *
-		 * @note	Internal method.
-		 */
-		virtual void _setClipRect(const Rect2I& clipRect);
-
-		/**
-		 * @brief	Sets the panel depth range that children of this element are allowed
-		 *			to be placed in.
-		 */
-		void _setPanelDepthRange(UINT16 min, UINT16 max);
-
-		/**
-		 * @brief	Retrieves the panel depth range that children of this element are allowed
-		 *			to be placed in.
-		 */
-		void _getPanelDepthRange(UINT16& min, UINT16& max);
-
-		/**
-		 * @brief	Returns width of the element in pixels.
-		 *
-		 * @note	This value is updated during layout update which means it might be out of date
-		 *			if parent element bounds changed since.
-		 *			Internal method:
-		 */
-		UINT32 _getWidth() const { return mWidth; }
-
-		/**
-		 * @brief	Returns height of the element in pixels.
-		 *
-		 * @note	This value is updated during layout update which means it might be out of date
-		 *			if parent element bounds changed since.
-		 *			Internal method:
-		 */
-		UINT32 _getHeight() const { return mHeight; }
-
-		/**
-		 * @brief	Returns position of the element, relative to parent GUI widget origin.
-		 *
-		 * @note	This value is updated during layout update which means it might be out of date
-		 *			if parent element bounds changed since.
-		 *			Internal method:
-		 */
-		Vector2I _getOffset() const { return mOffset; }
-
-		/**
-		 * @brief	Set widget part of element depth. (Most significant part)
-		 *
-		 * @note	Internal method.
-		 */
-		UINT8 _getWidgetDepth() const;
-
-		/**
-		 * @brief	Set area part of element depth. Less significant than widget
-		 *			depth but more than custom element depth.
-		 *
-		 * @note	Internal method.
-		 */
-		INT16 _getAreaDepth() const;
-
-		/**
-		 * @brief	Returns clip rect used for clipping the GUI element and related sprites
-		 *			to a specific region. Clip rect is relative to GUI element origin.
-		 *
-		 * @note	Internal method.
-		 */
-		const Rect2I& _getClipRect() const { return mClipRect; }
+		const GUILayoutData& _getLayoutData() const { return mLayoutData; }
 
 		/**
 		 * @brief	Sets a new parent for this element.
@@ -375,7 +275,7 @@ namespace BansheeEngine
 		 *
 		 * @note	Internal method.
 		 */
-		void markContentAsDirty();
+		void _markContentAsDirty();
 
 		/**
 		 * @brief	Mark only the elements that operate directly on the sprite mesh without requiring the mesh
@@ -383,7 +283,7 @@ namespace BansheeEngine
 		 *
 		 * @note	Internal method.
 		 */
-		void markMeshAsDirty();
+		void _markMeshAsDirty();
 
 		/**
 		 * @brief	Returns true if elements contents have changed since last update.
@@ -443,12 +343,6 @@ namespace BansheeEngine
 		bool mIsDirty;
 
 		GUIDimensions mDimensions;
-
-		Vector2I mOffset;
-		UINT32 mWidth, mHeight;
-
-		Rect2I mClipRect;
-		UINT32 mPanelDepthRange;
-		UINT32 mDepth;
+		GUILayoutData mLayoutData;
 	};
 }

+ 51 - 0
BansheeEngine/Include/BsGUILayoutData.h

@@ -0,0 +1,51 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsRect2I.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Contains all attributes that are output by GUI layouts and
+	 *			assigned to GUI elements. This includes element position,
+	 *			size and depth.
+	 */
+	struct BS_EXPORT GUILayoutData
+	{
+		GUILayoutData()
+			:depthRangeMin(-1), depthRangeMax(-1), depth(0)
+		{ 
+			setPanelDepth(0);
+		}
+
+		void setWidgetDepth(UINT8 depth)
+		{
+			UINT32 shiftedDepth = depth << 24;
+
+			depth = shiftedDepth | (depth & 0x00FFFFFF);
+		}
+
+		void setPanelDepth(INT16 depth)
+		{
+			UINT32 signedDepth = ((INT32)depth + 32768) << 8;
+
+			depth = signedDepth | (depth & 0xFF0000FF);;
+		}
+
+		UINT8 getWidgetDepth() const
+		{
+			return (depth >> 24) & 0xFF;
+		}
+
+		INT16 getPanelDepth() const
+		{
+			return (((INT32)depth >> 8) & 0xFFFF) - 32768;
+		}
+
+		Rect2I area;
+		Rect2I clipRect;
+		UINT32 depth;
+		UINT16 depthRangeMin;
+		UINT16 depthRangeMax;
+	};
+}

+ 0 - 15
BansheeEngine/Include/BsGUILayoutUtility.h

@@ -18,21 +18,6 @@ namespace BansheeEngine
 		 */
 		static Vector2I calcOptimalSize(const GUIElementBase* elem);
 
-		/**
-		 * Calculates position and size of a GUI element in its current layout.
-		 * Returned position is relative to parent GUI panel.
-		 *
-		 * @param	elem		Element to calculate bounds for.
-		 * @param	relativeTo	Parent panel of the provided element relative to which to return the
-		 *						bounds. If null the bounds relative to the first parent panel are returned.
-		 *						Behavior is undefined if provided panel is not a parent of the element.
-		 */
-		// TODO - This method might fail if element is part of a more complex hierarchy
-		// other than just GUILayouts and base elements (e.g. a tree view) because for a lot
-		// of such custom container elements like tree view don't have method for calculating 
-		// element bounds implemented
-		static Rect2I calcBounds(const GUIElementBase* elem, GUIPanel* relativeTo = nullptr);
-
 		/**
 		 * @brief	Calculates the actual size of the layout taken up by all of its elements.
 		 *			

+ 3 - 16
BansheeEngine/Include/BsGUILayoutX.h

@@ -29,7 +29,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	GUILayout::_getElementAreas
 		 */
-		void _getElementAreas(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I* elementAreas, UINT32 numElements, 
+		void _getElementAreas(const Rect2I& layoutArea, Rect2I* elementAreas, UINT32 numElements,
 			const Vector<LayoutSizeRange>& sizeRanges, const LayoutSizeRange& mySizeRange) const;
 
 		/**
@@ -51,21 +51,8 @@ namespace BansheeEngine
 
 	protected:
 		/**
-		 * @brief	Positions/size all child layout elements based on the provided settings and their (previously calculated) optimal sizes.
-		 *
-		 * @param	x					Start X coordinate of the layout area. First element will be placed here. Relative to parent widget.
-		 * @param	y					Start Y coordinate of the layout area. First element will be placed here. Relative to parent widget.
-		 * @param	width				Maximum width of the layout in pixels. Elements will be optimized so they best fit within this width if possible.
-		 * @param	height				Maximum height of the layout in pixels. Elements will be optimized so they best fit within this height if possible.
-		 * @param	clipRect			Rectangle to clip all child elements to. Relative to parent widget. Usually equal to specified x, y, width, height parameters.
-		 * @param	widgetDepth			Depth of the parent widget. Determines depth at which child elements will be placed on. Takes priority over any other depth.
-		 * @param	panelDepth			Depth of the parent panel, will be set for all child elements.
-		 * @param	panelDepthRangeMin  Minimum depth range that child GUI panels can have (relative to panelDepth).
-		 *								Values outside of the depth range will be clamped.
-		 * @param	panelDepthRangeMax	Maximum depth range that child GUI panels can have (relative to panelDepth).
-		 *								Values outside of the depth range will be clamped.
+		 * @copydoc	GUIElementBase::_updateLayoutInternal
 		 */
-		void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I clipRect, UINT8 widgetDepth, 
-			INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		void _updateLayoutInternal(const GUILayoutData& data);
 	};
 }

+ 3 - 16
BansheeEngine/Include/BsGUILayoutY.h

@@ -29,7 +29,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	GUILayout::_getElementAreas
 		 */
-		void _getElementAreas(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I* elementAreas, UINT32 numElements, 
+		void _getElementAreas(const Rect2I& layoutArea, Rect2I* elementAreas, UINT32 numElements, 
 			const Vector<LayoutSizeRange>& sizeRanges, const LayoutSizeRange& mySizeRange) const;
 
 		/**
@@ -51,21 +51,8 @@ namespace BansheeEngine
 
 	protected:
 		/**
-		 * @brief	Positions/size all child layout elements based on the provided settings and their (previously calculated) optimal sizes.
-		 *
-		 * @param	x					Start X coordinate of the layout area. First element will be placed here. Relative to parent widget.
-		 * @param	y					Start Y coordinate of the layout area. First element will be placed here. Relative to parent widget.
-		 * @param	width				Maximum width of the layout in pixels. Elements will be optimized so they best fit within this width if possible.
-		 * @param	height				Maximum height of the layout in pixels. Elements will be optimized so they best fit within this height if possible.
-		 * @param	clipRect			Rectangle to clip all child elements to. Relative to parent widget. Usually equal to specified x, y, width, height parameters.
-		 * @param	widgetDepth			Depth of the parent widget. Determines depth at which child elements will be placed on. Takes priority over any other depth.
-		 * @param	panelDepth			Depth of the parent panel, will be set for all child elements.
-		 * @param	panelDepthRangeMin  Minimum depth range that child GUI panels can have (relative to panelDepth).
-		 *								Values outside of the depth range will be clamped.
-		 * @param	panelDepthRangeMax	Maximum depth range that child GUI panels can have (relative to panelDepth).
-		 *								Values outside of the depth range will be clamped.
+		 * @copydoc	GUIElementBase::_updateLayoutInternal
 		 */
-		void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I clipRect, UINT8 widgetDepth, 
-			INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		void _updateLayoutInternal(const GUILayoutData& data);
 	};
 }

+ 5 - 19
BansheeEngine/Include/BsGUIPanel.h

@@ -34,7 +34,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	GUILayout::_getElementAreas
 		 */
-		void _getElementAreas(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I* elementAreas, UINT32 numElements, 
+		void _getElementAreas(const Rect2I& layoutArea, Rect2I* elementAreas, UINT32 numElements,
 			const Vector<LayoutSizeRange>& sizeRanges, const LayoutSizeRange& mySizeRange) const;
 
 		/**
@@ -42,7 +42,7 @@ namespace BansheeEngine
 		 *
 		 * @note	Internal method.
 		 */
-		Rect2I _getElementArea(INT32 x, INT32 y, UINT32 width, UINT32 height, const GUIElementBase* element, const LayoutSizeRange& sizeRange) const;
+		Rect2I _getElementArea(const Rect2I& layoutArea, const GUIElementBase* element, const LayoutSizeRange& sizeRange) const;
 
 		/**
 		 * @brief	Calculates an element size range for the provided child of the GUI panel. Will return cached bounds
@@ -57,8 +57,7 @@ namespace BansheeEngine
 		 *
 		 * @note	Internal method.
 		 */
-		void _updateChildLayout(GUIElementBase* element, const Rect2I& area, const Rect2I& clipRect, UINT8 widgetDepth,
-			INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		void _updateChildLayout(GUIElementBase* element, const GUILayoutData& data);
 
 		/**
 		 * @copydoc	GUILayout::_calcActualSize
@@ -122,22 +121,9 @@ namespace BansheeEngine
 
 	protected:
 		/**
-		 * @brief	Positions/size all child layout elements based on the provided settings and their (previously calculated) optimal sizes.
-		 *
-		 * @param	x					Start X coordinate of the layout area. First element will be placed here. Relative to parent widget.
-		 * @param	y					Start Y coordinate of the layout area. First element will be placed here. Relative to parent widget.
-		 * @param	width				Maximum width of the layout in pixels. Elements will be optimized so they best fit within this width if possible.
-		 * @param	height				Maximum height of the layout in pixels. Elements will be optimized so they best fit within this height if possible.
-		 * @param	clipRect			Rectangle to clip all child elements to. Relative to parent widget. Usually equal to specified x, y, width, height parameters.
-		 * @param	widgetDepth			Depth of the parent widget. Determines depth at which child elements will be placed on. Takes priority over any other depth.
-		 * @param	panelDepth			Depth of the parent panel, will be set for all child elements.
-		 * @param	panelDepthRangeMin  Minimum depth range that child GUI panels can have (relative to panelDepth).
-		 *								Values outside of the depth range will be clamped.
-		 * @param	panelDepthRangeMax	Maximum depth range that child GUI panels can have (relative to panelDepth).
-		 *								Values outside of the depth range will be clamped.
+		 * @copydoc	GUIElementBase::_updateLayoutInternal
 		 */
-		void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I clipRect, UINT8 widgetDepth, 
-			INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		void _updateLayoutInternal(const GUILayoutData& data);
 
 		INT16 mDepthOffset;
 		UINT16 mDepthRangeMin;

+ 1 - 2
BansheeEngine/Include/BsGUIProgressBar.h

@@ -77,8 +77,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	GUIElementContainer::_updateLayoutInternal
 		 */
-		virtual void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		virtual void _updateLayoutInternal(const GUILayoutData& data);
 
 		/**
 		 * @copydoc	GUIElementContainer::styleUpdated

+ 4 - 5
BansheeEngine/Include/BsGUIScrollArea.h

@@ -153,7 +153,7 @@ namespace BansheeEngine
 		 * @brief	Returns the bounds of the scroll area not including the scroll bars.
 		 *			(i.e. only the portion that contains the contents).
 		 */
-		Rect2I getContentBounds() const;
+		Rect2I getContentBounds();
 	protected:
 		~GUIScrollArea();
 
@@ -187,13 +187,12 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	GUIElementContainer::_updateLayoutInternal
 		 */
-		void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		void _updateLayoutInternal(const GUILayoutData& data);
 
 		/**
 		 * @copydoc	GUIElementContainer::_getElementAreas
 		 */
-		void _getElementAreas(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I* elementAreas, UINT32 numElements, 
+		void _getElementAreas(const Rect2I& layoutArea, Rect2I* elementAreas, UINT32 numElements, 
 			const Vector<LayoutSizeRange>& sizeRanges, const LayoutSizeRange& mySizeRange) const;
 
 		/**
@@ -201,7 +200,7 @@ namespace BansheeEngine
 		 *
 		 * @note	Also calculates some scroll area specific values.
 		 */
-		void _getElementAreas(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I* elementAreas, UINT32 numElements, 
+		void _getElementAreas(const Rect2I& layoutArea, Rect2I* elementAreas, UINT32 numElements, 
 			const Vector<LayoutSizeRange>& sizeRanges, Vector2I& visibleSize, Vector2I& contentSize) const;
 
 		ScrollBarType mVertBarType;

+ 1 - 2
BansheeEngine/Include/BsGUISlider.h

@@ -52,8 +52,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	GUIElementContainer::_updateLayoutInternal
 		 */
-		virtual void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		virtual void _updateLayoutInternal(const GUILayoutData& data);
 
 		/**
 		 * @copydoc	GUIElementContainer::styleUpdated

+ 1 - 1
BansheeEngine/Include/BsGUISpace.h

@@ -26,7 +26,7 @@ namespace BansheeEngine
 		/**
 		 * @brief	Changes the size of the space to the specified value, in pixels.
 		 */
-		void setSize(UINT32 size) { mSize = size; markContentAsDirty(); }
+		void setSize(UINT32 size) { mSize = size; _markContentAsDirty(); }
 
 		/**
 		 * @copydoc	GUIElementBase::_getType

+ 6 - 1
BansheeEngine/Include/BsGUIWidget.h

@@ -110,6 +110,11 @@ namespace BansheeEngine
 		 */
 		void _updateLayout();
 
+		/**
+		 * @brief	Updates the layout of the provided element, and queues content updates.
+		 */
+		void _updateLayout(GUIElementBase* elem);
+
 		/**
 		 * @brief	Forwards the specified mouse event to the specified element. The element
 		 * 			must be a child of this widget.
@@ -188,7 +193,7 @@ namespace BansheeEngine
 
 		HEvent mOwnerTargetResizedConn;
 
-		Vector<GUIElement*> mDirtyContents;
+		UnorderedSet<GUIElement*> mDirtyContents;
 
 		mutable bool mWidgetIsDirty;
 		mutable Rect2I mBounds;

+ 14 - 11
BansheeEngine/Source/BsGUIButtonBase.cpp

@@ -21,7 +21,7 @@ namespace BansheeEngine
 		if(SpriteTexture::checkIsLoaded(contentTex))
 			mContentImageSprite = bs_new<ImageSprite, PoolAlloc>();
 
-		mLocStringUpdatedConn = mContent.getText().addOnStringModifiedCallback(std::bind(&GUIButtonBase::markContentAsDirty, this));
+		mLocStringUpdatedConn = mContent.getText().addOnStringModifiedCallback(std::bind(&GUIButtonBase::_markContentAsDirty, this));
 	}
 
 	GUIButtonBase::~GUIButtonBase()
@@ -38,18 +38,18 @@ namespace BansheeEngine
 	void GUIButtonBase::setContent(const GUIContent& content)
 	{
 		mLocStringUpdatedConn.disconnect();
-		mLocStringUpdatedConn = content.getText().addOnStringModifiedCallback(std::bind(&GUIButtonBase::markContentAsDirty, this));
+		mLocStringUpdatedConn = content.getText().addOnStringModifiedCallback(std::bind(&GUIButtonBase::_markContentAsDirty, this));
 
 		mContent = content;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIButtonBase::setTint(const Color& color)
 	{
 		mColor = color;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIButtonBase::_setOn(bool on) 
@@ -107,8 +107,8 @@ namespace BansheeEngine
 
 	void GUIButtonBase::updateRenderElementsInternal()
 	{		
-		mImageDesc.width = mWidth;
-		mImageDesc.height = mHeight;
+		mImageDesc.width = mLayoutData.area.width;
+		mImageDesc.height = mLayoutData.area.height;
 
 		const HSpriteTexture& activeTex = getActiveTexture();
 		if(SpriteTexture::checkIsLoaded(activeTex))
@@ -142,10 +142,11 @@ namespace BansheeEngine
 
 	void GUIButtonBase::updateClippedBounds()
 	{
-		Vector2I offset = _getOffset();
-		mClippedBounds = Rect2I(offset.x, offset.y, _getWidth(), _getHeight());
+		mClippedBounds = mLayoutData.area;
 
-		Rect2I localClipRect(mClipRect.x + mOffset.x, mClipRect.y + mOffset.y, mClipRect.width, mClipRect.height);
+		Rect2I localClipRect = mLayoutData.clipRect;
+		localClipRect.x += mLayoutData.area.x;
+		localClipRect.y += mLayoutData.area.y;
 		mClippedBounds.clip(localClipRect);
 	}
 
@@ -194,8 +195,10 @@ namespace BansheeEngine
 
 		if(renderElementIdx < textSpriteIdx)
 		{
+			Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
+
 			mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, 
-				vertexStride, indexStride, renderElementIdx, mOffset, mClipRect);
+				vertexStride, indexStride, renderElementIdx, offset, mLayoutData.clipRect);
 
 			return;
 		}
@@ -329,7 +332,7 @@ namespace BansheeEngine
 	{
 		mActiveState = state;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	const HSpriteTexture& GUIButtonBase::getActiveTexture() const

+ 10 - 6
BansheeEngine/Source/BsGUIDropDownBox.cpp

@@ -110,17 +110,21 @@ namespace BansheeEngine
 		mHitBox = GUIDropDownHitBox::create(false);
 		mHitBox->onFocusLost.connect(std::bind(&GUIDropDownBox::dropDownFocusLost, this));
 		mHitBox->setFocus(true);
-		mHitBox->_setWidgetDepth(0);
-		mHitBox->_setAreaDepth(0);
+		GUILayoutData hitboxLayoutData = mHitBox->_getLayoutData();
+		hitboxLayoutData.setWidgetDepth(0);
+		hitboxLayoutData.setPanelDepth(0);
+		mHitBox->_setLayoutData(hitboxLayoutData);
 		mHitBox->_changeParentWidget(this);
-		mHitBox->markContentAsDirty();
+		mHitBox->_markContentAsDirty();
 
 		mCaptureHitBox = GUIDropDownHitBox::create(true);
 		mCaptureHitBox->setBounds(Rect2I(0, 0, target->getWidth(), target->getHeight()));
-		mCaptureHitBox->_setWidgetDepth(0);
-		mCaptureHitBox->_setAreaDepth(200);
+		GUILayoutData captureHitboxLayoutData = mCaptureHitBox->_getLayoutData();
+		captureHitboxLayoutData.setWidgetDepth(0);
+		captureHitboxLayoutData.setPanelDepth(200);
+		mCaptureHitBox->_setLayoutData(captureHitboxLayoutData);
 		mCaptureHitBox->_changeParentWidget(this);
-		mCaptureHitBox->markContentAsDirty();
+		mCaptureHitBox->_markContentAsDirty();
 
 		Rect2I availableBounds(target->getX(), target->getY(), target->getWidth(), target->getHeight());
 		mRootMenu = bs_new<DropDownSubMenu>(this, nullptr, placement, availableBounds, dropDownData, type, 0);

+ 21 - 28
BansheeEngine/Source/BsGUIDropDownContent.cpp

@@ -80,7 +80,7 @@ namespace BansheeEngine
 			[&](UINT32 idx, UINT32 visIdx)
 		{ 
 			setSelected(visIdx);
-			mParent->elementActivated(idx, mVisibleElements[visIdx].button->_getCachedBounds());
+			mParent->elementActivated(idx, mVisibleElements[visIdx].button->_getLayoutData().area);
 		};
 
 		// Remove all elements
@@ -133,7 +133,7 @@ namespace BansheeEngine
 			curVisIdx++;
 		}
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	UINT32 GUIDropDownContent::getElementHeight(UINT32 idx) const
@@ -199,7 +199,7 @@ namespace BansheeEngine
 			{
 				GUIDropDownDataEntry& entry = mDropDownData.entries[mVisibleElements[mSelectedIdx].idx];
 				if (entry.isSubMenu())
-					mParent->elementActivated(mVisibleElements[mSelectedIdx].idx, mVisibleElements[mSelectedIdx].button->_getCachedBounds());
+					mParent->elementActivated(mVisibleElements[mSelectedIdx].idx, mVisibleElements[mSelectedIdx].button->_getLayoutData().area);
 			}
 		}
 			return true;
@@ -207,7 +207,7 @@ namespace BansheeEngine
 			if (mSelectedIdx == UINT_MAX)
 				selectNext(0);
 			else
-				mParent->elementActivated(mVisibleElements[mSelectedIdx].idx, mVisibleElements[mSelectedIdx].button->_getCachedBounds());
+				mParent->elementActivated(mVisibleElements[mSelectedIdx].idx, mVisibleElements[mSelectedIdx].button->_getLayoutData().area);
 			return true;
 		}
 
@@ -326,17 +326,20 @@ namespace BansheeEngine
 
 	void GUIDropDownContent::updateClippedBounds()
 	{
-		Vector2I offset = _getOffset();
-		mClippedBounds = Rect2I(offset.x, offset.y, _getWidth(), _getHeight());
+		mClippedBounds = mLayoutData.area;
+
+		Rect2I localClipRect = mLayoutData.clipRect;
+		localClipRect.x += mLayoutData.area.x;
+		localClipRect.y += mLayoutData.area.y;
 
-		Rect2I localClipRect(mClipRect.x + mOffset.x, mClipRect.y + mOffset.y, mClipRect.width, mClipRect.height);
 		mClippedBounds.clip(localClipRect);
 	}
 
-	void GUIDropDownContent::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-		Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUIDropDownContent::_updateLayoutInternal(const GUILayoutData& data)
 	{
-		INT32 yOffset = y;
+		GUILayoutData childData = data;
+		INT32 yOffset = data.area.y;
+
 		for (auto& visElem : mVisibleElements)
 		{
 			const GUIDropDownDataEntry& element = mDropDownData.entries[visElem.idx];
@@ -347,30 +350,20 @@ namespace BansheeEngine
 			else
 				guiMainElement = visElem.button;
 
-			UINT32 elemHeight = getElementHeight(visElem.idx);
-			Vector2I offset(x, yOffset);
-			yOffset += elemHeight;
+			childData.area.y = yOffset;
+			childData.area.height = getElementHeight(visElem.idx);
+
+			yOffset += childData.area.height;
 
-			guiMainElement->_setPosition(offset);
-			guiMainElement->_setWidth(width);
-			guiMainElement->_setHeight(elemHeight);
-			guiMainElement->_setAreaDepth(panelDepth);
-			guiMainElement->_setWidgetDepth(widgetDepth);
+			childData.clipRect.x = data.clipRect.x - childData.area.x;
+			childData.clipRect.y = data.clipRect.y - childData.area.y;
 
-			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-			guiMainElement->_setClipRect(elemClipRect);
+			guiMainElement->_setLayoutData(childData);
 
 			// Shortcut label
 			GUILabel* shortcutLabel = visElem.shortcutLabel;
 			if (shortcutLabel != nullptr)
-			{
-				shortcutLabel->_setPosition(offset);
-				shortcutLabel->_setWidth(width);
-				shortcutLabel->_setHeight(elemHeight);
-				shortcutLabel->_setAreaDepth(panelDepth);
-				shortcutLabel->_setWidgetDepth(widgetDepth);
-				shortcutLabel->_setClipRect(elemClipRect);
-			}
+				shortcutLabel->_setLayoutData(childData);
 		}
 	}
 

+ 15 - 23
BansheeEngine/Source/BsGUIElement.cpp

@@ -57,17 +57,14 @@ namespace BansheeEngine
 
 	void GUIElement::_setElementDepth(UINT8 depth)
 	{
-		mDepth = depth | (mDepth & 0xFFFFFF00);
-		markMeshAsDirty();
+		mLayoutData.depth = depth | (mLayoutData.depth & 0xFFFFFF00);
+		_markMeshAsDirty();
 	}
 
-	void GUIElement::_setClipRect(const Rect2I& clipRect) 
-	{ 
-		if(mClipRect != clipRect)
-		{
-			mClipRect = clipRect; 
-			updateClippedBounds();
-		}
+	void GUIElement::_setLayoutData(const GUILayoutData& data)
+	{
+		GUIElementBase::_setLayoutData(data);
+		updateClippedBounds();
 	}
 
 	void GUIElement::_changeParentWidget(GUIWidget* widget)
@@ -94,11 +91,6 @@ namespace BansheeEngine
 		}
 	}
 
-	Rect2I GUIElement::_getCachedBounds() const
-	{
-		return Rect2I(mOffset.x, mOffset.y, mWidth, mHeight);
-	}
-
 	void GUIElement::setFocus(bool enabled)
 	{
 		GUIManager::instance().setFocus(this, enabled);
@@ -109,7 +101,7 @@ namespace BansheeEngine
 		mDimensions = GUIDimensions::create();
 		mDimensions.updateWithStyle(mStyle);
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	Rect2I GUIElement::getCachedVisibleBounds() const
@@ -128,11 +120,11 @@ namespace BansheeEngine
 	{
 		Rect2I bounds;
 
-		bounds.x = mOffset.x + mStyle->margins.left + mStyle->contentOffset.left;
-		bounds.y = mOffset.y + mStyle->margins.top + mStyle->contentOffset.top;
-		bounds.width = (UINT32)std::max(0, (INT32)mWidth - 
+		bounds.x = mLayoutData.area.x + mStyle->margins.left + mStyle->contentOffset.left;
+		bounds.y = mLayoutData.area.y + mStyle->margins.top + mStyle->contentOffset.top;
+		bounds.width = (UINT32)std::max(0, (INT32)mLayoutData.area.width -
 			(INT32)(mStyle->margins.left + mStyle->margins.right + mStyle->contentOffset.left + mStyle->contentOffset.right));
-		bounds.height = (UINT32)std::max(0, (INT32)mHeight - 
+		bounds.height = (UINT32)std::max(0, (INT32)mLayoutData.area.height -
 			(INT32)(mStyle->margins.top + mStyle->margins.bottom + mStyle->contentOffset.top + mStyle->contentOffset.bottom));
 
 		return bounds;
@@ -143,9 +135,9 @@ namespace BansheeEngine
 		Rect2I contentBounds = getCachedContentBounds();
 		
 		// Transform into element space so we can clip it using the element clip rectangle
-		Vector2I offsetDiff = Vector2I(contentBounds.x - mOffset.x, contentBounds.y - mOffset.y);
+		Vector2I offsetDiff = Vector2I(contentBounds.x - mLayoutData.area.x, contentBounds.y - mLayoutData.area.y);
 		Rect2I contentClipRect(offsetDiff.x, offsetDiff.y, contentBounds.width, contentBounds.height);
-		contentClipRect.clip(mClipRect);
+		contentClipRect.clip(mLayoutData.clipRect);
 
 		// Transform into content sprite space
 		contentClipRect.x -= offsetDiff.x;
@@ -175,7 +167,7 @@ namespace BansheeEngine
 			mDimensions.updateWithStyle(mStyle);
 			styleUpdated();
 
-			markContentAsDirty();
+			_markContentAsDirty();
 		}
 	}
 
@@ -202,7 +194,7 @@ namespace BansheeEngine
 		GUIManager::instance().queueForDestroy(element);
 	}
 
-	Rect2I GUIElement::getVisibleBounds() const
+	Rect2I GUIElement::getVisibleBounds()
 	{
 		Rect2I bounds = getBounds();
 

+ 56 - 83
BansheeEngine/Source/BsGUIElementBase.cpp

@@ -13,19 +13,17 @@ namespace BansheeEngine
 {
 	GUIElementBase::GUIElementBase()
 		:mIsDirty(true), mParentElement(nullptr), mIsDisabled(false), 
-		mParentWidget(nullptr), mWidth(0), mHeight(0), mAnchorParent(nullptr), 
-		mUpdateParent(nullptr), mPanelDepthRange(-1), mDepth(0)
+		mParentWidget(nullptr), mAnchorParent(nullptr), mUpdateParent(nullptr)
 	{
-		_setAreaDepth(0);
+
 	}
 
 	GUIElementBase::GUIElementBase(const GUIDimensions& dimensions)
 		:mIsDirty(true), mParentElement(nullptr), mIsDisabled(false),
-		mParentWidget(nullptr), mDimensions(dimensions), mWidth(0), 
-		mHeight(0), mAnchorParent(nullptr), mUpdateParent(nullptr), 
-		mPanelDepthRange(-1), mDepth(0)
+		mParentWidget(nullptr), mDimensions(dimensions), 
+		mAnchorParent(nullptr), mUpdateParent(nullptr)
 	{
-		_setAreaDepth(0);
+
 	}
 
 	GUIElementBase::~GUIElementBase()
@@ -61,7 +59,7 @@ namespace BansheeEngine
 		mDimensions.x = x;
 		mDimensions.y = y;
 
-		markMeshAsDirty();
+		_markMeshAsDirty();
 	}
 
 	void GUIElementBase::setWidth(UINT32 width)
@@ -76,7 +74,7 @@ namespace BansheeEngine
 		if (isFixedBefore != isFixedAfter)
 			refreshChildUpdateParents();
 			
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIElementBase::setFlexibleWidth(UINT32 minWidth, UINT32 maxWidth)
@@ -96,7 +94,7 @@ namespace BansheeEngine
 		if (isFixedBefore != isFixedAfter)
 			refreshChildUpdateParents();
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIElementBase::setHeight(UINT32 height)
@@ -111,7 +109,7 @@ namespace BansheeEngine
 		if (isFixedBefore != isFixedAfter)
 			refreshChildUpdateParents();
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIElementBase::setFlexibleHeight(UINT32 minHeight, UINT32 maxHeight)
@@ -131,7 +129,7 @@ namespace BansheeEngine
 		if (isFixedBefore != isFixedAfter)
 			refreshChildUpdateParents();
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIElementBase::resetDimensions()
@@ -145,88 +143,65 @@ namespace BansheeEngine
 		if (isFixedBefore != isFixedAfter)
 			refreshChildUpdateParents();
 
-		markContentAsDirty();
-	}
-
-	Rect2I GUIElementBase::getBounds() const
-	{
-		return GUILayoutUtility::calcBounds(this);
-	}
-
-	Rect2I GUIElementBase::getVisibleBounds() const
-	{
-		return getBounds();
-	}
-
-	void GUIElementBase::_setPosition(const Vector2I& offset)
-	{
-		mOffset = offset;
-	}
-
-	void GUIElementBase::_setWidth(UINT32 width)
-	{
-		mWidth = width;
-	}
-
-	void GUIElementBase::_setHeight(UINT32 height)
-	{
-		mHeight = height;
-	}
-
-	void GUIElementBase::_setWidgetDepth(UINT8 depth)
-	{
-		UINT32 shiftedDepth = depth << 24;
-
-		mDepth = shiftedDepth | (mDepth & 0x00FFFFFF);
+		_markContentAsDirty();
 	}
 
-	void GUIElementBase::_setAreaDepth(INT16 depth)
+	Rect2I GUIElementBase::getBounds(GUIPanel* relativeTo)
 	{
-		UINT32 signedDepth = ((INT32)depth + 32768) << 8;
+		if (relativeTo == nullptr)
+			relativeTo = mAnchorParent;
 
-		mDepth = signedDepth | (mDepth & 0xFF0000FF);;
-	}
+		Rect2I anchorBounds;
+		if (relativeTo != nullptr)
+			anchorBounds = relativeTo->getBounds();
 
-	void GUIElementBase::_setClipRect(const Rect2I& clipRect)
-	{
-		mClipRect = clipRect;
-	}
+		if (mUpdateParent != nullptr)
+		{
+			if (mUpdateParent->_isDirty() && mParentWidget != nullptr)
+			{
+				GUIElementBase* updateParent = mUpdateParent;
+				if (updateParent->_getType() == GUIElementBase::Type::Panel)
+				{
+					GUIElementBase* optimizedUpdateParent = this;
+					while (optimizedUpdateParent->_getParent() != updateParent)
+						optimizedUpdateParent = optimizedUpdateParent->_getParent();
 
-	void GUIElementBase::_setPanelDepthRange(UINT16 min, UINT16 max)
-	{
-		mPanelDepthRange = (min << 16) | max;
-	}
+					updateParent = optimizedUpdateParent;
+				}
 
-	void GUIElementBase::_getPanelDepthRange(UINT16& min, UINT16& max)
-	{
-		min = mPanelDepthRange >> 16;
-		max = mPanelDepthRange & 0xFFFF;
-	}
+				mParentWidget->_updateLayout(updateParent);
+			}
+		}
 
-	UINT8 GUIElementBase::_getWidgetDepth() const
-	{
-		return (mDepth >> 24) & 0xFF;
+		Rect2I bounds = mLayoutData.area;
+		bounds.x -= anchorBounds.x;
+		bounds.y -= anchorBounds.y;
+		
+		return bounds;
 	}
 
-	INT16 GUIElementBase::_getAreaDepth() const
+	Rect2I GUIElementBase::getVisibleBounds()
 	{
-		return (((INT32)mDepth >> 8) & 0xFFFF) - 32768;
+		return getBounds();
 	}
-
+	
 	void GUIElementBase::_markAsClean()
 	{
 		mIsDirty = false;
 	}
 
-	void GUIElementBase::markContentAsDirty() 
+	void GUIElementBase::_markContentAsDirty() 
 	{ 
 		if(_isDisabled())
 			return;
 
-		mIsDirty = true;
+		if (mUpdateParent != nullptr)
+			mUpdateParent->mIsDirty = true;
+		else
+			mIsDirty = true;
 	}
 
-	void GUIElementBase::markMeshAsDirty()
+	void GUIElementBase::_markMeshAsDirty()
 	{
 		if(_isDisabled())
 			return;
@@ -242,7 +217,7 @@ namespace BansheeEngine
 
 		// Make sure to mark everything as dirty, as we didn't track any dirty flags while the element was disabled
 		mIsDisabled = false;
-		markContentAsDirty();
+		_markContentAsDirty();
 
 		for(auto& elem : mChildren)
 		{
@@ -252,7 +227,7 @@ namespace BansheeEngine
 
 	void GUIElementBase::disableRecursively()
 	{
-		markMeshAsDirty(); // Just need to hide the mesh
+		_markMeshAsDirty(); // Just need to hide the mesh
 		mIsDisabled = true;
 
 		for(auto& elem : mChildren)
@@ -261,11 +236,10 @@ namespace BansheeEngine
 		}
 	}
 
-	void GUIElementBase::_updateLayout(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I clipRect, 
-		UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUIElementBase::_updateLayout(const GUILayoutData& data)
 	{
 		_updateOptimalLayoutSizes(); // We calculate optimal sizes of all layouts as a pre-processing step, as they are requested often during update
-		_updateLayoutInternal(x, y, width, height, clipRect, widgetDepth, panelDepth, panelDepthRangeMin, panelDepthRangeMax);
+		_updateLayoutInternal(data);
 	}
 
 	void GUIElementBase::_updateOptimalLayoutSizes()
@@ -276,12 +250,11 @@ namespace BansheeEngine
 		}
 	}
 
-	void GUIElementBase::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I clipRect, 
-		UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUIElementBase::_updateLayoutInternal(const GUILayoutData& data)
 	{
 		for(auto& child : mChildren)
 		{
-			child->_updateLayoutInternal(x, y, width, height, clipRect, widgetDepth, panelDepth, panelDepthRangeMin, panelDepthRangeMax);
+			child->_updateLayoutInternal(data);
 		}
 	}
 
@@ -294,7 +267,7 @@ namespace BansheeEngine
 		return dimensions.calculateSizeRange(_getOptimalSize());
 	}
 
-	void GUIElementBase::_getElementAreas(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I* elementAreas, UINT32 numElements,
+	void GUIElementBase::_getElementAreas(const Rect2I& layoutArea, Rect2I* elementAreas, UINT32 numElements,
 		const Vector<LayoutSizeRange>& sizeRanges, const LayoutSizeRange& mySizeRange) const
 	{
 		assert(mChildren.size() == 0);
@@ -331,7 +304,7 @@ namespace BansheeEngine
 		if (mIsDisabled)
 			element->disableRecursively();
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIElementBase::_unregisterChildElement(GUIElementBase* element)
@@ -347,7 +320,7 @@ namespace BansheeEngine
 				element->_setParent(nullptr);
 				foundElem = true;
 
-				markContentAsDirty();
+				_markContentAsDirty();
 				break;
 			}
 		}
@@ -374,7 +347,7 @@ namespace BansheeEngine
 			child->_changeParentWidget(widget);
 		}
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIElementBase::_updateAUParents()

+ 42 - 40
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -88,7 +88,7 @@ namespace BansheeEngine
 
 			scrollTextToCaret();
 
-			markContentAsDirty();
+			_markContentAsDirty();
 		}
 	}
 
@@ -96,7 +96,7 @@ namespace BansheeEngine
 	{
 		mColor = color;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	UINT32 GUIInputBox::_getNumRenderElements() const
@@ -137,8 +137,8 @@ namespace BansheeEngine
 
 	void GUIInputBox::updateRenderElementsInternal()
 	{		
-		mImageDesc.width = mWidth;
-		mImageDesc.height = mHeight;
+		mImageDesc.width = mLayoutData.area.width;
+		mImageDesc.height = mLayoutData.area.height;
 		mImageDesc.borderLeft = _getStyle()->border.left;
 		mImageDesc.borderRight = _getStyle()->border.right;
 		mImageDesc.borderTop = _getStyle()->border.top;
@@ -170,14 +170,16 @@ namespace BansheeEngine
 
 		// When text bounds are reduced the scroll needs to be adjusted so that
 		// input box isn't filled with mostly empty space.
-		clampScrollToBounds(mTextSprite->getBounds(mOffset, Rect2I()));
+		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
+		clampScrollToBounds(mTextSprite->getBounds(offset, Rect2I()));
 
 		GUIElement::updateRenderElementsInternal();
 	}
 
 	void GUIInputBox::updateClippedBounds()
 	{
-		mClippedBounds = mImageSprite->getBounds(mOffset, mClipRect);
+		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
+		mClippedBounds = mImageSprite->getBounds(offset, mLayoutData.clipRect);
 	}
 
 	Sprite* GUIInputBox::renderElemToSprite(UINT32 renderElemIdx, UINT32& localRenderElemIdx) const
@@ -242,7 +244,7 @@ namespace BansheeEngine
 		newNumElements += mImageSprite->getNumRenderElements();
 
 		if(renderElemIdx < newNumElements)
-			return mOffset;
+			return Vector2I(mLayoutData.area.x, mLayoutData.area.y);;
 
 		if(mCaretShown && gGUIManager().getCaretBlinkState())
 		{
@@ -283,7 +285,7 @@ namespace BansheeEngine
 		newNumElements += mImageSprite->getNumRenderElements();
 
 		if(renderElemIdx < newNumElements)
-			return mClipRect;
+			return mLayoutData.clipRect;
 
 		if(mCaretShown && gGUIManager().getCaretBlinkState())
 		{
@@ -342,8 +344,8 @@ namespace BansheeEngine
 	Rect2I GUIInputBox::_getTextInputRect() const
 	{
 		Rect2I textBounds = getCachedContentBounds();
-		textBounds.x -= mOffset.x;
-		textBounds.y -= mOffset.y;
+		textBounds.x -= mLayoutData.area.x;
+		textBounds.y -= mLayoutData.area.y;
 
 		return textBounds;
 	}
@@ -397,7 +399,7 @@ namespace BansheeEngine
 			if(!mHasFocus)
 			{
 				mState = State::Hover;
-				markContentAsDirty();
+				_markContentAsDirty();
 			}
 
 			mIsMouseOver = true;
@@ -409,7 +411,7 @@ namespace BansheeEngine
 			if(!mHasFocus)
 			{
 				mState = State::Normal;
-				markContentAsDirty();
+				_markContentAsDirty();
 			}
 
 			mIsMouseOver = false;
@@ -421,7 +423,7 @@ namespace BansheeEngine
 			showSelection(0);
 			gGUIManager().getInputSelectionTool()->selectAll();
 
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 		else if(ev.getType() == GUIMouseEventType::MouseDown && ev.getButton() == GUIMouseButton::Left)
@@ -450,7 +452,7 @@ namespace BansheeEngine
 				scrollTextToCaret();
 			}
 
-			markContentAsDirty();
+			_markContentAsDirty();
 
 			return true;
 		}
@@ -491,7 +493,7 @@ namespace BansheeEngine
 
 				scrollTextToCaret();
 
-				markContentAsDirty();
+				_markContentAsDirty();
 				return true;
 			}
 		}
@@ -522,7 +524,7 @@ namespace BansheeEngine
 			gGUIManager().getInputCaretTool()->moveCaretToChar(charIdx, CARET_AFTER);
 			scrollTextToCaret();
 
-			markContentAsDirty();
+			_markContentAsDirty();
 
 			if(!onValueChanged.empty())
 				onValueChanged(mText);
@@ -535,7 +537,7 @@ namespace BansheeEngine
 	{
 		if(ev.getType() == GUICommandEventType::Redraw)
 		{
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 
@@ -545,7 +547,7 @@ namespace BansheeEngine
 
 			showSelection(0);
 			gGUIManager().getInputSelectionTool()->selectAll();
-			markContentAsDirty();
+			_markContentAsDirty();
 
 			mHasFocus = true;
 
@@ -561,7 +563,7 @@ namespace BansheeEngine
 
 			hideCaret();
 			clearSelection();
-			markContentAsDirty();
+			_markContentAsDirty();
 
 			mHasFocus = false;
 
@@ -611,7 +613,7 @@ namespace BansheeEngine
 					}
 				}
 
-				markContentAsDirty();
+				_markContentAsDirty();
 			}
 
 			return true;
@@ -656,7 +658,7 @@ namespace BansheeEngine
 					}
 				}
 
-				markContentAsDirty();
+				_markContentAsDirty();
 			}
 
 			return true;
@@ -678,7 +680,7 @@ namespace BansheeEngine
 				gGUIManager().getInputCaretTool()->moveCaretLeft();
 
 			scrollTextToCaret();
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 
@@ -691,7 +693,7 @@ namespace BansheeEngine
 			gGUIManager().getInputSelectionTool()->moveSelectionToCaret(gGUIManager().getInputCaretTool()->getCaretPos());
 
 			scrollTextToCaret();
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 
@@ -711,7 +713,7 @@ namespace BansheeEngine
 				gGUIManager().getInputCaretTool()->moveCaretRight();
 
 			scrollTextToCaret();
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 
@@ -724,7 +726,7 @@ namespace BansheeEngine
 			gGUIManager().getInputSelectionTool()->moveSelectionToCaret(gGUIManager().getInputCaretTool()->getCaretPos());
 
 			scrollTextToCaret();
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 
@@ -735,7 +737,7 @@ namespace BansheeEngine
 			gGUIManager().getInputCaretTool()->moveCaretUp();
 
 			scrollTextToCaret();
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 
@@ -748,7 +750,7 @@ namespace BansheeEngine
 			gGUIManager().getInputSelectionTool()->moveSelectionToCaret(gGUIManager().getInputCaretTool()->getCaretPos());
 
 			scrollTextToCaret();
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 
@@ -759,7 +761,7 @@ namespace BansheeEngine
 			gGUIManager().getInputCaretTool()->moveCaretDown();
 
 			scrollTextToCaret();
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 
@@ -772,7 +774,7 @@ namespace BansheeEngine
 			gGUIManager().getInputSelectionTool()->moveSelectionToCaret(gGUIManager().getInputCaretTool()->getCaretPos());
 
 			scrollTextToCaret();
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 
@@ -801,7 +803,7 @@ namespace BansheeEngine
 					gGUIManager().getInputCaretTool()->moveCaretRight();
 					scrollTextToCaret();
 
-					markContentAsDirty();
+					_markContentAsDirty();
 
 					if(!onValueChanged.empty())
 						onValueChanged(mText);
@@ -821,7 +823,7 @@ namespace BansheeEngine
 		{
 			cutText();
 
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 		else if(ev.getButton() == mCopyVB)
@@ -834,7 +836,7 @@ namespace BansheeEngine
 		{
 			pasteText();
 
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 		else if(ev.getButton() == mSelectAllVB)
@@ -842,7 +844,7 @@ namespace BansheeEngine
 			showSelection(0);
 			gGUIManager().getInputSelectionTool()->selectAll();
 
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 
@@ -856,14 +858,14 @@ namespace BansheeEngine
 		TEXT_SPRITE_DESC textDesc = getTextDesc();
 		Vector2I offset = getTextOffset();
 		gGUIManager().getInputCaretTool()->updateText(this, textDesc);
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 
 	void GUIInputBox::hideCaret()
 	{
 		mCaretShown = false;
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIInputBox::showSelection(UINT32 anchorCaretPos)
@@ -874,14 +876,14 @@ namespace BansheeEngine
 
 		gGUIManager().getInputSelectionTool()->showSelection(anchorCaretPos);
 		mSelectionShown = true;
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIInputBox::clearSelection()
 	{
 		gGUIManager().getInputSelectionTool()->clearSelection();
 		mSelectionShown = false;
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIInputBox::scrollTextToCaret()
@@ -926,7 +928,7 @@ namespace BansheeEngine
 		gGUIManager().getInputCaretTool()->updateText(this, textDesc);
 		gGUIManager().getInputSelectionTool()->updateText(this, textDesc);
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIInputBox::clampScrollToBounds(Rect2I unclippedTextBounds)
@@ -946,7 +948,7 @@ namespace BansheeEngine
 			gGUIManager().getInputCaretTool()->updateText(this, textDesc);
 			gGUIManager().getInputSelectionTool()->updateText(this, textDesc);
 
-			markContentAsDirty();
+			_markContentAsDirty();
 		}
 	}
 
@@ -1151,7 +1153,7 @@ namespace BansheeEngine
 
 			scrollTextToCaret();
 
-			markContentAsDirty();
+			_markContentAsDirty();
 
 			if(!onValueChanged.empty())
 				onValueChanged(mText);

+ 3 - 1
BansheeEngine/Source/BsGUIInputCaret.cpp

@@ -25,7 +25,9 @@ namespace BansheeEngine
 
 	Rect2I GUIInputCaret::getSpriteClipRect(const Rect2I& parentClipRect) const
 	{
-		Vector2I clipOffset = getSpriteOffset() - mElement->_getOffset() - 
+		Vector2I offset(mElement->_getLayoutData().area.x, mElement->_getLayoutData().area.y);
+
+		Vector2I clipOffset = getSpriteOffset() - offset -
 			Vector2I(mElement->_getTextInputRect().x, mElement->_getTextInputRect().y);
 
 		Rect2I clipRect(-clipOffset.x, -clipOffset.y, mTextDesc.width, mTextDesc.height);

+ 3 - 1
BansheeEngine/Source/BsGUIInputTool.cpp

@@ -68,7 +68,9 @@ namespace BansheeEngine
 
 	Vector2I GUIInputTool::getTextOffset() const
 	{
-		return mElement->_getOffset() + mElement->_getTextInputOffset() + Vector2I(mElement->_getTextInputRect().x, mElement->_getTextInputRect().y);
+		Vector2I offset(mElement->_getLayoutData().area.x, mElement->_getLayoutData().area.y);
+
+		return offset + mElement->_getTextInputOffset() + Vector2I(mElement->_getTextInputRect().x, mElement->_getTextInputRect().y);
 	}
 
 	Rect2I GUIInputTool::getCharRect(UINT32 charIdx) const

+ 14 - 10
BansheeEngine/Source/BsGUILabel.cpp

@@ -14,7 +14,7 @@ namespace BansheeEngine
 	{
 		mTextSprite = bs_new<TextSprite, PoolAlloc>();
 
-		mLocStringUpdatedConn = mContent.getText().addOnStringModifiedCallback(std::bind(&GUILabel::markContentAsDirty, this));
+		mLocStringUpdatedConn = mContent.getText().addOnStringModifiedCallback(std::bind(&GUILabel::_markContentAsDirty, this));
 	}
 
 	GUILabel::~GUILabel()
@@ -45,8 +45,8 @@ namespace BansheeEngine
 		mDesc.wordWrap = _getStyle()->wordWrap;
 		mDesc.horzAlign = _getStyle()->textHorzAlign;
 		mDesc.vertAlign = _getStyle()->textVertAlign;
-		mDesc.width = mWidth;
-		mDesc.height = mHeight;
+		mDesc.width = mLayoutData.area.width;
+		mDesc.height = mLayoutData.area.height;
 		mDesc.text = mContent.getText();
 		mDesc.color = mColor * _getStyle()->normal.textColor;;
 
@@ -57,10 +57,11 @@ namespace BansheeEngine
 
 	void GUILabel::updateClippedBounds()
 	{
-		Vector2I offset = _getOffset();
-		mClippedBounds = Rect2I(offset.x, offset.y, _getWidth(), _getHeight());
+		mClippedBounds = mLayoutData.area;
 
-		Rect2I localClipRect(mClipRect.x + mOffset.x, mClipRect.y + mOffset.y, mClipRect.width, mClipRect.height);
+		Rect2I localClipRect = mLayoutData.clipRect;
+		localClipRect.x += mLayoutData.area.x;
+		localClipRect.y += mLayoutData.area.y;
 		mClippedBounds.clip(localClipRect);
 	}
 
@@ -72,24 +73,27 @@ namespace BansheeEngine
 	void GUILabel::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 	{
-		mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx, mOffset, mClipRect);
+		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
+
+		mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, 
+			indexStride, renderElementIdx, offset, mLayoutData.clipRect);
 	}
 
 	void GUILabel::setContent(const GUIContent& content)
 	{
 		mLocStringUpdatedConn.disconnect();
-		mLocStringUpdatedConn = content.getText().addOnStringModifiedCallback(std::bind(&GUILabel::markContentAsDirty, this));
+		mLocStringUpdatedConn = content.getText().addOnStringModifiedCallback(std::bind(&GUILabel::_markContentAsDirty, this));
 
 		mContent = content;
 		
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUILabel::setTint(const Color& color)
 	{
 		mColor = color;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	GUILabel* GUILabel::create(const HString& text, const String& styleName)

+ 2 - 2
BansheeEngine/Source/BsGUILayout.cpp

@@ -47,7 +47,7 @@ namespace BansheeEngine
 		if (mIsDisabled)
 			element->disableRecursively();
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUILayout::removeElementAt(UINT32 idx)
@@ -60,7 +60,7 @@ namespace BansheeEngine
 
 		child->_setParent(nullptr);
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	const RectOffset& GUILayout::_getPadding() const

+ 5 - 58
BansheeEngine/Source/BsGUILayoutUtility.cpp

@@ -14,63 +14,6 @@ namespace BansheeEngine
 		return elem->_calculateLayoutSizeRange().optimal;
 	}
 
-	Rect2I GUILayoutUtility::calcBounds(const GUIElementBase* elem, GUIPanel* relativeTo)
-	{
-		Rect2I parentArea;
-
-		GUIElementBase* parent = elem->_getParent();
-		if (parent != nullptr)
-		{
-			parentArea = calcBounds(parent);
-
-			if (parent->_getType() == GUIElementBase::Type::Panel && (relativeTo == nullptr || relativeTo == parent))
-			{
-				parentArea.x = 0;
-				parentArea.y = 0;
-			}
-		}
-		else
-		{
-			GUIWidget* parentWidget = elem->_getParentWidget();
-
-			if (parentWidget != nullptr)
-			{
-				parentArea.width = parentWidget->getTarget()->getWidth();
-				parentArea.height = parentWidget->getTarget()->getHeight();
-			}
-
-			return parentArea;
-		}
-
-		UINT32 numElements = (UINT32)parent->_getNumChildren();
-		UINT32 myIndex = 0;
-
-		Vector<LayoutSizeRange> sizeRanges;
-		for (UINT32 i = 0; i < numElements; i++)
-		{
-			GUIElementBase* child = parent->_getChild(i);
-
-			if (child == elem)
-				myIndex = i;
-
-			sizeRanges.push_back(child->_calculateLayoutSizeRange());
-		}
-
-		Rect2I* elementAreas = nullptr;
-
-		if (numElements > 0)
-			elementAreas = stackConstructN<Rect2I>(numElements);
-
-		parent->_getElementAreas(parentArea.x, parentArea.y, parentArea.width, parentArea.height, elementAreas, 
-			numElements, sizeRanges, parent->_calculateLayoutSizeRange());
-		Rect2I myArea = elementAreas[myIndex];
-
-		if (elementAreas != nullptr)
-			stackDeallocLast(elementAreas);
-
-		return myArea;
-	}
-
 	Vector2I GUILayoutUtility::calcActualSize(UINT32 width, UINT32 height, const GUILayout* layout)
 	{
 		UINT32 numElements = (UINT32)layout->_getNumChildren();
@@ -87,7 +30,11 @@ namespace BansheeEngine
 		if (numElements > 0)
 			elementAreas = stackConstructN<Rect2I>(numElements);
 
-		layout->_getElementAreas(0, 0, width, height, elementAreas, numElements, sizeRanges, layout->_calculateLayoutSizeRange());
+		Rect2I parentArea;
+		parentArea.width = width;
+		parentArea.height = height;
+
+		layout->_getElementAreas(parentArea, elementAreas, numElements, sizeRanges, layout->_calculateLayoutSizeRange());
 		Rect2I* actualAreas = elementAreas; // We re-use the same array
 
 		for (UINT32 i = 0; i < numElements; i++)

+ 26 - 34
BansheeEngine/Source/BsGUILayoutX.cpp

@@ -77,7 +77,7 @@ namespace BansheeEngine
 		mSizeRange = _getDimensions().calculateSizeRange(optimalSize);
 	}
 
-	void GUILayoutX::_getElementAreas(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I* elementAreas, UINT32 numElements, 
+	void GUILayoutX::_getElementAreas(const Rect2I& layoutArea, Rect2I* elementAreas, UINT32 numElements,
 		const Vector<LayoutSizeRange>& sizeRanges, const LayoutSizeRange& mySizeRange) const
 	{
 		assert(mChildren.size() == numElements);
@@ -131,9 +131,9 @@ namespace BansheeEngine
 		}
 
 		// If there is some room left, calculate flexible space sizes (since they will fill up all that extra room)
-		if (width > totalOptimalSize)
+		if ((UINT32)layoutArea.width > totalOptimalSize)
 		{
-			UINT32 extraSize = width - totalOptimalSize;
+			UINT32 extraSize = layoutArea.width - totalOptimalSize;
 			UINT32 remainingSize = extraSize;
 
 			// Flexible spaces always expand to fill up all unused space
@@ -166,7 +166,7 @@ namespace BansheeEngine
 					childIdx++;
 				}
 
-				totalOptimalSize = width;
+				totalOptimalSize = layoutArea.width;
 			}
 		}
 
@@ -188,9 +188,9 @@ namespace BansheeEngine
 		}
 
 		// Our optimal size is larger than maximum allowed, so we need to reduce size of some elements
-		if (totalOptimalSize > width)
+		if (totalOptimalSize > (UINT32)layoutArea.width)
 		{
-			UINT32 extraSize = totalOptimalSize - width;
+			UINT32 extraSize = totalOptimalSize - layoutArea.width;
 			UINT32 remainingSize = extraSize;
 
 			// Iterate until we reduce everything so it fits, while maintaining
@@ -253,7 +253,7 @@ namespace BansheeEngine
 		}
 		else // We are smaller than the allowed maximum, so try to expand some elements
 		{
-			UINT32 extraSize = width - totalOptimalSize;
+			UINT32 extraSize = layoutArea.width - totalOptimalSize;
 			UINT32 remainingSize = extraSize;
 
 			// Iterate until we reduce everything so it fits, while maintaining
@@ -326,7 +326,7 @@ namespace BansheeEngine
 			const GUIDimensions& dimensions = child->_getDimensions();
 			if (!dimensions.fixedHeight())
 			{
-				elemHeight = height;
+				elemHeight = layoutArea.height;
 				if (dimensions.minHeight > 0 && elemHeight < dimensions.minHeight)
 					elemHeight = dimensions.minHeight;
 
@@ -341,18 +341,18 @@ namespace BansheeEngine
 				GUIElement* element = static_cast<GUIElement*>(child);
 
 				UINT32 yPadding = element->_getPadding().top + element->_getPadding().bottom;
-				INT32 yOffset = Math::ceilToInt(((INT32)height - (INT32)(elemHeight + yPadding)) * 0.5f);
+				INT32 yOffset = Math::ceilToInt(((INT32)layoutArea.height - (INT32)(elemHeight + yPadding)) * 0.5f);
 				yOffset = std::max(0, yOffset);
 
-				elementAreas[childIdx].x = x + xOffset;
-				elementAreas[childIdx].y = y + yOffset;
+				elementAreas[childIdx].x = layoutArea.x + xOffset;
+				elementAreas[childIdx].y = layoutArea.y + yOffset;
 			}
 			else if (child->_getType() == GUIElementBase::Type::Layout || child->_getType() == GUIElementBase::Type::Panel)
 			{
 				GUILayout* layout = static_cast<GUILayout*>(child);
 
-				elementAreas[childIdx].x = x + xOffset;
-				elementAreas[childIdx].y = y;
+				elementAreas[childIdx].x = layoutArea.x + xOffset;
+				elementAreas[childIdx].y = layoutArea.y;
 			}
 
 			xOffset += elemWidth + child->_getPadding().right;
@@ -366,8 +366,7 @@ namespace BansheeEngine
 			stackDeallocLast(processedElements);
 	}
 
-	void GUILayoutX::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I clipRect, 
-		UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUILayoutX::_updateLayoutInternal(const GUILayoutData& data)
 	{
 		UINT32 numElements = (UINT32)mChildren.size();
 		Rect2I* elementAreas = nullptr;
@@ -375,31 +374,24 @@ namespace BansheeEngine
 		if (numElements > 0)
 			elementAreas = stackConstructN<Rect2I>(numElements);
 
-		_getElementAreas(x, y,width, height, elementAreas, numElements, mChildSizeRanges, mSizeRange);
+		_getElementAreas(data.area, elementAreas, numElements, mChildSizeRanges, mSizeRange);
 
 		// Now that we have all the areas, actually assign them
 		UINT32 childIdx = 0;
 
+		GUILayoutData childData = data;
 		for(auto& child : mChildren)
 		{
-			Rect2I childArea = elementAreas[childIdx];
-			Vector2I offset(childArea.x, childArea.y);
-
-			child->_setPosition(offset);
-			child->_setWidth(childArea.width);
-			child->_setHeight(childArea.height);
-			child->_setWidgetDepth(widgetDepth);
-			child->_setAreaDepth(panelDepth);
-			child->_setPanelDepthRange(panelDepthRangeMin, panelDepthRangeMax);
-			
-			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-			child->_setClipRect(elemClipRect);
-
-			Rect2I newClipRect(offset.x, offset.y, childArea.width, childArea.height);
-			newClipRect.clip(clipRect);
-
-			child->_updateLayoutInternal(offset.x, offset.y, childArea.width, childArea.height, newClipRect,
-				widgetDepth, panelDepth, panelDepthRangeMin, panelDepthRangeMax);
+			childData.area = elementAreas[childIdx];
+			childData.clipRect.x -= childData.area.x;
+			childData.clipRect.y -= childData.area.y;
+
+			child->_setLayoutData(childData);
+
+			childData.clipRect = childData.area;
+			childData.clipRect.clip(data.clipRect);
+
+			child->_updateLayoutInternal(childData);
 
 			childIdx++;
 		}

+ 23 - 31
BansheeEngine/Source/BsGUILayoutY.cpp

@@ -77,7 +77,7 @@ namespace BansheeEngine
 		mSizeRange = _getDimensions().calculateSizeRange(optimalSize);
 	}
 
-	void GUILayoutY::_getElementAreas(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I* elementAreas, UINT32 numElements, 
+	void GUILayoutY::_getElementAreas(const Rect2I& layoutArea, Rect2I* elementAreas, UINT32 numElements,
 		const Vector<LayoutSizeRange>& sizeRanges, const LayoutSizeRange& mySizeRange) const
 	{
 		assert(mChildren.size() == numElements);
@@ -131,9 +131,9 @@ namespace BansheeEngine
 		}
 
 		// If there is some room left, calculate flexible space sizes (since they will fill up all that extra room)
-		if (height > totalOptimalSize)
+		if ((UINT32)layoutArea.height > totalOptimalSize)
 		{
-			UINT32 extraSize = height - totalOptimalSize;
+			UINT32 extraSize = layoutArea.height - totalOptimalSize;
 			UINT32 remainingSize = extraSize;
 
 			// Flexible spaces always expand to fill up all unused space
@@ -166,7 +166,7 @@ namespace BansheeEngine
 					childIdx++;
 				}
 
-				totalOptimalSize = height;
+				totalOptimalSize = layoutArea.height;
 			}
 		}
 
@@ -188,9 +188,9 @@ namespace BansheeEngine
 		}
 
 		// Our optimal size is larger than maximum allowed, so we need to reduce size of some elements
-		if (totalOptimalSize > height)
+		if (totalOptimalSize > (UINT32)layoutArea.height)
 		{
-			UINT32 extraSize = totalOptimalSize - height;
+			UINT32 extraSize = totalOptimalSize - layoutArea.height;
 			UINT32 remainingSize = extraSize;
 
 			// Iterate until we reduce everything so it fits, while maintaining
@@ -253,7 +253,7 @@ namespace BansheeEngine
 		}
 		else // We are smaller than the allowed maximum, so try to expand some elements
 		{
-			UINT32 extraSize = height - totalOptimalSize;
+			UINT32 extraSize = layoutArea.height - totalOptimalSize;
 			UINT32 remainingSize = extraSize;
 
 			// Iterate until we reduce everything so it fits, while maintaining
@@ -332,7 +332,7 @@ namespace BansheeEngine
 			const GUIDimensions& dimensions = child->_getDimensions();
 			if (!dimensions.fixedWidth())
 			{
-				elemWidth = width;
+				elemWidth = layoutArea.width;
 				if (dimensions.minWidth > 0 && elemWidth < dimensions.minWidth)
 					elemWidth = dimensions.minWidth;
 
@@ -347,16 +347,16 @@ namespace BansheeEngine
 				GUIElement* element = static_cast<GUIElement*>(child);
 
 				UINT32 xPadding = element->_getPadding().left + element->_getPadding().right;
-				INT32 xOffset = Math::ceilToInt((INT32)(width - (INT32)(elemWidth + xPadding)) * 0.5f);
+				INT32 xOffset = Math::ceilToInt((INT32)(layoutArea.width - (INT32)(elemWidth + xPadding)) * 0.5f);
 				xOffset = std::max(0, xOffset);
 
-				elementAreas[childIdx].x = x + xOffset;
-				elementAreas[childIdx].y = y + yOffset;
+				elementAreas[childIdx].x = layoutArea.x + xOffset;
+				elementAreas[childIdx].y = layoutArea.y + yOffset;
 			}
 			else if (child->_getType() == GUIElementBase::Type::Layout || child->_getType() == GUIElementBase::Type::Panel)
 			{
-				elementAreas[childIdx].x = x;
-				elementAreas[childIdx].y = y + yOffset;
+				elementAreas[childIdx].x = layoutArea.x;
+				elementAreas[childIdx].y = layoutArea.y + yOffset;
 			}
 
 			yOffset += elemHeight + child->_getPadding().bottom;
@@ -364,8 +364,7 @@ namespace BansheeEngine
 		}
 	}
 
-	void GUILayoutY::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I clipRect, 
-		UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUILayoutY::_updateLayoutInternal(const GUILayoutData& data)
 	{
 		UINT32 numElements = (UINT32)mChildren.size();
 		Rect2I* elementAreas = nullptr;
@@ -373,31 +372,24 @@ namespace BansheeEngine
 		if (numElements > 0)
 			elementAreas = stackConstructN<Rect2I>(numElements);
 
-		_getElementAreas(x, y, width, height, elementAreas, numElements, mChildSizeRanges, mSizeRange);
+		_getElementAreas(data.area, elementAreas, numElements, mChildSizeRanges, mSizeRange);
 
 		// Now that we have all the areas, actually assign them
 		UINT32 childIdx = 0;
 
+		GUILayoutData childData = data;
 		for(auto& child : mChildren)
 		{
-			Rect2I childArea = elementAreas[childIdx];
-			Vector2I offset(childArea.x, childArea.y);
+			childData.area = elementAreas[childIdx];
+			childData.clipRect.x -= childData.area.x;
+			childData.clipRect.y -= childData.area.y;
 
-			child->_setPosition(offset);
-			child->_setHeight(childArea.height);
-			child->_setWidth(childArea.width);
-			child->_setWidgetDepth(widgetDepth);
-			child->_setAreaDepth(panelDepth);
-			child->_setPanelDepthRange(panelDepthRangeMin, panelDepthRangeMax);
+			child->_setLayoutData(childData);
 
-			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-			child->_setClipRect(elemClipRect);
+			childData.clipRect = childData.area;
+			childData.clipRect.clip(data.clipRect);
 
-			Rect2I newClipRect(offset.x, offset.y, childArea.width, childArea.height);
-			newClipRect.clip(clipRect);
-
-			child->_updateLayoutInternal(offset.x, offset.y, childArea.width, childArea.height, newClipRect,
-				widgetDepth, panelDepth, panelDepthRangeMin, panelDepthRangeMax);
+			child->_updateLayoutInternal(childData);
 
 			childIdx++;
 		}

+ 1 - 1
BansheeEngine/Source/BsGUIListBox.cpp

@@ -106,7 +106,7 @@ namespace BansheeEngine
 		}
 
 		GUIWidget* widget = _getParentWidget();
-		GUIDropDownAreaPlacement placement = GUIDropDownAreaPlacement::aroundBoundsHorz(_getCachedBounds());
+		GUIDropDownAreaPlacement placement = GUIDropDownAreaPlacement::aroundBoundsHorz(_getLayoutData().area);
 
 		GameObjectHandle<GUIDropDownBox> dropDownBox = GUIDropDownBoxManager::instance().openDropDownBox(widget->getTarget(), 
 			placement, dropDownData, widget->getSkinResource(), GUIDropDownType::MenuBar, std::bind(&GUIListBox::onListBoxClosed, this));

+ 1 - 1
BansheeEngine/Source/BsGUIManager.cpp

@@ -1421,7 +1421,7 @@ namespace BansheeEngine
 			const Matrix4& worldTfrm = bridgeElement->_getParentWidget()->SO()->getWorldTfrm();
 
 			Vector4 vecLocalPos = worldTfrm.inverse().multiplyAffine(Vector4((float)windowPos.x, (float)windowPos.y, 0.0f, 1.0f));
-			Rect2I bridgeBounds = bridgeElement->_getCachedBounds();
+			Rect2I bridgeBounds = bridgeElement->_getLayoutData().area;
 
 			// Find coordinates relative to the bridge element
 			float x = vecLocalPos.x - (float)bridgeBounds.x;

+ 34 - 39
BansheeEngine/Source/BsGUIPanel.cpp

@@ -16,7 +16,7 @@ namespace BansheeEngine
 		mDepthRangeMin = depthRangeMin;
 		mDepthRangeMax = depthRangeMax;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	LayoutSizeRange GUIPanel::_calculateLayoutSizeRange() const
@@ -104,7 +104,7 @@ namespace BansheeEngine
 		mSizeRange = _getDimensions().calculateSizeRange(optimalSize);
 	}
 
-	void GUIPanel::_getElementAreas(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I* elementAreas, UINT32 numElements,
+	void GUIPanel::_getElementAreas(const Rect2I& layoutArea, Rect2I* elementAreas, UINT32 numElements,
 		const Vector<LayoutSizeRange>& sizeRanges, const LayoutSizeRange& mySizeRange) const
 	{
 		assert(mChildren.size() == numElements);
@@ -113,26 +113,26 @@ namespace BansheeEngine
 		UINT32 childIdx = 0;
 		for (auto& child : mChildren)
 		{
-			elementAreas[childIdx] = _getElementArea(x, y, width, height, child, sizeRanges[childIdx]);
+			elementAreas[childIdx] = _getElementArea(layoutArea, child, sizeRanges[childIdx]);
 
 			childIdx++;
 		}
 	}
 
-	Rect2I GUIPanel::_getElementArea(INT32 x, INT32 y, UINT32 width, UINT32 height, const GUIElementBase* element, const LayoutSizeRange& sizeRange) const
+	Rect2I GUIPanel::_getElementArea(const Rect2I& layoutArea, const GUIElementBase* element, const LayoutSizeRange& sizeRange) const
 	{
 		const GUIDimensions& dimensions = element->_getDimensions();
 
 		Rect2I area;
 
-		area.x = x + dimensions.x;
-		area.y = y + dimensions.y;
+		area.x = layoutArea.x + dimensions.x;
+		area.y = layoutArea.y + dimensions.y;
 
 		if (dimensions.fixedWidth())
 			area.width = (UINT32)sizeRange.optimal.x;
 		else
 		{
-			UINT32 modifiedWidth = (UINT32)std::max(0, (INT32)width - dimensions.x);
+			UINT32 modifiedWidth = (UINT32)std::max(0, (INT32)layoutArea.width - dimensions.x);
 
 			if (modifiedWidth > (UINT32)sizeRange.optimal.x)
 			{
@@ -152,7 +152,7 @@ namespace BansheeEngine
 			area.height = (UINT32)sizeRange.optimal.y;
 		else
 		{
-			UINT32 modifiedHeight = (UINT32)std::max(0, (INT32)height - dimensions.y);
+			UINT32 modifiedHeight = (UINT32)std::max(0, (INT32)layoutArea.height - dimensions.y);
 
 			if (modifiedHeight > (UINT32)sizeRange.optimal.y)
 			{
@@ -171,10 +171,9 @@ namespace BansheeEngine
 		return area;
 	}
 
-	void GUIPanel::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I clipRect, UINT8 widgetDepth, 
-		INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUIPanel::_updateLayoutInternal(const GUILayoutData& data)
 	{
-		INT32 newPanelDepth = panelDepth + mDepthOffset;
+		INT32 newPanelDepth = data.getPanelDepth() + mDepthOffset;
 		INT32 newPanelDepthRangeMin = newPanelDepth - mDepthRangeMin;
 		INT32 newPanelDepthRangeMax = newPanelDepth + mDepthRangeMax;
 
@@ -182,20 +181,21 @@ namespace BansheeEngine
 
 		for (auto& depth : allDepths)
 		{
-			INT32 minValue = std::max((INT32)panelDepth - (INT32)panelDepthRangeMin, (INT32)std::numeric_limits<INT16>::min());
+			INT32 minValue = std::max((INT32)data.getPanelDepth() - (INT32)data.depthRangeMin, (INT32)std::numeric_limits<INT16>::min());
 			*depth = std::max(*depth, minValue);
 
-			INT32 maxValue = std::min((INT32)panelDepth + (INT32)panelDepthRangeMax, (INT32)std::numeric_limits<INT16>::max());
+			INT32 maxValue = std::min((INT32)data.getPanelDepth() + (INT32)data.depthRangeMax, (INT32)std::numeric_limits<INT16>::max());
 			*depth = std::min(*depth, maxValue);
 		}
 
-		panelDepth = (INT16)newPanelDepth;
+		GUILayoutData childData = data;
+		childData.setPanelDepth((INT16)newPanelDepth);
 		
-		if (mDepthRangeMin != (UINT16)-1 || panelDepthRangeMin != (UINT16)-1)
-			panelDepthRangeMin = (UINT16)(newPanelDepth - newPanelDepthRangeMin);
+		if (mDepthRangeMin != (UINT16)-1 || childData.depthRangeMin != (UINT16)-1)
+			childData.depthRangeMin = (UINT16)(newPanelDepth - newPanelDepthRangeMin);
 
-		if (mDepthRangeMax != (UINT16)-1 || panelDepthRangeMax != (UINT16)-1)
-			panelDepthRangeMax = (UINT16)(newPanelDepthRangeMax - newPanelDepth);
+		if (mDepthRangeMax != (UINT16)-1 || childData.depthRangeMax != (UINT16)-1)
+			childData.depthRangeMax = (UINT16)(newPanelDepthRangeMax - newPanelDepth);
 
 		UINT32 numElements = (UINT32)mChildren.size();
 		Rect2I* elementAreas = nullptr;
@@ -203,15 +203,15 @@ namespace BansheeEngine
 		if (numElements > 0)
 			elementAreas = stackConstructN<Rect2I>(numElements);
 
-		_getElementAreas(x, y, width, height, elementAreas, numElements, mChildSizeRanges, mSizeRange);
+		_getElementAreas(data.area, elementAreas, numElements, mChildSizeRanges, mSizeRange);
 
 		UINT32 childIdx = 0;
 
 		for (auto& child : mChildren)
 		{
-			Rect2I childArea = elementAreas[childIdx];
+			childData.area = elementAreas[childIdx];
 
-			_updateChildLayout(child, childArea, clipRect, widgetDepth, panelDepth, panelDepthRangeMin, panelDepthRangeMax);
+			_updateChildLayout(child, childData);
 
 			childIdx++;
 		}
@@ -220,25 +220,20 @@ namespace BansheeEngine
 			stackDeallocLast(elementAreas);
 	}
 
-	void GUIPanel::_updateChildLayout(GUIElementBase* element, const Rect2I& area, const Rect2I& clipRect, UINT8 widgetDepth,
-		INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUIPanel::_updateChildLayout(GUIElementBase* element, const GUILayoutData& data)
 	{
-		Vector2I offset(area.x, area.y);
-		element->_setPosition(offset);
-		element->_setWidth(area.width);
-		element->_setHeight(area.height);
-		element->_setWidgetDepth(widgetDepth);
-		element->_setAreaDepth(panelDepth);
-		element->_setPanelDepthRange(panelDepthRangeMin, panelDepthRangeMax);
-
-		Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
-		element->_setClipRect(elemClipRect);
-
-		Rect2I newClipRect(offset.x, offset.y, area.width, area.height);
-		newClipRect.clip(clipRect);
-
-		element->_updateLayoutInternal(offset.x, offset.y, area.width, area.height, newClipRect,
-			widgetDepth, panelDepth, panelDepthRangeMin, panelDepthRangeMax);
+		GUILayoutData childData = data;
+
+		childData.clipRect = data.clipRect;
+		childData.clipRect.x -= data.area.x;
+		childData.clipRect.y -= data.area.y;
+
+		element->_setLayoutData(childData);
+
+		childData.clipRect = data.area;
+		childData.clipRect.clip(data.clipRect);
+
+		element->_updateLayoutInternal(childData);
 	}
 
 	Vector2I GUIPanel::_calcActualSize(INT32 x, INT32 y, Rect2I* elementAreas, UINT32 numElements) const

+ 20 - 23
BansheeEngine/Source/BsGUIProgressBar.cpp

@@ -44,33 +44,30 @@ namespace BansheeEngine
 		return optimalSize;
 	}
 
-	void GUIProgressBar::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-		Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUIProgressBar::_updateLayoutInternal(const GUILayoutData& data)
 	{
-		Vector2I bgOffset(x, y);
-		Rect2I bgClipRect(clipRect.x - bgOffset.x, clipRect.y - bgOffset.y, clipRect.width, clipRect.height);
+		GUILayoutData bgLayoutData = data;
+		bgLayoutData.clipRect.x -= data.area.x;
+		bgLayoutData.clipRect.y -= data.area.y;
 
-		mBackground->_setPosition(bgOffset);
-		mBackground->_setWidth(width);
-		mBackground->_setHeight(height);
-		mBackground->_setAreaDepth(panelDepth);
-		mBackground->_setWidgetDepth(widgetDepth);
-		mBackground->_setClipRect(bgClipRect);
+		mBackground->_setLayoutData(bgLayoutData);
 
 		const GUIElementStyle* style = _getStyle();
 		
-		Vector2I barOffset(x + style->margins.left, y + style->margins.top);
-		Rect2I barClipRect(clipRect.x - barOffset.x, clipRect.y - barOffset.y, clipRect.width, clipRect.height);
-
-		UINT32 maxProgressBarWidth = std::max((UINT32)0, (UINT32)(width - style->margins.left - style->margins.right));
-		UINT32 progressBarHeight = std::max((UINT32)0, (UINT32)(height - style->margins.top - style->margins.bottom)); 
-
-		mBar->_setPosition(barOffset);
-		mBar->_setWidth((UINT32)Math::floorToInt(maxProgressBarWidth * mPercent));
-		mBar->_setHeight(progressBarHeight);
-		mBar->_setAreaDepth(panelDepth);
-		mBar->_setWidgetDepth(widgetDepth);
-		mBar->_setClipRect(barClipRect);
+		GUILayoutData barLayoutData = data;
+
+		barLayoutData.area.x += style->margins.left;
+		barLayoutData.area.y += style->margins.top;
+		barLayoutData.clipRect.x -= barLayoutData.area.x;
+		barLayoutData.clipRect.y -= barLayoutData.area.y;
+
+		UINT32 maxProgressBarWidth = std::max((UINT32)0, (UINT32)(data.area.width - style->margins.left - style->margins.right));
+		UINT32 progressBarHeight = std::max((UINT32)0, (UINT32)(data.area.height - style->margins.top - style->margins.bottom));
+
+		barLayoutData.area.width = (UINT32)Math::floorToInt(maxProgressBarWidth * mPercent);
+		barLayoutData.area.height = progressBarHeight;
+
+		mBar->_setLayoutData(barLayoutData);
 	}
 
 	void GUIProgressBar::styleUpdated()
@@ -82,7 +79,7 @@ namespace BansheeEngine
 	void GUIProgressBar::setPercent(float pct)
 	{
 		mPercent = pct;
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIProgressBar::setTint(const Color& color)

+ 3 - 3
BansheeEngine/Source/BsGUIRenderTexture.cpp

@@ -59,7 +59,7 @@ namespace BansheeEngine
 			setTexture(SpriteTexture::create(HTexture()));
 		}
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIRenderTexture::updateRenderElementsInternal()
@@ -69,8 +69,8 @@ namespace BansheeEngine
 			mDesc.texture = mActiveTexture.getInternalPtr();
 		}
 
-		mDesc.width = mWidth;
-		mDesc.height = mHeight;
+		mDesc.width = mLayoutData.area.width;
+		mDesc.height = mLayoutData.area.height;
 		mDesc.transparent = false;
 		mDesc.color = mColor;
 

+ 57 - 67
BansheeEngine/Source/BsGUIScrollArea.cpp

@@ -44,22 +44,22 @@ namespace BansheeEngine
 
 	void GUIScrollArea::updateClippedBounds()
 	{
-		Rect2I bounds(0, 0, mWidth, mHeight);
-		bounds.clip(mClipRect);
-		bounds.x += mOffset.x;
-		bounds.y += mOffset.y;
+		Rect2I bounds(0, 0, mLayoutData.area.width, mLayoutData.area.height);
+		bounds.clip(mLayoutData.clipRect);
+		bounds.x += mLayoutData.area.x;
+		bounds.y += mLayoutData.area.y;
 
 		mClippedBounds = bounds;
 	}
 
-	void GUIScrollArea::_getElementAreas(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I* elementAreas, UINT32 numElements, 
+	void GUIScrollArea::_getElementAreas(const Rect2I& layoutArea, Rect2I* elementAreas, UINT32 numElements,
 		const Vector<LayoutSizeRange>& sizeRanges, const LayoutSizeRange& mySizeRange) const
 	{
 		Vector2I visibleSize, contentSize;
-		_getElementAreas(x, y, width, height, elementAreas, numElements, sizeRanges, visibleSize, contentSize);
+		_getElementAreas(layoutArea, elementAreas, numElements, sizeRanges, visibleSize, contentSize);
 	}
 
-	void GUIScrollArea::_getElementAreas(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I* elementAreas, UINT32 numElements, 
+	void GUIScrollArea::_getElementAreas(const Rect2I& layoutArea, Rect2I* elementAreas, UINT32 numElements,
 		const Vector<LayoutSizeRange>& sizeRanges, Vector2I& visibleSize, Vector2I& contentSize) const
 	{
 		assert(mChildren.size() == numElements && numElements == 3);
@@ -86,19 +86,19 @@ namespace BansheeEngine
 
 		//// We want elements to use their optimal height, since scroll area
 		//// technically provides "infinite" space
-		UINT32 optimalContentWidth = width;
+		UINT32 optimalContentWidth = layoutArea.width;
 		if (mHorzBarType != ScrollBarType::NeverShow)
 			optimalContentWidth = sizeRanges[layoutIdx].optimal.x;
 
-		UINT32 optimalContentHeight = height;
+		UINT32 optimalContentHeight = layoutArea.height;
 		if (mVertBarType != ScrollBarType::NeverShow)
 			optimalContentHeight = sizeRanges[layoutIdx].optimal.y;
 
-		UINT32 layoutWidth = std::max(optimalContentWidth, width);
-		UINT32 layoutHeight = std::max(optimalContentHeight, height);
+		UINT32 layoutWidth = std::max(optimalContentWidth, (UINT32)layoutArea.width);
+		UINT32 layoutHeight = std::max(optimalContentHeight, (UINT32)layoutArea.height);
 
 		contentSize = GUILayoutUtility::calcActualSize(layoutWidth, layoutHeight, mContentLayout);
-		visibleSize = Vector2I(width, height);
+		visibleSize = Vector2I(layoutArea.width, layoutArea.height);
 
 		bool addHorzScrollbar = (mHorzBarType == ScrollBarType::ShowIfDoesntFit && contentSize.x > visibleSize.x) ||
 			mHorzBarType == ScrollBarType::AlwaysShow && mHorzBarType != ScrollBarType::NeverShow;
@@ -108,7 +108,7 @@ namespace BansheeEngine
 		if (addHorzScrollbar)
 		{
 			// Make room for scrollbar
-			visibleSize.y = (UINT32)std::max(0, (INT32)height - (INT32)ScrollBarWidth);
+			visibleSize.y = (UINT32)std::max(0, (INT32)layoutArea.height - (INT32)ScrollBarWidth);
 
 			if (mVertBarType == ScrollBarType::NeverShow)
 				layoutHeight = (UINT32)visibleSize.y;
@@ -125,7 +125,7 @@ namespace BansheeEngine
 		if (addVertScrollbar)
 		{
 			// Make room for scrollbar
-			visibleSize.x = (UINT32)std::max(0, (INT32)width - (INT32)ScrollBarWidth);
+			visibleSize.x = (UINT32)std::max(0, (INT32)layoutArea.width - (INT32)ScrollBarWidth);
 			
 			if (mHorzBarType == ScrollBarType::NeverShow)
 				layoutWidth = (UINT32)visibleSize.x;
@@ -142,7 +142,7 @@ namespace BansheeEngine
 				if (addHorzScrollbar)
 				{
 					// Make room for scrollbar
-					visibleSize.y = (UINT32)std::max(0, (INT32)height - (INT32)ScrollBarWidth);
+					visibleSize.y = (UINT32)std::max(0, (INT32)layoutArea.height - (INT32)ScrollBarWidth);
 
 					if (mVertBarType == ScrollBarType::NeverShow)
 						layoutHeight = (UINT32)visibleSize.y;
@@ -155,41 +155,40 @@ namespace BansheeEngine
 			}
 		}
 
-		elementAreas[layoutIdx] = Rect2I(x - Math::floorToInt(mHorzOffset), y - Math::floorToInt(mVertOffset), layoutWidth, layoutHeight);
+		elementAreas[layoutIdx] = Rect2I(layoutArea.x - Math::floorToInt(mHorzOffset), layoutArea.y - Math::floorToInt(mVertOffset), layoutWidth, layoutHeight);
 
 		// Calculate vertical scrollbar bounds
 		if (hasVertScrollbar)
 		{
-			INT32 scrollBarOffset = (UINT32)std::max(0, (INT32)width - (INT32)ScrollBarWidth);
-			UINT32 scrollBarHeight = height;
+			INT32 scrollBarOffset = (UINT32)std::max(0, (INT32)layoutArea.width - (INT32)ScrollBarWidth);
+			UINT32 scrollBarHeight = layoutArea.height;
 			if (hasHorzScrollbar)
 				scrollBarHeight = (UINT32)std::max(0, (INT32)scrollBarHeight - (INT32)ScrollBarWidth);
 
-			elementAreas[vertScrollIdx] = Rect2I(x + scrollBarOffset, y, ScrollBarWidth, scrollBarHeight);
+			elementAreas[vertScrollIdx] = Rect2I(layoutArea.x + scrollBarOffset, layoutArea.y, ScrollBarWidth, scrollBarHeight);
 		}
 		else
 		{
-			elementAreas[vertScrollIdx] = Rect2I(x + layoutWidth, y, 0, 0);
+			elementAreas[vertScrollIdx] = Rect2I(layoutArea.x + layoutWidth, layoutArea.y, 0, 0);
 		}
 
 		// Calculate horizontal scrollbar bounds
 		if (hasHorzScrollbar)
 		{
-			INT32 scrollBarOffset = (UINT32)std::max(0, (INT32)height - (INT32)ScrollBarWidth);
-			UINT32 scrollBarWidth = width;
+			INT32 scrollBarOffset = (UINT32)std::max(0, (INT32)layoutArea.height - (INT32)ScrollBarWidth);
+			UINT32 scrollBarWidth = layoutArea.width;
 			if (hasVertScrollbar)
 				scrollBarWidth = (UINT32)std::max(0, (INT32)scrollBarWidth - (INT32)ScrollBarWidth);
 
-			elementAreas[horzScrollIdx] = Rect2I(x, y + scrollBarOffset, scrollBarWidth, ScrollBarWidth);
+			elementAreas[horzScrollIdx] = Rect2I(layoutArea.x, layoutArea.y + scrollBarOffset, scrollBarWidth, ScrollBarWidth);
 		}
 		else
 		{
-			elementAreas[horzScrollIdx] = Rect2I(x, y + layoutHeight, 0, 0);
+			elementAreas[horzScrollIdx] = Rect2I(layoutArea.x, layoutArea.y + layoutHeight, 0, 0);
 		}
 	}
 
-	void GUIScrollArea::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-		Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUIScrollArea::_updateLayoutInternal(const GUILayoutData& data)
 	{
 		UINT32 numElements = (UINT32)mChildren.size();
 		Rect2I* elementAreas = nullptr;
@@ -216,49 +215,44 @@ namespace BansheeEngine
 				vertScrollIdx = i;
 		}
 
-		_getElementAreas(x, y, width, height, elementAreas, numElements, sizeRanges, mVisibleSize, mContentSize);
+		_getElementAreas(data.area, elementAreas, numElements, sizeRanges, mVisibleSize, mContentSize);
 
 		Rect2I& layoutBounds = elementAreas[layoutIdx];
 		Rect2I& horzScrollBounds = elementAreas[horzScrollIdx];
 		Rect2I& vertScrollBounds = elementAreas[vertScrollIdx];
 
 		// Layout
-		Rect2I layoutClipRect = clipRect;
+		Rect2I layoutClipRect = data.clipRect;
 		layoutClipRect.width = (UINT32)mVisibleSize.x;
 		layoutClipRect.height = (UINT32)mVisibleSize.y;
 
-		mContentLayout->_setPosition(Vector2I(layoutBounds.x, layoutBounds.y));
-		mContentLayout->_setWidth(layoutBounds.width);
-		mContentLayout->_setHeight(layoutBounds.height);
-		mContentLayout->_setWidgetDepth(widgetDepth);
-		mContentLayout->_setAreaDepth(panelDepth);
-		mContentLayout->_setPanelDepthRange(panelDepthRangeMin, panelDepthRangeMax);
+		GUILayoutData layoutData = data;
+		layoutData.area = layoutBounds;
+		layoutData.clipRect = layoutClipRect;
+		layoutData.clipRect.x -= layoutBounds.x;
+		layoutData.clipRect.y -= layoutBounds.y;
 
-		Rect2I localClipRect(layoutClipRect.x - layoutBounds.x, layoutClipRect.y - layoutBounds.y, layoutClipRect.width, layoutClipRect.height);
-		mContentLayout->_setClipRect(localClipRect);
+		mContentLayout->_setLayoutData(layoutData);
 
-		mContentLayout->_updateLayoutInternal(layoutBounds.x, layoutBounds.y,
-			layoutBounds.width, layoutBounds.height, layoutClipRect, 
-			widgetDepth, panelDepth, panelDepthRangeMin, panelDepthRangeMax);
+		layoutData.clipRect = layoutClipRect;
+
+		mContentLayout->_updateLayoutInternal(layoutData);
 
 		// Vertical scrollbar
 		{
-			mVertScroll->_setPosition(Vector2I(vertScrollBounds.x, vertScrollBounds.y));
-			mVertScroll->_setWidth(vertScrollBounds.width);
-			mVertScroll->_setHeight(vertScrollBounds.height);
-			mVertScroll->_setAreaDepth(panelDepth);
-			mVertScroll->_setWidgetDepth(widgetDepth);
-			mVertScroll->_setPanelDepthRange(panelDepthRangeMin, panelDepthRangeMax);
+			GUILayoutData vertScrollData = data;
+			vertScrollData.area = vertScrollBounds;
+
+			UINT32 clippedScrollbarWidth = std::min((UINT32)data.area.width, ScrollBarWidth);
+			vertScrollData.clipRect = Rect2I(0, 0, clippedScrollbarWidth, data.clipRect.height);
+
+			mVertScroll->_setLayoutData(layoutData);
 
-			UINT32 clippedScrollbarWidth = std::min(width, ScrollBarWidth);
-			Rect2I elemClipRect(0, 0, clippedScrollbarWidth, clipRect.height);
-			mVertScroll->_setClipRect(elemClipRect);
+			vertScrollData.clipRect = Rect2I(data.clipRect.x + (vertScrollBounds.x - data.area.x), 
+				data.clipRect.y + (vertScrollBounds.y - data.area.y), clippedScrollbarWidth, data.clipRect.height);
 
 			// This element is not a child of any layout so we treat it as a root element
-			Rect2I scrollBarLayoutClipRect(clipRect.x + (vertScrollBounds.x - x), clipRect.y + (vertScrollBounds.y - y), clippedScrollbarWidth, clipRect.height);
-			mVertScroll->_updateLayout(vertScrollBounds.x, vertScrollBounds.y, vertScrollBounds.width, 
-				vertScrollBounds.height, scrollBarLayoutClipRect, widgetDepth, panelDepth, 
-				panelDepthRangeMin, panelDepthRangeMax);
+			mVertScroll->_updateLayout(vertScrollData);
 
 			// Set new handle size and update position to match the new size
 			UINT32 newHandleSize = (UINT32)Math::floorToInt(mVertScroll->getMaxHandleSize() * (vertScrollBounds.height / (float)mContentSize.y));
@@ -276,21 +270,17 @@ namespace BansheeEngine
 
 		// Horizontal scrollbar
 		{
-			mHorzScroll->_setPosition(Vector2I(horzScrollBounds.x, horzScrollBounds.y));
-			mHorzScroll->_setWidth(horzScrollBounds.width);
-			mHorzScroll->_setHeight(horzScrollBounds.height);
-			mHorzScroll->_setAreaDepth(panelDepth);
-			mHorzScroll->_setWidgetDepth(widgetDepth);
-			mVertScroll->_setPanelDepthRange(panelDepthRangeMin, panelDepthRangeMax);
+			GUILayoutData horzScrollData = data;
+			horzScrollData.area = horzScrollBounds;
 
-			UINT32 clippedScrollbarHeight = std::min(height, ScrollBarWidth);
-			Rect2I elemClipRect(0, 0, clipRect.width, clippedScrollbarHeight);
-			mHorzScroll->_setClipRect(elemClipRect);
+			UINT32 clippedScrollbarHeight = std::min((UINT32)data.area.height, ScrollBarWidth);
+			horzScrollData.clipRect = Rect2I(0, 0, data.clipRect.width, clippedScrollbarHeight);
+			mHorzScroll->_setLayoutData(horzScrollData);
 
 			// This element is not a child of any layout so we treat it as a root element
-			Rect2I scrollBarLayoutClipRect(clipRect.x + (horzScrollBounds.x - x), clipRect.y + (horzScrollBounds.y - y), clipRect.width, clippedScrollbarHeight);
-			mHorzScroll->_updateLayout(horzScrollBounds.x, horzScrollBounds.y, horzScrollBounds.width, 
-				horzScrollBounds.height, scrollBarLayoutClipRect, widgetDepth, panelDepth, panelDepthRangeMin, panelDepthRangeMax);
+			horzScrollData.clipRect = Rect2I(data.clipRect.x + (horzScrollBounds.x - data.area.x), 
+				data.clipRect.y + (horzScrollBounds.y - data.area.y), data.clipRect.width, clippedScrollbarHeight);
+			mHorzScroll->_updateLayout(horzScrollData);
 
 			// Set new handle size and update position to match the new size
 			UINT32 newHandleSize = (UINT32)Math::floorToInt(mHorzScroll->getMaxHandleSize() * (horzScrollBounds.width / (float)mContentSize.x));
@@ -325,7 +315,7 @@ namespace BansheeEngine
 		UINT32 scrollableHeight = (UINT32)std::max(0, INT32(mContentSize.y) - INT32(mVisibleSize.y));
 		mVertOffset = scrollableHeight * Math::clamp01(pct);
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUIScrollArea::scrollToHorizontal(float pct)
@@ -333,7 +323,7 @@ namespace BansheeEngine
 		UINT32 scrollableWidth = (UINT32)std::max(0, INT32(mContentSize.x) - INT32(mVisibleSize.x));
 		mHorzOffset = scrollableWidth * Math::clamp01(pct);
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	float GUIScrollArea::getVerticalScroll() const
@@ -352,7 +342,7 @@ namespace BansheeEngine
 		return 0.0f;
 	}
 
-	Rect2I GUIScrollArea::getContentBounds() const
+	Rect2I GUIScrollArea::getContentBounds()
 	{
 		Rect2I bounds = getBounds();
 

+ 7 - 5
BansheeEngine/Source/BsGUIScrollBar.cpp

@@ -91,8 +91,8 @@ namespace BansheeEngine
 		if(_getStyle()->normal.texture != nullptr && _getStyle()->normal.texture.isLoaded())
 			desc.texture = _getStyle()->normal.texture.getInternalPtr();
 
-		desc.width = mWidth;
-		desc.height = mHeight;
+		desc.width = mLayoutData.area.width;
+		desc.height = mLayoutData.area.height;
 		desc.color = mColor;
 
 		mImageSprite->update(desc, (UINT64)_getParentWidget());
@@ -123,7 +123,9 @@ namespace BansheeEngine
 	void GUIScrollBar::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 	{
-		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx, mOffset, mClipRect);
+		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
+		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, 
+			vertexStride, indexStride, renderElementIdx, offset, mLayoutData.clipRect);
 	}
 
 	void GUIScrollBar::handleMoved(float handlePct)
@@ -159,7 +161,7 @@ namespace BansheeEngine
 		float newHandlePos = Math::clamp01(mHandleBtn->getHandlePos() - amount);
 
 		mHandleBtn->_setHandlePos(newHandlePos);
-		mHandleBtn->markContentAsDirty();
+		mHandleBtn->_markContentAsDirty();
 
 		if(!onScrollPositionChanged.empty())
 			onScrollPositionChanged(newHandlePos);
@@ -194,6 +196,6 @@ namespace BansheeEngine
 	{
 		mColor = color;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 }

+ 7 - 17
BansheeEngine/Source/BsGUISlider.cpp

@@ -52,25 +52,15 @@ namespace BansheeEngine
 		return optimalSize;
 	}
 
-	void GUISlider::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-		Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUISlider::_updateLayoutInternal(const GUILayoutData& data)
 	{
-		Vector2I offset(x, y);
-		Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
+		GUILayoutData childData = data;
 
-		mBackground->_setPosition(offset);
-		mBackground->_setWidth(width);
-		mBackground->_setHeight(height);
-		mBackground->_setAreaDepth(panelDepth);
-		mBackground->_setWidgetDepth(widgetDepth);
-		mBackground->_setClipRect(elemClipRect);
+		childData.clipRect = Rect2I(data.clipRect.x - data.area.x, data.clipRect.y - data.area.y, 
+			data.clipRect.width, data.clipRect.height);
 
-		mSliderHandle->_setPosition(offset);
-		mSliderHandle->_setWidth(width);
-		mSliderHandle->_setHeight(height);
-		mSliderHandle->_setAreaDepth(panelDepth);
-		mSliderHandle->_setWidgetDepth(widgetDepth);
-		mSliderHandle->_setClipRect(elemClipRect);
+		mBackground->_setLayoutData(childData);
+		mSliderHandle->_setLayoutData(childData);
 	}
 
 	void GUISlider::styleUpdated()
@@ -82,7 +72,7 @@ namespace BansheeEngine
 	void GUISlider::setPercent(float pct)
 	{
 		mSliderHandle->_setHandlePos(pct);
-		mSliderHandle->markContentAsDirty();
+		mSliderHandle->_markContentAsDirty();
 	}
 
 	float GUISlider::getPercent() const

+ 28 - 26
BansheeEngine/Source/BsGUISliderHandle.cpp

@@ -65,7 +65,7 @@ namespace BansheeEngine
 	{
 		mColor = color;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	UINT32 GUISliderHandle::_getNumRenderElements() const
@@ -97,14 +97,14 @@ namespace BansheeEngine
 				mHandleSize = desc.texture->getWidth();
 
 			desc.width = mHandleSize;
-			desc.height = mHeight;
+			desc.height = mLayoutData.area.height;
 		}
 		else
 		{
 			if (mHandleSize == 0 && desc.texture != nullptr)
 				mHandleSize = desc.texture->getHeight();
 
-			desc.width = mWidth;
+			desc.width = mLayoutData.area.width;
 			desc.height = mHandleSize;
 		}
 
@@ -116,9 +116,11 @@ namespace BansheeEngine
 
 	void GUISliderHandle::updateClippedBounds()
 	{
-		mClippedBounds = Rect2I(mOffset.x, mOffset.y, mWidth, mHeight);
+		mClippedBounds = mLayoutData.area;
 
-		Rect2I localClipRect(mClipRect.x + mOffset.x, mClipRect.y + mOffset.y, mClipRect.width, mClipRect.height);
+		Rect2I localClipRect = mLayoutData.clipRect;
+		localClipRect.x += mLayoutData.area.x;
+		localClipRect.y += mLayoutData.area.y;
 		mClippedBounds.clip(localClipRect);
 	}
 
@@ -135,13 +137,13 @@ namespace BansheeEngine
 	void GUISliderHandle::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 	{
-		Vector2I offset = mOffset;
+		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
 		if(mHorizontal)
 			offset.x += getHandlePosPx();
 		else
 			offset.y += getHandlePosPx();
 
-		Rect2I clipRect = mClipRect;
+		Rect2I clipRect = mLayoutData.clipRect;
 		if(mHorizontal)
 			clipRect.x -= getHandlePosPx();
 		else
@@ -162,7 +164,7 @@ namespace BansheeEngine
 					mMouseOverHandle = false;
 
 					mState = State::Normal;
-					markContentAsDirty();
+					_markContentAsDirty();
 
 					return true;
 				}
@@ -174,7 +176,7 @@ namespace BansheeEngine
 					mMouseOverHandle = true;
 
 					mState = State::Hover;
-					markContentAsDirty();
+					_markContentAsDirty();
 
 					return true;
 				}
@@ -184,16 +186,16 @@ namespace BansheeEngine
 		if(ev.getType() == GUIMouseEventType::MouseDown && (mMouseOverHandle || mJumpOnClick))
 		{
 			mState = State::Active;
-			markContentAsDirty();
+			_markContentAsDirty();
 
 			if (mJumpOnClick)
 			{
 				float handlePosPx = 0.0f;
 
 				if (mHorizontal)
-					handlePosPx = (float)(ev.getPosition().x - (INT32)mOffset.x - mHandleSize * 0.5f);
+					handlePosPx = (float)(ev.getPosition().x - (INT32)mLayoutData.area.x - mHandleSize * 0.5f);
 				else
-					handlePosPx = (float)(ev.getPosition().y - (INT32)mOffset.y - mHandleSize * 0.5f);
+					handlePosPx = (float)(ev.getPosition().y - (INT32)mLayoutData.area.y - mHandleSize * 0.5f);
 
 				float maxScrollAmount = (float)getMaxSize() - mHandleSize;
 				mPctHandlePos = Math::clamp01(handlePosPx / maxScrollAmount);
@@ -201,12 +203,12 @@ namespace BansheeEngine
 
 			if(mHorizontal)
 			{
-				INT32 left = (INT32)mOffset.x + getHandlePosPx();
+				INT32 left = (INT32)mLayoutData.area.x + getHandlePosPx();
 				mDragStartPos = ev.getPosition().x - left;
 			}
 			else
 			{
-				INT32 top = (INT32)mOffset.y + getHandlePosPx();
+				INT32 top = (INT32)mLayoutData.area.y + getHandlePosPx();
 				mDragStartPos = ev.getPosition().y - top;
 			}
 
@@ -219,11 +221,11 @@ namespace BansheeEngine
 			float handlePosPx = 0.0f;
 			if(mHorizontal)
 			{
-				handlePosPx = (float)(ev.getPosition().x - mDragStartPos - mOffset.x);
+				handlePosPx = (float)(ev.getPosition().x - mDragStartPos - mLayoutData.area.x);
 			}
 			else
 			{
-				handlePosPx = (float)(ev.getPosition().y - mDragStartPos - mOffset.y);
+				handlePosPx = (float)(ev.getPosition().y - mDragStartPos - mLayoutData.area.y);
 			}
 
 			float maxScrollAmount = (float)getMaxSize() - mHandleSize;
@@ -231,7 +233,7 @@ namespace BansheeEngine
 
 			onHandleMoved(mPctHandlePos);
 
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 
@@ -239,7 +241,7 @@ namespace BansheeEngine
 		{
 			mState = State::Normal;
 			mMouseOverHandle = false;
-			markContentAsDirty();
+			_markContentAsDirty();
 
 			return true;
 		}
@@ -258,7 +260,7 @@ namespace BansheeEngine
 				INT32 handleOffset = 0;
 				if (mHorizontal)
 				{
-					INT32 handleLeft = (INT32)mOffset.x + handlePosPx;
+					INT32 handleLeft = (INT32)mLayoutData.area.x + handlePosPx;
 					INT32 handleRight = handleLeft + mHandleSize;
 
 					if (ev.getPosition().x < handleLeft)
@@ -268,7 +270,7 @@ namespace BansheeEngine
 				}
 				else
 				{
-					INT32 handleTop = (INT32)mOffset.y + handlePosPx;
+					INT32 handleTop = (INT32)mLayoutData.area.y + handlePosPx;
 					INT32 handleBottom = handleTop + mHandleSize;
 
 					if (ev.getPosition().y < handleTop)
@@ -285,7 +287,7 @@ namespace BansheeEngine
 
 			onHandleMoved(mPctHandlePos);
 
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 
@@ -298,7 +300,7 @@ namespace BansheeEngine
 			else
 				mState = State::Normal;
 
-			markContentAsDirty();
+			_markContentAsDirty();
 			return true;
 		}
 		
@@ -309,7 +311,7 @@ namespace BansheeEngine
 	{
 		if(mHorizontal)
 		{
-			INT32 left = (INT32)mOffset.x + getHandlePosPx();
+			INT32 left = (INT32)mLayoutData.area.x + getHandlePosPx();
 			INT32 right = left + mHandleSize;
 
 			if(pos.x >= left && pos.x < right)
@@ -317,7 +319,7 @@ namespace BansheeEngine
 		}
 		else
 		{
-			INT32 top = (INT32)mOffset.y + getHandlePosPx();
+			INT32 top = (INT32)mLayoutData.area.y + getHandlePosPx();
 			INT32 bottom = top + mHandleSize;
 
 			if(pos.y >= top && pos.y < bottom)
@@ -335,9 +337,9 @@ namespace BansheeEngine
 
 	UINT32 GUISliderHandle::getMaxSize() const
 	{
-		UINT32 maxSize = mHeight;
+		UINT32 maxSize = mLayoutData.area.height;
 		if(mHorizontal)
-			maxSize = mWidth;
+			maxSize = mLayoutData.area.width;
 
 		return maxSize;
 	}

+ 19 - 16
BansheeEngine/Source/BsGUITexture.cpp

@@ -107,7 +107,7 @@ namespace BansheeEngine
 	{
 		mColor = color;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	void GUITexture::setTexture(const HSpriteTexture& texture)
@@ -115,7 +115,7 @@ namespace BansheeEngine
 		mActiveTexture = texture;
 		mUsingStyleTexture = false;
 
-		markContentAsDirty();
+		_markContentAsDirty();
 	}
 
 	UINT32 GUITexture::_getNumRenderElements() const
@@ -135,8 +135,8 @@ namespace BansheeEngine
 
 	void GUITexture::updateRenderElementsInternal()
 	{		
-		mDesc.width = mWidth;
-		mDesc.height = mHeight;
+		mDesc.width = mLayoutData.area.width;
+		mDesc.height = mLayoutData.area.height;
 
 		mDesc.borderLeft = _getStyle()->border.left;
 		mDesc.borderRight = _getStyle()->border.right;
@@ -160,40 +160,40 @@ namespace BansheeEngine
 			mDesc.uvScale = Vector2(1.0f, 1.0f);
 			break;
 		case GUIImageScaleMode::ScaleToFit:
-			mDesc.uvScale.x = optimalWidth / mWidth;
-			mDesc.uvScale.y = optimalHeight / mHeight;
+			mDesc.uvScale.x = optimalWidth / mLayoutData.area.width;
+			mDesc.uvScale.y = optimalHeight / mLayoutData.area.height;
 
 			if(mDesc.uvScale.x < mDesc.uvScale.y)
 			{
 				mDesc.uvScale.x = 1.0f;
-				mDesc.uvScale.y = (mWidth * (optimalHeight / optimalWidth)) / mHeight;
+				mDesc.uvScale.y = (mLayoutData.area.width * (optimalHeight / optimalWidth)) / mLayoutData.area.height;
 			}
 			else
 			{
-				mDesc.uvScale.x = (mHeight * (optimalWidth / optimalHeight)) / mWidth;
+				mDesc.uvScale.x = (mLayoutData.area.height * (optimalWidth / optimalHeight)) / mLayoutData.area.width;
 				mDesc.uvScale.y = 1.0f;
 			}
 
 			break;
 		case GUIImageScaleMode::CropToFit:
-			mDesc.uvScale.x = optimalWidth / mWidth;
-			mDesc.uvScale.y = optimalHeight / mHeight;
+			mDesc.uvScale.x = optimalWidth / mLayoutData.area.width;
+			mDesc.uvScale.y = optimalHeight / mLayoutData.area.height;
 
 			if(mDesc.uvScale.x < mDesc.uvScale.y)
 			{
-				mDesc.uvScale.x = (mHeight * (optimalWidth / optimalHeight)) / mWidth;
+				mDesc.uvScale.x = (mLayoutData.area.height * (optimalWidth / optimalHeight)) / mLayoutData.area.width;
 				mDesc.uvScale.y = 1.0f;
 			}
 			else
 			{
 				mDesc.uvScale.x = 1.0f;
-				mDesc.uvScale.y = (mWidth * (optimalHeight / optimalWidth)) / mHeight;
+				mDesc.uvScale.y = (mLayoutData.area.width * (optimalHeight / optimalWidth)) / mLayoutData.area.height;
 			}
 
 			break;
 		case GUIImageScaleMode::RepeatToFit:
-			mDesc.uvScale.x = mWidth / optimalWidth;
-			mDesc.uvScale.y = mHeight / optimalHeight;
+			mDesc.uvScale.x = mLayoutData.area.width / optimalWidth;
+			mDesc.uvScale.y = mLayoutData.area.height / optimalHeight;
 			break;
 		default:
 			break;
@@ -206,7 +206,8 @@ namespace BansheeEngine
 
 	void GUITexture::updateClippedBounds()
 	{
-		mClippedBounds = mImageSprite->getBounds(mOffset, mClipRect);
+		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
+		mClippedBounds = mImageSprite->getBounds(offset, mLayoutData.clipRect);
 	}
 
 	void GUITexture::styleUpdated()
@@ -245,6 +246,8 @@ namespace BansheeEngine
 	void GUITexture::_fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 	{
-		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx, mOffset, mClipRect);
+		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
+		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, 
+			vertexStride, indexStride, renderElementIdx, offset, mLayoutData.clipRect);
 	}
 }

+ 9 - 9
BansheeEngine/Source/BsGUIViewport.cpp

@@ -57,10 +57,10 @@ namespace BansheeEngine
 
 	void GUIViewport::updateClippedBounds()
 	{
-		Rect2I mBounds = Rect2I(0, 0, mWidth, mHeight);
-		mBounds.clip(mClipRect);
-		mBounds.x += mOffset.x;
-		mBounds.y += mOffset.y;
+		Rect2I mBounds = Rect2I(0, 0, mLayoutData.area.width, mLayoutData.area.height);
+		mBounds.clip(mLayoutData.clipRect);
+		mBounds.x += mLayoutData.area.x;
+		mBounds.y += mLayoutData.area.y;
 	}
 
 	Vector2I GUIViewport::_getOptimalSize() const
@@ -77,7 +77,7 @@ namespace BansheeEngine
 	void GUIViewport::updateRenderElementsInternal()
 	{
 		// TODO - This doesn't get called if element mesh is dirty!!! and I need to update the viewport when offset changes (in which case mesh is marked as dirty)
-		float currentAspect = mWidth / (float)mHeight;
+		float currentAspect = mLayoutData.area.width / (float)mLayoutData.area.height;
 		Radian currentFOV = 2.0f * Math::atan(Math::tan(mVerticalFOV * 0.5f) * currentAspect);
 
 		mCamera->setHorzFOV(currentFOV);
@@ -86,10 +86,10 @@ namespace BansheeEngine
 		RenderTargetPtr renderTarget = viewport->getTarget();
 		const RenderTargetProperties& rtProps = renderTarget->getProperties();
 
-		float x = mOffset.x / (float)rtProps.getWidth();
-		float y = mOffset.y / (float)rtProps.getHeight();
-		float width = mWidth / (float)rtProps.getWidth();
-		float height = mHeight / (float)rtProps.getHeight();
+		float x = mLayoutData.area.x / (float)rtProps.getWidth();
+		float y = mLayoutData.area.y / (float)rtProps.getHeight();
+		float width = mLayoutData.area.width / (float)rtProps.getWidth();
+		float height = mLayoutData.area.height / (float)rtProps.getHeight();
 
 		viewport->setArea(x, y, width, height);
 	}

+ 60 - 61
BansheeEngine/Source/BsGUIWidget.cpp

@@ -135,8 +135,6 @@ namespace BansheeEngine
 				{
 					elementsToUpdate.insert(std::make_pair(mPanel, false));
 				}
-
-				currentElem->_markAsClean();
 			}
 
 			UINT32 numChildren = currentElem->_getNumChildren();
@@ -147,10 +145,9 @@ namespace BansheeEngine
 		// Determine top-level layouts and update them
 		for (auto& elemData : elementsToUpdate)
 		{
-			bool isPanelOptimized = elemData.second;
-
 			GUIElementBase* updateParent = nullptr;
-			
+
+			bool isPanelOptimized = elemData.second;
 			if (isPanelOptimized)
 				updateParent = elemData.first->_getParent();
 			else
@@ -173,72 +170,70 @@ namespace BansheeEngine
 			if (!isTopLevel)
 				continue;
 
-			// For GUIPanel we can do a an optimization and update only the element in question instead
-			// of all the children
-			if (isPanelOptimized)
-			{
-				GUIPanel* panel = static_cast<GUIPanel*>(updateParent);
+			_updateLayout(elemData.first);
+		}
+	}
 
-				INT32 x = panel->_getOffset().x;
-				INT32 y = panel->_getOffset().y;
-				UINT32 width = panel->_getWidth();
-				UINT32 height = panel->_getHeight();
+	void GUIWidget::_updateLayout(GUIElementBase* elem)
+	{
+		GUIElementBase* parent = elem->_getParent();
+		bool isPanelOptimized = parent != nullptr && parent->_getType() == GUIElementBase::Type::Panel;
 
-				GUIElementBase* dirtyElement = elemData.first;
-				dirtyElement->_updateOptimalLayoutSizes();
+		GUIElementBase* updateParent = nullptr;
 
-				LayoutSizeRange elementSizeRange = panel->_getElementSizeRange(dirtyElement);
-				Rect2I elementArea = panel->_getElementArea(x, y, width, height, dirtyElement, elementSizeRange);
+		if (isPanelOptimized)
+			updateParent = parent;
+		else
+			updateParent = elem;
 
-				INT16 panelDepth = panel->_getAreaDepth();
-				UINT16 panelDepthRangeMin = -1;
-				UINT16 panelDepthRangeMax = -1;
+		// For GUIPanel we can do a an optimization and update only the element in question instead
+		// of all the children
+		if (isPanelOptimized)
+		{
+			GUIPanel* panel = static_cast<GUIPanel*>(updateParent);
 
-				panel->_getPanelDepthRange(panelDepthRangeMin, panelDepthRangeMax);
+			GUIElementBase* dirtyElement = elem;
+			dirtyElement->_updateOptimalLayoutSizes();
 
-				Rect2I clipRect = panel->_getClipRect();
-				clipRect.x += x;
-				clipRect.y += y;
+			LayoutSizeRange elementSizeRange = panel->_getElementSizeRange(dirtyElement);
+			Rect2I elementArea = panel->_getElementArea(panel->_getLayoutData().area, dirtyElement, elementSizeRange);
 
-				panel->_updateChildLayout(dirtyElement, elementArea, clipRect, mDepth, panelDepth, panelDepthRangeMin, panelDepthRangeMax);
-			}
-			else
-			{
-				INT32 x = updateParent->_getOffset().x;
-				INT32 y = updateParent->_getOffset().y;
-				UINT32 width = updateParent->_getWidth();
-				UINT32 height = updateParent->_getHeight();
+			GUILayoutData childLayoutData = panel->_getLayoutData();
+
+			childLayoutData.clipRect.x += childLayoutData.area.x;
+			childLayoutData.clipRect.y += childLayoutData.area.y;
+
+			childLayoutData.area = elementArea;
 
-				INT16 panelDepth = updateParent->_getAreaDepth();
-				UINT16 panelDepthRangeMin = -1;
-				UINT16 panelDepthRangeMax = -1;
+			panel->_updateChildLayout(dirtyElement, childLayoutData);
+		}
+		else
+		{
+			GUILayoutData childLayoutData = updateParent->_getLayoutData();
 
-				updateParent->_getPanelDepthRange(panelDepthRangeMin, panelDepthRangeMax);
+			childLayoutData.clipRect.x += childLayoutData.area.x;
+			childLayoutData.clipRect.y += childLayoutData.area.y;
 
-				Rect2I clipRect = updateParent->_getClipRect();
-				clipRect.x += x;
-				clipRect.y += y;
+			updateParent->_updateLayout(childLayoutData);
+		}
 
-				updateParent->_updateLayout(x, y, width, height, clipRect, getDepth(), 
-					panelDepth, panelDepthRangeMin, panelDepthRangeMax);
-			}
+		// Mark dirty contents
+		Stack<GUIElementBase*> todo;
+		todo.push(updateParent);
 
-			// Mark dirty contents
-			Stack<GUIElementBase*> todo;
-			todo.push(mPanel);
+		while (!todo.empty())
+		{
+			GUIElementBase* currentElem = todo.top();
+			todo.pop();
 
-			while (!todo.empty())
-			{
-				GUIElementBase* currentElem = todo.top();
-				todo.pop();
+			if (currentElem->_getType() == GUIElementBase::Type::Element)
+				mDirtyContents.insert(static_cast<GUIElement*>(currentElem));
 
-				if (currentElem->_getType() == GUIElementBase::Type::Element)
-					mDirtyContents.push_back(static_cast<GUIElement*>(currentElem));
+			currentElem->_markAsClean();
 
-				UINT32 numChildren = currentElem->_getNumChildren();
-				for (UINT32 i = 0; i < numChildren; i++)
-					todo.push(currentElem->_getChild(i));
-			}
+			UINT32 numChildren = currentElem->_getNumChildren();
+			for (UINT32 i = 0; i < numChildren; i++)
+				todo.push(currentElem->_getChild(i));
 		}
 	}
 
@@ -283,6 +278,9 @@ namespace BansheeEngine
 			mElements.erase(iterFind);
 			mWidgetIsDirty = true;
 		}
+
+		if (elem->_getType() == GUIElementBase::Type::Element)
+			mDirtyContents.erase(static_cast<GUIElement*>(elem));
 	}
 
 	void GUIWidget::_markMeshDirty(GUIElementBase* elem)
@@ -362,15 +360,16 @@ namespace BansheeEngine
 		UINT32 width = getTarget()->getWidth();
 		UINT32 height = getTarget()->getHeight();
 
-		mPanel->_setWidth(width);
-		mPanel->_setHeight(height);
+		GUILayoutData layoutData;
+		layoutData.area.width = width;
+		layoutData.area.height = height;
+		layoutData.clipRect = Rect2I(0, 0, width, height);
 
 		mPanel->setWidth(width);
 		mPanel->setHeight(height);
 
-		Rect2I clipRect(0, 0, width, height);
-		mPanel->_setClipRect(clipRect);
-		mPanel->markContentAsDirty();
+		mPanel->_setLayoutData(layoutData);
+		mPanel->_markContentAsDirty();
 	}
 
 	void GUIWidget::ownerWindowFocusChanged()

+ 1 - 2
SBansheeEditor/Include/BsGUIGameObjectField.h

@@ -51,8 +51,7 @@ namespace BansheeEngine
 		 */
 		virtual void setTint(const Color& color);
 
-		void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		void _updateLayoutInternal(const GUILayoutData& data);
 
 		Vector2I _getOptimalSize() const;
 

+ 1 - 2
SBansheeEditor/Include/BsGUIResourceField.h

@@ -54,8 +54,7 @@ namespace BansheeEngine
 		 */
 		virtual void setTint(const Color& color);
 
-		void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-			Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax);
+		void _updateLayoutInternal(const GUILayoutData& data);
 
 		Vector2I _getOptimalSize() const;
 

+ 8 - 11
SBansheeEditor/Source/BsGUIGameObjectField.cpp

@@ -193,20 +193,17 @@ namespace BansheeEngine
 		mClearButton->setTint(color);
 	}
 
-	void GUIGameObjectField::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-		Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUIGameObjectField::_updateLayoutInternal(const GUILayoutData& data)
 	{
-		mLayout->_setPosition(Vector2I(x, y));
-		mLayout->_setWidth(width);
-		mLayout->_setHeight(height);
-		mLayout->_setWidgetDepth(widgetDepth);
-		mLayout->_setAreaDepth(panelDepth);
-		mLayout->_setPanelDepthRange(panelDepthRangeMin, panelDepthRangeMax);
+		GUILayoutData childData = data;
+		childData.clipRect.x -= data.area.x;
+		childData.clipRect.y -= data.area.y;
 
-		Rect2I elemClipRect(clipRect.x - x, clipRect.y - y, clipRect.width, clipRect.height);
-		mLayout->_setClipRect(elemClipRect);
+		mLayout->_setLayoutData(childData);
 
-		mLayout->_updateLayoutInternal(x, y, width, height, clipRect, widgetDepth, panelDepth, panelDepthRangeMin, panelDepthRangeMax);
+		childData.clipRect = data.clipRect;
+
+		mLayout->_updateLayoutInternal(childData);
 	}
 
 	Vector2I GUIGameObjectField::_getOptimalSize() const

+ 10 - 14
SBansheeEditor/Source/BsGUIResourceField.cpp

@@ -198,21 +198,17 @@ namespace BansheeEngine
 		mClearButton->setTint(color);
 	}
 
-	void GUIResourceField::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
-		Rect2I clipRect, UINT8 widgetDepth, INT16 panelDepth, UINT16 panelDepthRangeMin, UINT16 panelDepthRangeMax)
+	void GUIResourceField::_updateLayoutInternal(const GUILayoutData& data)
 	{
-		mLayout->_setPosition(Vector2I(x, y));
-		mLayout->_setWidth(width);
-		mLayout->_setHeight(height);
-		mLayout->_setWidgetDepth(widgetDepth);
-		mLayout->_setAreaDepth(panelDepth);
-		mLayout->_setPanelDepthRange(panelDepthRangeMin, panelDepthRangeMax);
-
-		Rect2I elemClipRect(clipRect.x - x, clipRect.y - y, clipRect.width, clipRect.height);
-		mLayout->_setClipRect(elemClipRect);
-
-		mLayout->_updateLayoutInternal(x, y, width, height, clipRect, widgetDepth, 
-			panelDepth, panelDepthRangeMin, panelDepthRangeMax);
+		GUILayoutData childData = data;
+		childData.clipRect.x -= data.area.x;
+		childData.clipRect.y -= data.area.y;
+
+		mLayout->_setLayoutData(childData);
+
+		childData.clipRect = data.clipRect;
+
+		mLayout->_updateLayoutInternal(childData);
 	}
 
 	Vector2I GUIResourceField::_getOptimalSize() const

+ 1 - 1
SBansheeEngine/Source/BsScriptGUILayoutUtility.cpp

@@ -33,6 +33,6 @@ namespace BansheeEngine
 		if (relativeTo != nullptr)
 			relativeToPanel = static_cast<GUIPanel*>(relativeTo->getGUIElement());
 
-		*output = GUILayoutUtility::calcBounds(guiElement->getGUIElement(), relativeToPanel);
+		*output = guiElement->getGUIElement()->getBounds(relativeToPanel);
 	}
 }

+ 8 - 12
TODO.txt

@@ -32,21 +32,17 @@ Add C# Renderable
 ----------------------------------------------------------------------
 Project window
 
+Potential issue: isPanelOptimize is now determined on the fly in _updateLayout but it can trigger
+ on elements that were originally imaged to be panel optimized (but the end result /should/ be the same)
+
+Root panel isn't being updated properly
+Positions in color picker are screwed up
+Depth in COlorPicker is fucked up
+Test dock manager and sliders (right now it doesn't seem to work at all)
+
 Later:
- - Switch bound calculations to the new system
- - Get rid of _calculateLayoutSizeRange as I don't need it without GUILayoutUtility::calcBounds
  - Unify position, width, height, depth, depthMin, depthMax, layoutClipRect, elementClipRect into a single structure
    - So I don't need to call 6 different _set methods in _updateLayoutInternal, and so that _updateLayoutInternal doesn't have as many parameters
- - Rename markContentAsDirty and markMeshAsDirty so they have a _ prefix since they're now internal
- - Rename get/setAreaDepth to get/setPanelDepth
-
- getBounds
-{
-   if(mUpdateParent != nullptr && mUpdateParent->mIsDirty)
-      mUpdateParent->_updateLayout();
-
-   return _getCachedBounds();
-}
 
 Simple tasks:
  - Add C# Renderable interface