Browse Source

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

Marko Pintera 10 years ago
parent
commit
22cf8a4b76
68 changed files with 867 additions and 1121 deletions
  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