Browse Source

Added enable/disable functionality for GUI elements (WIP)

BearishSun 10 years ago
parent
commit
1091551099

+ 28 - 5
BansheeEngine/Include/BsGUIElementBase.h

@@ -28,6 +28,17 @@ namespace BansheeEngine
 			Panel
 		};
 
+	protected:
+		/**
+		 * @brief	Flags that signal the state of the GUI element.
+		 */
+		enum GUIElementFlags
+		{
+			GUIElem_Dirty = 0x01,
+			GUIElem_Hidden = 0x02,
+			GUIElem_Disabled = 0x04
+		};
+
 	public:
 		GUIElementBase();
 		GUIElementBase(const GUIDimensions& dimensions);
@@ -77,6 +88,13 @@ namespace BansheeEngine
 		 */
 		void setVisible(bool visible);
 
+		/**
+		 * @brief	Enables or disables this element and recursively applies the same state to all the child elements.
+		 * 			This has the same effect as ::setVisible, but when disabled it will also remove the element from the 
+		 * 			layout, essentially having the same effect is if you destroyed the element.
+		 */
+		void setEnabled(bool enabled);
+
 		/**
 		 * @brief	Returns non-clipped bounds of the GUI element. Relative to a parent GUI panel.
 		 *
@@ -263,7 +281,14 @@ namespace BansheeEngine
 		 *
 		 * @note	Internal method.
 		 */
-		bool _isVisible() const { return mIsVisible; }
+		bool _isVisible() const { return (mFlags & GUIElem_Hidden) == 0; }
+
+		/**
+		 * @brief	Returns if element is enabled or disabled.
+		 *
+		 * @note	Internal method.
+		 */
+		bool _isEnabled() const { return (mFlags & GUIElem_Disabled) == 0; }
 
 		/**
 		 * @brief	Changes the active GUI element widget. This allows you to move an element
@@ -322,7 +347,7 @@ namespace BansheeEngine
 		/**
 		 * @brief	Returns true if elements contents have changed since last update.
 		 */
-		bool _isDirty() const { return mIsDirty; }
+		bool _isDirty() const { return (mFlags & GUIElem_Dirty) != 0; }
 
 		/**
 		 * @brief	Marks the element contents to be up to date. (i.e. processed by the GUI system)
@@ -330,7 +355,6 @@ namespace BansheeEngine
 		void _markAsClean();
 
 	protected:
-
 		/**
 		 * @brief	Finds anchor and update parents and recursively assigns them to all children.
 		 */
@@ -373,8 +397,7 @@ namespace BansheeEngine
 		GUIElementBase* mParentElement;
 
 		Vector<GUIElementBase*> mChildren;	
-		bool mIsVisible;
-		bool mIsDirty;
+		UINT8 mFlags;
 
 		GUIDimensions mDimensions;
 		GUILayoutData mLayoutData;

+ 46 - 13
BansheeEngine/Source/BsGUIElementBase.cpp

@@ -13,16 +13,15 @@
 namespace BansheeEngine
 {
 	GUIElementBase::GUIElementBase()
-		:mIsDirty(true), mParentElement(nullptr), mIsVisible(true), 
-		mParentWidget(nullptr), mAnchorParent(nullptr), mUpdateParent(nullptr)
+		:mParentElement(nullptr), mParentWidget(nullptr), mAnchorParent(nullptr), mUpdateParent(nullptr), 
+		mFlags(GUIElem_Dirty)
 	{
 
 	}
 
 	GUIElementBase::GUIElementBase(const GUIDimensions& dimensions)
-		:mIsDirty(true), mParentElement(nullptr), mIsVisible(true),
-		mParentWidget(nullptr), mDimensions(dimensions), 
-		mAnchorParent(nullptr), mUpdateParent(nullptr)
+		:mParentElement(nullptr), mParentWidget(nullptr), mDimensions(dimensions), mAnchorParent(nullptr), 
+		mUpdateParent(nullptr), mFlags(GUIElem_Dirty)
 	{
 
 	}
@@ -188,7 +187,7 @@ namespace BansheeEngine
 	
 	void GUIElementBase::_markAsClean()
 	{
-		mIsDirty = false;
+		mFlags &= ~GUIElem_Dirty;
 	}
 
 	void GUIElementBase::_markLayoutAsDirty() 
@@ -197,9 +196,9 @@ namespace BansheeEngine
 			return;
 
 		if (mUpdateParent != nullptr)
-			mUpdateParent->mIsDirty = true;
+			mUpdateParent->mFlags |= GUIElem_Dirty;
 		else
-			mIsDirty = true;
+			mFlags |= GUIElem_Dirty;
 	}
 
 	void GUIElementBase::_markContentAsDirty()
@@ -222,24 +221,56 @@ namespace BansheeEngine
 
 	void GUIElementBase::setVisible(bool visible)
 	{
-		if (visible && mParentElement != nullptr && !mParentElement->mIsVisible)
+		if (visible && mParentElement != nullptr && !mParentElement->_isVisible())
 			return; // Cannot make visible if parent is not visible
 
-		if (mIsVisible != visible)
+		if (_isVisible() != visible)
 		{
 			// If making an element visible make sure to mark layout as dirty, as we didn't track any dirty flags while the element was disabled
 			if (!visible)
+			{
 				_markMeshAsDirty();
+				mFlags |= GUIElem_Hidden;
+				
+			}
 			else
+			{
 				_markLayoutAsDirty();
-
-			mIsVisible = visible;
+				mFlags &= ~GUIElem_Hidden;
+			}
 		}
 
 		for(auto& elem : mChildren)
 			elem->setVisible(visible);
 	}
 
+	void GUIElementBase::setEnabled(bool enabled)
+	{
+		if (enabled && mParentElement != nullptr && !mParentElement->_isEnabled())
+			return; // Cannot enable if parent is disabled
+
+		if (_isEnabled() != enabled)
+		{
+			_markLayoutAsDirty();
+
+			// If parent is not visible, just enable the element but don't make it visible
+			if (enabled && mParentElement != nullptr && !mParentElement->_isVisible())
+			{
+				mFlags &= ~GUIElem_Disabled;
+			}
+			else
+			{
+				if (!enabled)
+					mFlags |= GUIElem_Disabled | GUIElem_Hidden;
+				else
+					mFlags &= ~(GUIElem_Disabled | GUIElem_Hidden);
+			}
+		}
+
+		for (auto& elem : mChildren)
+			elem->setEnabled(enabled);
+	}
+
 	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
@@ -309,7 +340,9 @@ namespace BansheeEngine
 		element->_setParent(this);
 		mChildren.push_back(element);
 
-		if (!mIsVisible)
+		if (!_isEnabled())
+			element->setEnabled(false);
+		else if (!_isVisible())
 			element->setVisible(false);
 
 		_markLayoutAsDirty();

+ 3 - 1
BansheeEngine/Source/BsGUILayout.cpp

@@ -48,7 +48,9 @@ namespace BansheeEngine
 		element->_setParent(this);
 		mChildren.insert(mChildren.begin() + idx, element);
 		
-		if (!mIsVisible)
+		if (!_isEnabled())
+			element->setEnabled(false);
+		else if (!_isVisible())
 			element->setVisible(false);
 
 		_markLayoutAsDirty();

+ 38 - 24
BansheeEngine/Source/BsGUILayoutX.cpp

@@ -17,6 +17,9 @@ namespace BansheeEngine
 		Vector2I minSize;
 		for (auto& child : mChildren)
 		{
+			if (!child->_isEnabled())
+				continue;
+
 			LayoutSizeRange sizeRange = child->_calculateLayoutSizeRange();
 
 			if (child->_getType() == GUIElementBase::Type::FixedSpace)
@@ -55,21 +58,24 @@ namespace BansheeEngine
 		{
 			LayoutSizeRange& childSizeRange = mChildSizeRanges[childIdx];
 
-			childSizeRange = child->_getLayoutSizeRange();
-			if (child->_getType() == GUIElementBase::Type::FixedSpace)
+			if (child->_isEnabled())
 			{
-				childSizeRange.optimal.y = 0;
-				childSizeRange.min.y = 0;
-			}
+				childSizeRange = child->_getLayoutSizeRange();
+				if (child->_getType() == GUIElementBase::Type::FixedSpace)
+				{
+					childSizeRange.optimal.y = 0;
+					childSizeRange.min.y = 0;
+				}
 
-			UINT32 paddingX = child->_getPadding().left + child->_getPadding().right;
-			UINT32 paddingY = child->_getPadding().top + child->_getPadding().bottom;
+				UINT32 paddingX = child->_getPadding().left + child->_getPadding().right;
+				UINT32 paddingY = child->_getPadding().top + child->_getPadding().bottom;
 
-			optimalSize.x += childSizeRange.optimal.x + paddingX;
-			optimalSize.y = std::max((UINT32)optimalSize.y, childSizeRange.optimal.y + paddingY);
+				optimalSize.x += childSizeRange.optimal.x + paddingX;
+				optimalSize.y = std::max((UINT32)optimalSize.y, childSizeRange.optimal.y + paddingY);
 
-			minSize.x += childSizeRange.min.x + paddingX;
-			minSize.y = std::max((UINT32)minSize.y, childSizeRange.min.y + paddingY);
+				minSize.x += childSizeRange.min.x + paddingX;
+				minSize.y = std::max((UINT32)minSize.y, childSizeRange.min.y + paddingY);
+			}
 
 			childIdx++;
 		}
@@ -113,8 +119,13 @@ namespace BansheeEngine
 			}
 			else if (child->_getType() == GUIElementBase::Type::FlexibleSpace)
 			{
-				numFlexibleSpaces++;
-				numNonClampedElements++;
+				if (child->_isEnabled())
+				{
+					numFlexibleSpaces++;
+					numNonClampedElements++;
+				}
+				else
+					processedElements[childIdx] = true;
 			}
 			else
 			{
@@ -329,18 +340,18 @@ namespace BansheeEngine
 			UINT32 elemWidth = elementAreas[childIdx].width;
 			xOffset += child->_getPadding().left;
 
-			UINT32 elemHeight = (UINT32)sizeRanges[childIdx].optimal.y;
+			const LayoutSizeRange& sizeRange = sizeRanges[childIdx];
+			UINT32 elemHeight = (UINT32)sizeRange.optimal.y;
 			const GUIDimensions& dimensions = child->_getDimensions();
 			if (!dimensions.fixedHeight())
 			{
 				elemHeight = layoutArea.height;
-				if (dimensions.minHeight > 0 && elemHeight < dimensions.minHeight)
-					elemHeight = dimensions.minHeight;
+				if (sizeRange.min.y > 0 && elemHeight < (UINT32)sizeRange.min.y)
+					elemHeight = (UINT32)sizeRange.min.y;
 
-				if (dimensions.maxHeight > 0 && elemHeight > dimensions.maxHeight)
-					elemHeight = dimensions.maxHeight;
+				if (sizeRange.max.y > 0 && elemHeight > (UINT32)sizeRange.max.y)
+					elemHeight = (UINT32)sizeRange.max.y;
 			}
-
 			elementAreas[childIdx].height = elemHeight;
 
 			if (child->_getType() == GUIElementBase::Type::Element)
@@ -389,12 +400,15 @@ namespace BansheeEngine
 		GUILayoutData childData = data;
 		for(auto& child : mChildren)
 		{
-			childData.area = elementAreas[childIdx];
-			childData.clipRect = childData.area;
-			childData.clipRect.clip(data.clipRect);
+			if (child->_isEnabled())
+			{
+				childData.area = elementAreas[childIdx];
+				childData.clipRect = childData.area;
+				childData.clipRect.clip(data.clipRect);
 
-			child->_setLayoutData(childData);
-			child->_updateLayoutInternal(childData);
+				child->_setLayoutData(childData);
+				child->_updateLayoutInternal(childData);
+			}
 
 			childIdx++;
 		}

+ 37 - 22
BansheeEngine/Source/BsGUILayoutY.cpp

@@ -17,6 +17,9 @@ namespace BansheeEngine
 
 		for (auto& child : mChildren)
 		{
+			if (!child->_isEnabled())
+				continue;
+
 			LayoutSizeRange sizeRange = child->_calculateLayoutSizeRange();
 			
 			if (child->_getType() == GUIElementBase::Type::FixedSpace)
@@ -55,21 +58,24 @@ namespace BansheeEngine
 		{
 			LayoutSizeRange& childSizeRange = mChildSizeRanges[childIdx];
 
-			childSizeRange = child->_getLayoutSizeRange();
-			if(child->_getType() == GUIElementBase::Type::FixedSpace)
+			if (child->_isEnabled())
 			{
-				childSizeRange.optimal.x = 0;
-				childSizeRange.min.x = 0;
-			}
+				childSizeRange = child->_getLayoutSizeRange();
+				if (child->_getType() == GUIElementBase::Type::FixedSpace)
+				{
+					childSizeRange.optimal.x = 0;
+					childSizeRange.min.x = 0;
+				}
 
-			UINT32 paddingX = child->_getPadding().left + child->_getPadding().right;
-			UINT32 paddingY = child->_getPadding().top + child->_getPadding().bottom;
+				UINT32 paddingX = child->_getPadding().left + child->_getPadding().right;
+				UINT32 paddingY = child->_getPadding().top + child->_getPadding().bottom;
 
-			optimalSize.y += childSizeRange.optimal.y + paddingY;
-			optimalSize.x = std::max((UINT32)optimalSize.x, childSizeRange.optimal.x + paddingX);
+				optimalSize.y += childSizeRange.optimal.y + paddingY;
+				optimalSize.x = std::max((UINT32)optimalSize.x, childSizeRange.optimal.x + paddingX);
 
-			minSize.y += childSizeRange.min.y + paddingY;
-			minSize.x = std::max((UINT32)minSize.x, childSizeRange.min.x + paddingX);
+				minSize.y += childSizeRange.min.y + paddingY;
+				minSize.x = std::max((UINT32)minSize.x, childSizeRange.min.x + paddingX);
+			}
 
 			childIdx++;
 		}
@@ -113,8 +119,13 @@ namespace BansheeEngine
 			}
 			else if (child->_getType() == GUIElementBase::Type::FlexibleSpace)
 			{
-				numFlexibleSpaces++;
-				numNonClampedElements++;
+				if (child->_isEnabled())
+				{
+					numFlexibleSpaces++;
+					numNonClampedElements++;
+				}
+				else
+					processedElements[childIdx] = true;
 			}
 			else
 			{
@@ -335,16 +346,17 @@ namespace BansheeEngine
 			UINT32 elemHeight = elementAreas[childIdx].height;
 			yOffset += child->_getPadding().top;
 
+			const LayoutSizeRange& sizeRange = sizeRanges[childIdx];
 			UINT32 elemWidth = (UINT32)sizeRanges[childIdx].optimal.x;
 			const GUIDimensions& dimensions = child->_getDimensions();
 			if (!dimensions.fixedWidth())
 			{
 				elemWidth = layoutArea.width;
-				if (dimensions.minWidth > 0 && elemWidth < dimensions.minWidth)
-					elemWidth = dimensions.minWidth;
+				if (sizeRange.min.x > 0 && elemWidth < (UINT32)sizeRange.min.x)
+					elemWidth = (UINT32)sizeRange.min.x;
 
-				if (dimensions.maxWidth > 0 && elemWidth > dimensions.maxWidth)
-					elemWidth = dimensions.maxWidth;
+				if (sizeRange.max.x > 0 && elemWidth > (UINT32)sizeRange.max.x)
+					elemWidth = (UINT32)sizeRange.max.x;
 			}
 
 			elementAreas[childIdx].width = elemWidth;
@@ -387,12 +399,15 @@ namespace BansheeEngine
 		GUILayoutData childData = data;
 		for(auto& child : mChildren)
 		{
-			childData.area = elementAreas[childIdx];
-			childData.clipRect = childData.area;
-			childData.clipRect.clip(data.clipRect);
+			if (child->_isEnabled())
+			{
+				childData.area = elementAreas[childIdx];
+				childData.clipRect = childData.area;
+				childData.clipRect.clip(data.clipRect);
 
-			child->_setLayoutData(childData);
-			child->_updateLayoutInternal(childData);
+				child->_setLayoutData(childData);
+				child->_updateLayoutInternal(childData);
+			}
 
 			childIdx++;
 		}

+ 32 - 22
BansheeEngine/Source/BsGUIPanel.cpp

@@ -27,6 +27,9 @@ namespace BansheeEngine
 
 		for (auto& child : mChildren)
 		{
+			if (!child->_isEnabled())
+				continue;
+
 			LayoutSizeRange sizeRange = child->_calculateLayoutSizeRange();
 
 			if (child->_getType() == GUIElementBase::Type::FixedSpace || child->_getType() == GUIElementBase::Type::FlexibleSpace)
@@ -90,23 +93,27 @@ namespace BansheeEngine
 		for (auto& child : mChildren)
 		{
 			LayoutSizeRange& childSizeRange = mChildSizeRanges[childIdx];
-			childSizeRange = _getElementSizeRange(child);
 
-			UINT32 paddingX = child->_getPadding().left + child->_getPadding().right;
-			UINT32 paddingY = child->_getPadding().top + child->_getPadding().bottom;
+			if (child->_isEnabled())
+			{
+				childSizeRange = _getElementSizeRange(child);
 
-			Vector2I childMax;
-			childMax.x = child->_getDimensions().x + childSizeRange.optimal.x + paddingX;
-			childMax.y = child->_getDimensions().y + childSizeRange.optimal.y + paddingY;
+				UINT32 paddingX = child->_getPadding().left + child->_getPadding().right;
+				UINT32 paddingY = child->_getPadding().top + child->_getPadding().bottom;
 
-			optimalSize.x = std::max(optimalSize.x, childMax.x);
-			optimalSize.y = std::max(optimalSize.y, childMax.y);
+				Vector2I childMax;
+				childMax.x = child->_getDimensions().x + childSizeRange.optimal.x + paddingX;
+				childMax.y = child->_getDimensions().y + childSizeRange.optimal.y + paddingY;
 
-			childMax.x = child->_getDimensions().x + childSizeRange.min.x + paddingX;
-			childMax.y = child->_getDimensions().y + childSizeRange.min.y + paddingY;
+				optimalSize.x = std::max(optimalSize.x, childMax.x);
+				optimalSize.y = std::max(optimalSize.y, childMax.y);
 
-			minSize.x = std::max(minSize.x, childMax.x);
-			minSize.y = std::max(minSize.y, childMax.y);
+				childMax.x = child->_getDimensions().x + childSizeRange.min.x + paddingX;
+				childMax.y = child->_getDimensions().y + childSizeRange.min.y + paddingY;
+
+				minSize.x = std::max(minSize.x, childMax.x);
+				minSize.y = std::max(minSize.y, childMax.y);
+			}
 
 			childIdx++;
 		}
@@ -148,13 +155,13 @@ namespace BansheeEngine
 
 			if (modifiedWidth > (UINT32)sizeRange.optimal.x)
 			{
-				if (dimensions.maxWidth > 0)
-					modifiedWidth = std::min(modifiedWidth, dimensions.maxWidth);
+				if (sizeRange.max.x > 0)
+					modifiedWidth = std::min(modifiedWidth, (UINT32)sizeRange.max.x);
 			}
 			else if (modifiedWidth < (UINT32)sizeRange.optimal.x)
 			{
-				if (dimensions.minWidth > 0)
-					modifiedWidth = std::max(modifiedWidth, dimensions.minWidth);
+				if (sizeRange.min.x > 0)
+					modifiedWidth = std::max(modifiedWidth, (UINT32)sizeRange.min.x);
 			}
 
 			area.width = modifiedWidth;
@@ -168,13 +175,13 @@ namespace BansheeEngine
 
 			if (modifiedHeight > (UINT32)sizeRange.optimal.y)
 			{
-				if (dimensions.maxHeight > 0)
-					modifiedHeight = std::min(modifiedHeight, dimensions.maxHeight);
+				if (sizeRange.max.y > 0)
+					modifiedHeight = std::min(modifiedHeight, (UINT32)sizeRange.max.y);
 			}
 			else if (modifiedHeight < (UINT32)sizeRange.optimal.y)
 			{
-				if (dimensions.minHeight > 0)
-					modifiedHeight = std::max(modifiedHeight, dimensions.minHeight);
+				if (sizeRange.min.y > 0)
+					modifiedHeight = std::max(modifiedHeight, (UINT32)sizeRange.min.y);
 			}
 
 			area.height = modifiedHeight;
@@ -226,9 +233,12 @@ namespace BansheeEngine
 
 		for (auto& child : mChildren)
 		{
-			childData.area = elementAreas[childIdx];
+			if (child->_isEnabled())
+			{
+				childData.area = elementAreas[childIdx];
 
-			_updateChildLayout(child, childData);
+				_updateChildLayout(child, childData);
+			}
 
 			childIdx++;
 		}

+ 18 - 9
BansheeEngine/Source/BsGUIScrollArea.cpp

@@ -68,7 +68,10 @@ namespace BansheeEngine
 		// then they're not needed and the range is valid. And if it doesn't
 		// fit the area will get clipped anyway and including the scroll bars
 		// won't change the size much, but it would complicate this method significantly.
-		return mDimensions.calculateSizeRange(_getOptimalSize());
+		if (mContentLayout->_isEnabled())
+			return mDimensions.calculateSizeRange(_getOptimalSize());
+
+		return mDimensions.calculateSizeRange(Vector2I());
 	}
 
 	LayoutSizeRange GUIScrollArea::_getLayoutSizeRange() const
@@ -87,6 +90,9 @@ namespace BansheeEngine
 		UINT32 childIdx = 0;
 		for (auto& child : mChildren)
 		{
+			if (!child->_isEnabled())
+				continue;
+
 			mChildSizeRanges[childIdx] = child->_getLayoutSizeRange();
 			childIdx++;
 		}
@@ -265,16 +271,19 @@ namespace BansheeEngine
 		Rect2I& vertScrollBounds = elementAreas[vertScrollIdx];
 
 		// Layout
-		Rect2I layoutClipRect = data.clipRect;
-		layoutClipRect.width = (UINT32)mVisibleSize.x;
-		layoutClipRect.height = (UINT32)mVisibleSize.y;
+		if (mContentLayout->_isEnabled())
+		{
+			Rect2I layoutClipRect = data.clipRect;
+			layoutClipRect.width = (UINT32)mVisibleSize.x;
+			layoutClipRect.height = (UINT32)mVisibleSize.y;
 
-		GUILayoutData layoutData = data;
-		layoutData.area = layoutBounds;
-		layoutData.clipRect = layoutClipRect;
+			GUILayoutData layoutData = data;
+			layoutData.area = layoutBounds;
+			layoutData.clipRect = layoutClipRect;
 
-		mContentLayout->_setLayoutData(layoutData);
-		mContentLayout->_updateLayoutInternal(layoutData);
+			mContentLayout->_setLayoutData(layoutData);
+			mContentLayout->_updateLayoutInternal(layoutData);
+		}
 
 		// Vertical scrollbar
 		{

+ 2 - 2
MBansheeEditor/GUI/GUIArray.cs

@@ -85,7 +85,7 @@ namespace BansheeEditor
                 {
                     guiChildLayout = layout.AddLayoutX();
                     guiChildLayout.AddSpace(IndentAmount);
-                    guiChildLayout.Visible = isExpanded;
+                    guiChildLayout.Enabled = isExpanded;
 
                     GUIPanel guiContentPanel = guiChildLayout.AddPanel();
                     GUILayoutX guiIndentLayoutX = guiContentPanel.AddLayoutX();
@@ -135,7 +135,7 @@ namespace BansheeEditor
             isExpanded = expanded;
 
             if (guiChildLayout != null)
-                guiChildLayout.Visible = isExpanded;
+                guiChildLayout.Enabled = isExpanded;
         }
 
         /// <summary>

+ 1 - 1
MBansheeEditor/Inspector/GenericInspector.cs

@@ -59,7 +59,7 @@ namespace BansheeEditor
         /// <inheritdoc/>
         internal override void SetVisible(bool visible)
         {
-            RootGUI.Visible = !isEmpty && visible;
+            RootGUI.Enabled = !isEmpty && visible;
         }
     }
 }

+ 1 - 1
MBansheeEditor/Inspector/Inspector.cs

@@ -54,7 +54,7 @@ namespace BansheeEditor
         /// <param name="visible">True to make the GUI elements visible.</param>
         internal virtual void SetVisible(bool visible)
         {
-            RootGUI.Visible = visible;
+            RootGUI.Enabled = visible;
         }
 
         /// <summary>

+ 2 - 2
MBansheeEditor/Inspector/InspectorWindow.cs

@@ -161,7 +161,7 @@ namespace BansheeEditor
             inspectorScrollArea = new GUIScrollArea();
             scrollAreaHighlight = new GUITexture(Builtin.WhiteTexture);
             scrollAreaHighlight.SetTint(HIGHLIGHT_COLOR);
-            scrollAreaHighlight.Visible = false;
+            scrollAreaHighlight.Enabled = false;
 
             GUI.AddElement(inspectorScrollArea);
             GUIPanel inspectorPanel = inspectorScrollArea.Layout.AddPanel();
@@ -504,7 +504,7 @@ namespace BansheeEditor
             }
 
             if (scrollAreaHighlight != null)
-                scrollAreaHighlight.Visible = isValidDrag;
+                scrollAreaHighlight.Enabled = isValidDrag;
         }
 
         /// <summary>

+ 4 - 4
MBansheeEditor/Inspectors/CameraInspector.cs

@@ -112,13 +112,13 @@ namespace BansheeEditor
         {
             if (type == ProjectionType.Orthographic)
             {
-                fieldOfView.Visible = false;
-                orthoHeight.Visible = true;
+                fieldOfView.Enabled = false;
+                orthoHeight.Enabled = true;
             }
             else
             {
-                fieldOfView.Visible = true;
-                orthoHeight.Visible = false;
+                fieldOfView.Enabled = true;
+                orthoHeight.Enabled = false;
             }
         }
 

+ 9 - 9
MBansheeEditor/Inspectors/LightInspector.cs

@@ -63,21 +63,21 @@ namespace BansheeEditor
         {
             if (type == LightType.Directional)
             {
-                rangeField.Visible = false;
-                spotAngleField.Visible = false;
-                spotFalloffAngleField.Visible = false;
+                rangeField.Enabled = false;
+                spotAngleField.Enabled = false;
+                spotFalloffAngleField.Enabled = false;
             }
             else if (type == LightType.Point)
             {
-                rangeField.Visible = true;
-                spotAngleField.Visible = false;
-                spotFalloffAngleField.Visible = false;
+                rangeField.Enabled = true;
+                spotAngleField.Enabled = false;
+                spotFalloffAngleField.Enabled = false;
             }
             else
             {
-                rangeField.Visible = true;
-                spotAngleField.Visible = true;
-                spotFalloffAngleField.Visible = true;
+                rangeField.Enabled = true;
+                spotAngleField.Enabled = true;
+                spotFalloffAngleField.Enabled = true;
             }
         }
 

+ 2 - 2
MBansheeEditor/Library/LibraryGUIEntry.cs

@@ -207,7 +207,7 @@ namespace BansheeEditor
             renameTextBox.Text = name;
             renameTextBox.Focus = true;
 
-            label.Visible = false;
+            label.Enabled = false;
         }
 
         /// <summary>
@@ -221,7 +221,7 @@ namespace BansheeEditor
                 renameTextBox = null;
             }
 
-            label.Visible = true;
+            label.Enabled = true;
         }
 
         /// <summary>

+ 14 - 1
MBansheeEngine/GUI/GUIElement.cs

@@ -33,13 +33,23 @@ namespace BansheeEngine
         }
 
         /// <summary>
-        /// Makes the element hidden or visible.
+        /// Makes the element hidden or visible. This will not affect the layout as the room for the element will still
+        /// be reserved in the parent layout, use <see cref="Enabled"/> if you need to affect the layout as well.
         /// </summary>
         public bool Visible
         {
             set { Internal_SetVisible(mCachedPtr, value); }
         }
 
+        /// <summary>
+        /// Disables or enables an element, making it hidden or visible. When disabled it is essentially removed from the 
+        /// parent achieving the similar effect as if the element was destroyed.
+        /// </summary>
+        public bool Enabled
+        {
+            set { Internal_SetEnabled(mCachedPtr, value); }
+        }
+
         /// <summary>
         /// Assigns or removes keyboard focus on this element.
         /// </summary>
@@ -149,6 +159,9 @@ namespace BansheeEngine
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetVisible(IntPtr nativeInstance, bool visible);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetEnabled(IntPtr nativeInstance, bool enabled);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetFocus(IntPtr nativeInstance, bool focus);
 

+ 1 - 0
SBansheeEngine/Include/BsScriptGUIElement.h

@@ -138,6 +138,7 @@ namespace BansheeEngine
 		/************************************************************************/
 		static void internal_destroy(ScriptGUIElementBaseTBase* nativeInstance);
 		static void internal_setVisible(ScriptGUIElementBaseTBase* nativeInstance, bool visible);
+		static void internal_setEnabled(ScriptGUIElementBaseTBase* nativeInstance, bool enabled);
 		static void internal_setFocus(ScriptGUIElementBaseTBase* nativeInstance, bool focus);
 		static Rect2I internal_getBounds(ScriptGUIElementBaseTBase* nativeInstance);
 		static void internal_setBounds(ScriptGUIElementBaseTBase* nativeInstance, Rect2I bounds);

+ 9 - 0
SBansheeEngine/Source/BsScriptGUIElement.cpp

@@ -76,6 +76,7 @@ namespace BansheeEngine
 	{
 		metaData.scriptClass->addInternalCall("Internal_Destroy", &ScriptGUIElement::internal_destroy);
 		metaData.scriptClass->addInternalCall("Internal_SetVisible", &ScriptGUIElement::internal_setVisible);
+		metaData.scriptClass->addInternalCall("Internal_SetEnabled", &ScriptGUIElement::internal_setEnabled);
 		metaData.scriptClass->addInternalCall("Internal_SetFocus", &ScriptGUIElement::internal_setFocus);
 		metaData.scriptClass->addInternalCall("Internal_GetBounds", &ScriptGUIElement::internal_getBounds);
 		metaData.scriptClass->addInternalCall("Internal_SetBounds", &ScriptGUIElement::internal_setBounds);
@@ -104,6 +105,14 @@ namespace BansheeEngine
 		nativeInstance->getGUIElement()->setVisible(visible);
 	}
 
+	void ScriptGUIElement::internal_setEnabled(ScriptGUIElementBaseTBase* nativeInstance, bool enabled)
+	{
+		if (nativeInstance->isDestroyed())
+			return;
+
+		nativeInstance->getGUIElement()->setEnabled(enabled);
+	}
+
 	void ScriptGUIElement::internal_setFocus(ScriptGUIElementBaseTBase* nativeInstance, bool focus)
 	{
 		if (nativeInstance->isDestroyed())