Explorar el Código

Updating GUI elements in common ways (hovering, changing content, inputting text) no longer triggers a layout update

Marko Pintera hace 10 años
padre
commit
bc542214fd

+ 2 - 2
BansheeEditor/Source/BsGUIColor.cpp

@@ -49,14 +49,14 @@ namespace BansheeEngine
 	{
 	{
 		mColor = color;
 		mColor = color;
 
 
-		_markLayoutAsDirty();
+		_markContentAsDirty();
 	}
 	}
 
 
 	void GUIColor::setTint(const Color& color)
 	void GUIColor::setTint(const Color& color)
 	{
 	{
 		mTint = color;
 		mTint = color;
 
 
-		_markLayoutAsDirty();
+		_markContentAsDirty();
 	}
 	}
 
 
 	UINT32 GUIColor::_getNumRenderElements() const
 	UINT32 GUIColor::_getNumRenderElements() const

+ 0 - 4
BansheeEditor/Source/BsGUIComponentFoldout.cpp

@@ -57,8 +57,6 @@ namespace BansheeEngine
 			else
 			else
 				mToggle->toggleOff();
 				mToggle->toggleOff();
 
 
-			_markLayoutAsDirty();
-
 			if(!onStateChanged.empty())
 			if(!onStateChanged.empty())
 				onStateChanged(mIsExpanded);
 				onStateChanged(mIsExpanded);
 		}
 		}
@@ -78,8 +76,6 @@ namespace BansheeEngine
 	{
 	{
 		mIsExpanded = value;
 		mIsExpanded = value;
 
 
-		_markLayoutAsDirty();
-
 		onStateChanged(value);
 		onStateChanged(value);
 	}
 	}
 
 

+ 0 - 4
BansheeEditor/Source/BsGUIFoldout.cpp

@@ -59,8 +59,6 @@ namespace BansheeEngine
 			else
 			else
 				mToggle->toggleOff();
 				mToggle->toggleOff();
 
 
-			_markLayoutAsDirty();
-
 			if (!onStateChanged.empty())
 			if (!onStateChanged.empty())
 				onStateChanged(mIsExpanded);
 				onStateChanged(mIsExpanded);
 		}
 		}
@@ -81,8 +79,6 @@ namespace BansheeEngine
 	{
 	{
 		mIsExpanded = value;
 		mIsExpanded = value;
 
 
-		_markLayoutAsDirty();
-
 		onStateChanged(value);
 		onStateChanged(value);
 	}
 	}
 
 

+ 8 - 1
BansheeEditor/Source/BsGUIWindowFrame.cpp

@@ -39,11 +39,18 @@ namespace BansheeEngine
 
 
 	void GUIWindowFrame::setFocused(bool focused)
 	void GUIWindowFrame::setFocused(bool focused)
 	{
 	{
+		Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+
 		if(focused)
 		if(focused)
 			mActiveTexture = _getStyle()->focused.texture;
 			mActiveTexture = _getStyle()->focused.texture;
 		else
 		else
 			mActiveTexture = _getStyle()->normal.texture;
 			mActiveTexture = _getStyle()->normal.texture;
 
 
-		_markLayoutAsDirty();
+		Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+
+		if (origSize != newSize)
+			_markLayoutAsDirty();
+		else
+			_markContentAsDirty();
 	}
 	}
 }
 }

+ 1 - 1
BansheeEngine/Include/BsGUIButtonBase.h

@@ -38,7 +38,7 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @copydoc	GUIElement::setTint
 		 * @copydoc	GUIElement::setTint
 		 */
 		 */
-		virtual void setTint(const Color& color);
+		virtual void setTint(const Color& color) override;
 
 
 		/**
 		/**
 		 * @brief	Change the button "on" state. This state determines
 		 * @brief	Change the button "on" state. This state determines

+ 10 - 2
BansheeEngine/Include/BsGUIElementBase.h

@@ -294,15 +294,23 @@ namespace BansheeEngine
 		virtual bool _isDestroyed() const { return false; }
 		virtual bool _isDestroyed() const { return false; }
 
 
 		/**
 		/**
-		 * @brief	Marks the elements contents as dirty, which causes the sprite meshes to be recreated from scratch.
+		 * @brief	Marks the element's dimensions as dirty, triggering a layout rebuild.
 		 *
 		 *
 		 * @note	Internal method.
 		 * @note	Internal method.
 		 */
 		 */
 		void _markLayoutAsDirty();
 		void _markLayoutAsDirty();
 
 
+		/**
+		 * @brief	Marks the element's contents as dirty, which causes the sprite meshes to be recreated from scratch.
+		 *
+		 * @note	Internal method.
+		 */
+		void _markContentAsDirty();
+
 		/**
 		/**
 		 * @brief	Mark only the elements that operate directly on the sprite mesh without requiring the mesh
 		 * @brief	Mark only the elements that operate directly on the sprite mesh without requiring the mesh
-		 * 			to be recreated as dirty. This includes position, depth and clip rectangle.
+		 * 			to be recreated as dirty. This includes position, depth and clip rectangle. This will cause
+		 *			the parent widget mesh to be rebuilt from its child element's meshes.
 		 *
 		 *
 		 * @note	Internal method.
 		 * @note	Internal method.
 		 */
 		 */

+ 14 - 3
BansheeEngine/Source/BsGUIButtonBase.cpp

@@ -40,6 +40,7 @@ namespace BansheeEngine
 		mLocStringUpdatedConn.disconnect();
 		mLocStringUpdatedConn.disconnect();
 		mLocStringUpdatedConn = content.getText().addOnStringModifiedCallback(std::bind(&GUIButtonBase::_markLayoutAsDirty, this));
 		mLocStringUpdatedConn = content.getText().addOnStringModifiedCallback(std::bind(&GUIButtonBase::_markLayoutAsDirty, this));
 
 
+		Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 		mContent = content;
 		mContent = content;
 
 
 		HSpriteTexture contentTex = content.getImage();
 		HSpriteTexture contentTex = content.getImage();
@@ -57,14 +58,19 @@ namespace BansheeEngine
 			}
 			}
 		}
 		}
 
 
-		_markLayoutAsDirty();
+		Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+
+		if (origSize != newSize)
+			_markLayoutAsDirty();
+		else
+			_markContentAsDirty();
 	}
 	}
 
 
 	void GUIButtonBase::setTint(const Color& color)
 	void GUIButtonBase::setTint(const Color& color)
 	{
 	{
 		mColor = color;
 		mColor = color;
 
 
-		_markLayoutAsDirty();
+		_markContentAsDirty();
 	}
 	}
 
 
 	void GUIButtonBase::_setOn(bool on) 
 	void GUIButtonBase::_setOn(bool on) 
@@ -368,9 +374,14 @@ namespace BansheeEngine
 
 
 	void GUIButtonBase::setState(GUIButtonState state)
 	void GUIButtonBase::setState(GUIButtonState state)
 	{
 	{
+		Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 		mActiveState = state;
 		mActiveState = state;
+		Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 
 
-		_markLayoutAsDirty();
+		if (origSize != newSize)
+			_markLayoutAsDirty();
+		else
+			_markContentAsDirty();
 	}
 	}
 
 
 	const HSpriteTexture& GUIButtonBase::getActiveTexture() const
 	const HSpriteTexture& GUIButtonBase::getActiveTexture() const

+ 9 - 0
BansheeEngine/Source/BsGUIElementBase.cpp

@@ -195,6 +195,15 @@ namespace BansheeEngine
 			mIsDirty = true;
 			mIsDirty = true;
 	}
 	}
 
 
+	void GUIElementBase::_markContentAsDirty()
+	{
+		if (_isDisabled())
+			return;
+
+		if (mParentWidget != nullptr)
+			mParentWidget->_markContentDirty(this);
+	}
+
 	void GUIElementBase::_markMeshAsDirty()
 	void GUIElementBase::_markMeshAsDirty()
 	{
 	{
 		if(_isDisabled())
 		if(_isDisabled())

+ 94 - 41
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -75,6 +75,8 @@ namespace BansheeEngine
 
 
 		if(filterOkay)
 		if(filterOkay)
 		{
 		{
+			Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+
 			WString oldText = mText;
 			WString oldText = mText;
 			mText = text;
 			mText = text;
 
 
@@ -91,7 +93,11 @@ namespace BansheeEngine
 
 
 			scrollTextToCaret();
 			scrollTextToCaret();
 
 
-			_markLayoutAsDirty();
+			Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+			if (origSize != newSize)
+				_markLayoutAsDirty();
+			else
+				_markContentAsDirty();
 		}
 		}
 	}
 	}
 
 
@@ -99,7 +105,7 @@ namespace BansheeEngine
 	{
 	{
 		mColor = color;
 		mColor = color;
 
 
-		_markLayoutAsDirty();
+		_markContentAsDirty();
 	}
 	}
 
 
 	UINT32 GUIInputBox::_getNumRenderElements() const
 	UINT32 GUIInputBox::_getNumRenderElements() const
@@ -401,8 +407,14 @@ namespace BansheeEngine
 		{
 		{
 			if(!mHasFocus)
 			if(!mHasFocus)
 			{
 			{
+				Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 				mState = State::Hover;
 				mState = State::Hover;
-				_markLayoutAsDirty();
+				Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+
+				if (origSize != newSize)
+					_markLayoutAsDirty();
+				else
+					_markContentAsDirty();
 			}
 			}
 
 
 			mIsMouseOver = true;
 			mIsMouseOver = true;
@@ -413,8 +425,14 @@ namespace BansheeEngine
 		{
 		{
 			if(!mHasFocus)
 			if(!mHasFocus)
 			{
 			{
+				Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 				mState = State::Normal;
 				mState = State::Normal;
-				_markLayoutAsDirty();
+				Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+
+				if (origSize != newSize)
+					_markLayoutAsDirty();
+				else
+					_markContentAsDirty();
 			}
 			}
 
 
 			mIsMouseOver = false;
 			mIsMouseOver = false;
@@ -426,7 +444,7 @@ namespace BansheeEngine
 			showSelection(0);
 			showSelection(0);
 			gGUIManager().getInputSelectionTool()->selectAll();
 			gGUIManager().getInputSelectionTool()->selectAll();
 
 
-			_markLayoutAsDirty();
+			_markContentAsDirty();
 			return true;
 			return true;
 		}
 		}
 		else if(ev.getType() == GUIMouseEventType::MouseDown && ev.getButton() == GUIMouseButton::Left)
 		else if(ev.getType() == GUIMouseEventType::MouseDown && ev.getButton() == GUIMouseButton::Left)
@@ -453,10 +471,9 @@ namespace BansheeEngine
 					gGUIManager().getInputSelectionTool()->moveSelectionToCaret(gGUIManager().getInputCaretTool()->getCaretPos());
 					gGUIManager().getInputSelectionTool()->moveSelectionToCaret(gGUIManager().getInputCaretTool()->getCaretPos());
 
 
 				scrollTextToCaret();
 				scrollTextToCaret();
+				_markContentAsDirty();
 			}
 			}
 
 
-			_markLayoutAsDirty();
-
 			return true;
 			return true;
 		}
 		}
 		else if(ev.getType() == GUIMouseEventType::MouseDragStart)
 		else if(ev.getType() == GUIMouseEventType::MouseDragStart)
@@ -468,6 +485,7 @@ namespace BansheeEngine
 				UINT32 caretPos = gGUIManager().getInputCaretTool()->getCaretPos();
 				UINT32 caretPos = gGUIManager().getInputCaretTool()->getCaretPos();
 				showSelection(caretPos);
 				showSelection(caretPos);
 				gGUIManager().getInputSelectionTool()->selectionDragStart(caretPos);
 				gGUIManager().getInputSelectionTool()->selectionDragStart(caretPos);
+				_markContentAsDirty();
 
 
 				return true;
 				return true;
 			}
 			}
@@ -479,7 +497,7 @@ namespace BansheeEngine
 				mDragInProgress = false;
 				mDragInProgress = false;
 
 
 				gGUIManager().getInputSelectionTool()->selectionDragEnd();
 				gGUIManager().getInputSelectionTool()->selectionDragEnd();
-
+				_markContentAsDirty();
 				return true;
 				return true;
 			}
 			}
 		}
 		}
@@ -495,8 +513,7 @@ namespace BansheeEngine
 				gGUIManager().getInputSelectionTool()->selectionDragUpdate(gGUIManager().getInputCaretTool()->getCaretPos());
 				gGUIManager().getInputSelectionTool()->selectionDragUpdate(gGUIManager().getInputCaretTool()->getCaretPos());
 
 
 				scrollTextToCaret();
 				scrollTextToCaret();
-
-				_markLayoutAsDirty();
+				_markContentAsDirty();
 				return true;
 				return true;
 			}
 			}
 		}
 		}
@@ -506,6 +523,8 @@ namespace BansheeEngine
 
 
 	bool GUIInputBox::_textInputEvent(const GUITextInputEvent& ev)
 	bool GUIInputBox::_textInputEvent(const GUITextInputEvent& ev)
 	{
 	{
+		Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+
 		if(mSelectionShown)
 		if(mSelectionShown)
 			deleteSelectedText();
 			deleteSelectedText();
 
 
@@ -527,12 +546,16 @@ namespace BansheeEngine
 			gGUIManager().getInputCaretTool()->moveCaretToChar(charIdx, CARET_AFTER);
 			gGUIManager().getInputCaretTool()->moveCaretToChar(charIdx, CARET_AFTER);
 			scrollTextToCaret();
 			scrollTextToCaret();
 
 
-			_markLayoutAsDirty();
-
 			if(!onValueChanged.empty())
 			if(!onValueChanged.empty())
 				onValueChanged(mText);
 				onValueChanged(mText);
 		}
 		}
 
 
+		Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+		if (origSize != newSize)
+			_markLayoutAsDirty();
+		else
+			_markContentAsDirty();
+
 		return true;
 		return true;
 	}
 	}
 
 
@@ -542,20 +565,26 @@ namespace BansheeEngine
 
 
 		if(ev.getType() == GUICommandEventType::Redraw)
 		if(ev.getType() == GUICommandEventType::Redraw)
 		{
 		{
-			_markLayoutAsDirty();
+			_markContentAsDirty();
 			return true;
 			return true;
 		}
 		}
 
 
 		if(ev.getType() == GUICommandEventType::FocusGained)
 		if(ev.getType() == GUICommandEventType::FocusGained)
 		{
 		{
+			Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 			mState = State::Focused;
 			mState = State::Focused;
 
 
 			showSelection(0);
 			showSelection(0);
 			gGUIManager().getInputSelectionTool()->selectAll();
 			gGUIManager().getInputSelectionTool()->selectAll();
-			_markLayoutAsDirty();
 
 
 			mHasFocus = true;
 			mHasFocus = true;
 
 
+			Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+			if (origSize != newSize)
+				_markLayoutAsDirty();
+			else
+				_markContentAsDirty();
+
 			if(!onFocusGained.empty())
 			if(!onFocusGained.empty())
 				onFocusGained();
 				onFocusGained();
 
 
@@ -564,14 +593,20 @@ namespace BansheeEngine
 		
 		
 		if(ev.getType() == GUICommandEventType::FocusLost)
 		if(ev.getType() == GUICommandEventType::FocusLost)
 		{
 		{
+			Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 			mState = State::Normal;
 			mState = State::Normal;
 
 
 			hideCaret();
 			hideCaret();
 			clearSelection();
 			clearSelection();
-			_markLayoutAsDirty();
 
 
 			mHasFocus = false;
 			mHasFocus = false;
 
 
+			Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+			if (origSize != newSize)
+				_markLayoutAsDirty();
+			else
+				_markContentAsDirty();
+
 			if(!onFocusLost.empty())
 			if(!onFocusLost.empty())
 				onFocusLost();
 				onFocusLost();
 
 
@@ -582,6 +617,7 @@ namespace BansheeEngine
 		{
 		{
 			if(mText.size() > 0)
 			if(mText.size() > 0)
 			{
 			{
+				Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 				if(mSelectionShown)
 				if(mSelectionShown)
 				{
 				{
 					deleteSelectedText();
 					deleteSelectedText();
@@ -618,7 +654,11 @@ namespace BansheeEngine
 					}
 					}
 				}
 				}
 
 
-				_markLayoutAsDirty();
+				Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+				if (origSize != newSize)
+					_markLayoutAsDirty();
+				else
+					_markContentAsDirty();
 			}
 			}
 
 
 			return true;
 			return true;
@@ -628,6 +668,7 @@ namespace BansheeEngine
 		{
 		{
 			if(mText.size() > 0)
 			if(mText.size() > 0)
 			{
 			{
+				Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 				if(mSelectionShown)
 				if(mSelectionShown)
 				{
 				{
 					deleteSelectedText();
 					deleteSelectedText();
@@ -663,7 +704,11 @@ namespace BansheeEngine
 					}
 					}
 				}
 				}
 
 
-				_markLayoutAsDirty();
+				Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+				if (origSize != newSize)
+					_markLayoutAsDirty();
+				else
+					_markContentAsDirty();
 			}
 			}
 
 
 			return true;
 			return true;
@@ -688,7 +733,7 @@ namespace BansheeEngine
 				gGUIManager().getInputCaretTool()->moveCaretLeft();
 				gGUIManager().getInputCaretTool()->moveCaretLeft();
 
 
 			scrollTextToCaret();
 			scrollTextToCaret();
-			_markLayoutAsDirty();
+			_markContentAsDirty();
 			return true;
 			return true;
 		}
 		}
 
 
@@ -701,7 +746,7 @@ namespace BansheeEngine
 			gGUIManager().getInputSelectionTool()->moveSelectionToCaret(gGUIManager().getInputCaretTool()->getCaretPos());
 			gGUIManager().getInputSelectionTool()->moveSelectionToCaret(gGUIManager().getInputCaretTool()->getCaretPos());
 
 
 			scrollTextToCaret();
 			scrollTextToCaret();
-			_markLayoutAsDirty();
+			_markContentAsDirty();
 			return true;
 			return true;
 		}
 		}
 
 
@@ -724,7 +769,7 @@ namespace BansheeEngine
 				gGUIManager().getInputCaretTool()->moveCaretRight();
 				gGUIManager().getInputCaretTool()->moveCaretRight();
 
 
 			scrollTextToCaret();
 			scrollTextToCaret();
-			_markLayoutAsDirty();
+			_markContentAsDirty();
 			return true;
 			return true;
 		}
 		}
 
 
@@ -737,7 +782,7 @@ namespace BansheeEngine
 			gGUIManager().getInputSelectionTool()->moveSelectionToCaret(gGUIManager().getInputCaretTool()->getCaretPos());
 			gGUIManager().getInputSelectionTool()->moveSelectionToCaret(gGUIManager().getInputCaretTool()->getCaretPos());
 
 
 			scrollTextToCaret();
 			scrollTextToCaret();
-			_markLayoutAsDirty();
+			_markContentAsDirty();
 			return true;
 			return true;
 		}
 		}
 
 
@@ -752,7 +797,7 @@ namespace BansheeEngine
 			gGUIManager().getInputCaretTool()->moveCaretUp();
 			gGUIManager().getInputCaretTool()->moveCaretUp();
 
 
 			scrollTextToCaret();
 			scrollTextToCaret();
-			_markLayoutAsDirty();
+			_markContentAsDirty();
 			return true;
 			return true;
 		}
 		}
 
 
@@ -765,7 +810,7 @@ namespace BansheeEngine
 			gGUIManager().getInputSelectionTool()->moveSelectionToCaret(gGUIManager().getInputCaretTool()->getCaretPos());
 			gGUIManager().getInputSelectionTool()->moveSelectionToCaret(gGUIManager().getInputCaretTool()->getCaretPos());
 
 
 			scrollTextToCaret();
 			scrollTextToCaret();
-			_markLayoutAsDirty();
+			_markContentAsDirty();
 			return true;
 			return true;
 		}
 		}
 
 
@@ -780,7 +825,7 @@ namespace BansheeEngine
 			gGUIManager().getInputCaretTool()->moveCaretDown();
 			gGUIManager().getInputCaretTool()->moveCaretDown();
 
 
 			scrollTextToCaret();
 			scrollTextToCaret();
-			_markLayoutAsDirty();
+			_markContentAsDirty();
 			return true;
 			return true;
 		}
 		}
 
 
@@ -793,7 +838,7 @@ namespace BansheeEngine
 			gGUIManager().getInputSelectionTool()->moveSelectionToCaret(gGUIManager().getInputCaretTool()->getCaretPos());
 			gGUIManager().getInputSelectionTool()->moveSelectionToCaret(gGUIManager().getInputCaretTool()->getCaretPos());
 
 
 			scrollTextToCaret();
 			scrollTextToCaret();
-			_markLayoutAsDirty();
+			_markContentAsDirty();
 			return true;
 			return true;
 		}
 		}
 
 
@@ -801,6 +846,8 @@ namespace BansheeEngine
 		{
 		{
 			if(mIsMultiline)
 			if(mIsMultiline)
 			{
 			{
+				Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+
 				if(mSelectionShown)
 				if(mSelectionShown)
 					deleteSelectedText();
 					deleteSelectedText();
 
 
@@ -822,12 +869,16 @@ namespace BansheeEngine
 					gGUIManager().getInputCaretTool()->moveCaretRight();
 					gGUIManager().getInputCaretTool()->moveCaretRight();
 					scrollTextToCaret();
 					scrollTextToCaret();
 
 
-					_markLayoutAsDirty();
-
 					if(!onValueChanged.empty())
 					if(!onValueChanged.empty())
 						onValueChanged(mText);
 						onValueChanged(mText);
 				}
 				}
 
 
+				Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+				if (origSize != newSize)
+					_markLayoutAsDirty();
+				else
+					_markContentAsDirty();
+
 				return true;
 				return true;
 			}
 			}
 
 
@@ -842,7 +893,6 @@ namespace BansheeEngine
 		{
 		{
 			cutText();
 			cutText();
 
 
-			_markLayoutAsDirty();
 			return true;
 			return true;
 		}
 		}
 		else if(ev.getButton() == mCopyVB)
 		else if(ev.getButton() == mCopyVB)
@@ -854,16 +904,14 @@ namespace BansheeEngine
 		else if(ev.getButton() == mPasteVB)
 		else if(ev.getButton() == mPasteVB)
 		{
 		{
 			pasteText();
 			pasteText();
-
-			_markLayoutAsDirty();
 			return true;
 			return true;
 		}
 		}
 		else if(ev.getButton() == mSelectAllVB)
 		else if(ev.getButton() == mSelectAllVB)
 		{
 		{
 			showSelection(0);
 			showSelection(0);
 			gGUIManager().getInputSelectionTool()->selectAll();
 			gGUIManager().getInputSelectionTool()->selectAll();
+			_markContentAsDirty();
 
 
-			_markLayoutAsDirty();
 			return true;
 			return true;
 		}
 		}
 
 
@@ -877,14 +925,11 @@ namespace BansheeEngine
 		TEXT_SPRITE_DESC textDesc = getTextDesc();
 		TEXT_SPRITE_DESC textDesc = getTextDesc();
 		Vector2I offset = getTextOffset();
 		Vector2I offset = getTextOffset();
 		gGUIManager().getInputCaretTool()->updateText(this, textDesc);
 		gGUIManager().getInputCaretTool()->updateText(this, textDesc);
-		_markLayoutAsDirty();
 	}
 	}
 
 
-
 	void GUIInputBox::hideCaret()
 	void GUIInputBox::hideCaret()
 	{
 	{
 		mCaretShown = false;
 		mCaretShown = false;
-		_markLayoutAsDirty();
 	}
 	}
 
 
 	void GUIInputBox::showSelection(UINT32 anchorCaretPos)
 	void GUIInputBox::showSelection(UINT32 anchorCaretPos)
@@ -895,14 +940,12 @@ namespace BansheeEngine
 
 
 		gGUIManager().getInputSelectionTool()->showSelection(anchorCaretPos);
 		gGUIManager().getInputSelectionTool()->showSelection(anchorCaretPos);
 		mSelectionShown = true;
 		mSelectionShown = true;
-		_markLayoutAsDirty();
 	}
 	}
 
 
 	void GUIInputBox::clearSelection()
 	void GUIInputBox::clearSelection()
 	{
 	{
 		gGUIManager().getInputSelectionTool()->clearSelection();
 		gGUIManager().getInputSelectionTool()->clearSelection();
 		mSelectionShown = false;
 		mSelectionShown = false;
-		_markLayoutAsDirty();
 	}
 	}
 
 
 	void GUIInputBox::scrollTextToCaret()
 	void GUIInputBox::scrollTextToCaret()
@@ -946,12 +989,11 @@ namespace BansheeEngine
 
 
 		gGUIManager().getInputCaretTool()->updateText(this, textDesc);
 		gGUIManager().getInputCaretTool()->updateText(this, textDesc);
 		gGUIManager().getInputSelectionTool()->updateText(this, textDesc);
 		gGUIManager().getInputSelectionTool()->updateText(this, textDesc);
-
-		_markLayoutAsDirty();
 	}
 	}
 
 
 	void GUIInputBox::clampScrollToBounds(Rect2I unclippedTextBounds)
 	void GUIInputBox::clampScrollToBounds(Rect2I unclippedTextBounds)
 	{
 	{
+		Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 		TEXT_SPRITE_DESC textDesc = getTextDesc();
 		TEXT_SPRITE_DESC textDesc = getTextDesc();
 
 
 		Vector2I newTextOffset;
 		Vector2I newTextOffset;
@@ -966,8 +1008,6 @@ namespace BansheeEngine
 
 
 			gGUIManager().getInputCaretTool()->updateText(this, textDesc);
 			gGUIManager().getInputCaretTool()->updateText(this, textDesc);
 			gGUIManager().getInputSelectionTool()->updateText(this, textDesc);
 			gGUIManager().getInputSelectionTool()->updateText(this, textDesc);
-
-			_markLayoutAsDirty();
 		}
 		}
 	}
 	}
 
 
@@ -1141,8 +1181,16 @@ namespace BansheeEngine
 
 
 	void GUIInputBox::cutText()
 	void GUIInputBox::cutText()
 	{
 	{
+		Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+
 		copyText();
 		copyText();
 		deleteSelectedText();
 		deleteSelectedText();
+
+		Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+		if (origSize != newSize)
+			_markLayoutAsDirty();
+		else
+			_markContentAsDirty();
 	}
 	}
 
 
 	void GUIInputBox::copyText()
 	void GUIInputBox::copyText()
@@ -1167,6 +1215,7 @@ namespace BansheeEngine
 
 
 		if(filterOkay)
 		if(filterOkay)
 		{
 		{
+			Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 			insertString(charIdx, textInClipboard);
 			insertString(charIdx, textInClipboard);
 
 
 			if(textInClipboard.size() > 0)
 			if(textInClipboard.size() > 0)
@@ -1174,7 +1223,11 @@ namespace BansheeEngine
 
 
 			scrollTextToCaret();
 			scrollTextToCaret();
 
 
-			_markLayoutAsDirty();
+			Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+			if (origSize != newSize)
+				_markLayoutAsDirty();
+			else
+				_markContentAsDirty();
 
 
 			if(!onValueChanged.empty())
 			if(!onValueChanged.empty())
 				onValueChanged(mText);
 				onValueChanged(mText);

+ 8 - 3
BansheeEngine/Source/BsGUILabel.cpp

@@ -80,16 +80,21 @@ namespace BansheeEngine
 		mLocStringUpdatedConn.disconnect();
 		mLocStringUpdatedConn.disconnect();
 		mLocStringUpdatedConn = content.getText().addOnStringModifiedCallback(std::bind(&GUILabel::_markLayoutAsDirty, this));
 		mLocStringUpdatedConn = content.getText().addOnStringModifiedCallback(std::bind(&GUILabel::_markLayoutAsDirty, this));
 
 
+		Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 		mContent = content;
 		mContent = content;
-		
-		_markLayoutAsDirty();
+		Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+
+		if (origSize != newSize)
+			_markLayoutAsDirty();
+		else
+			_markContentAsDirty();
 	}
 	}
 
 
 	void GUILabel::setTint(const Color& color)
 	void GUILabel::setTint(const Color& color)
 	{
 	{
 		mColor = color;
 		mColor = color;
 
 
-		_markLayoutAsDirty();
+		_markContentAsDirty();
 	}
 	}
 
 
 	GUILabel* GUILabel::create(const HString& text, const String& styleName)
 	GUILabel* GUILabel::create(const HString& text, const String& styleName)

+ 8 - 2
BansheeEngine/Source/BsGUITexture.cpp

@@ -107,15 +107,21 @@ namespace BansheeEngine
 	{
 	{
 		mColor = color;
 		mColor = color;
 
 
-		_markLayoutAsDirty();
+		_markContentAsDirty();
 	}
 	}
 
 
 	void GUITexture::setTexture(const HSpriteTexture& texture)
 	void GUITexture::setTexture(const HSpriteTexture& texture)
 	{
 	{
+		Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+
 		mActiveTexture = texture;
 		mActiveTexture = texture;
 		mUsingStyleTexture = false;
 		mUsingStyleTexture = false;
 
 
-		_markLayoutAsDirty();
+		Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
+		if (origSize != newSize)
+			_markLayoutAsDirty();
+		else
+			_markContentAsDirty();
 	}
 	}
 
 
 	UINT32 GUITexture::_getNumRenderElements() const
 	UINT32 GUITexture::_getNumRenderElements() const

+ 2 - 0
TODO.txt

@@ -71,6 +71,8 @@ Avoid fully recalculating layout for common operations like changing button stat
   - when button state changes, when input box contents change (by user or code), when text field data changes
   - when button state changes, when input box contents change (by user or code), when text field data changes
  - ADDITIONALLY consider marking the mesh not dirty after layout update if size didn't change
  - ADDITIONALLY consider marking the mesh not dirty after layout update if size didn't change
 
 
+GET RID OF CONTENT STRING CALLBACKS - They're messsing with my optimization as I cannot calculate orig bounds before and after their update
+
 GUILabel
 GUILabel
  - don't mark as dirty when contents change unless it affects optimal size
  - don't mark as dirty when contents change unless it affects optimal size
 GUIInputBox
 GUIInputBox