Procházet zdrojové kódy

Modified GUIContent so it can accept separate images for different GUI element states

BearishSun před 10 roky
rodič
revize
1755c6baeb

+ 1 - 1
BansheeEditor/Include/BsGUITabButton.h

@@ -122,7 +122,7 @@ namespace BansheeEngine
 		UINT32 mIndex;
 		UINT32 mIndex;
 		Vector2I mDragStartPosition;
 		Vector2I mDragStartPosition;
 		bool mDraggedState;
 		bool mDraggedState;
-		GUIButtonState mInactiveState;
+		GUIElementState mInactiveState;
 
 
 		static const UINT32 DRAG_MIN_DISTANCE;
 		static const UINT32 DRAG_MIN_DISTANCE;
 	};
 	};

+ 6 - 6
BansheeEditor/Source/BsGUITabButton.cpp

@@ -75,8 +75,8 @@ namespace BansheeEngine
 		{
 		{
 			mInactiveState = getState();
 			mInactiveState = getState();
 
 
-			if(mInactiveState != GUIButtonState::Normal)
-				_setState(GUIButtonState::Normal);
+			if(mInactiveState != GUIElementState::Normal)
+				_setState(GUIElementState::Normal);
 		}
 		}
 		else
 		else
 		{
 		{
@@ -91,7 +91,7 @@ namespace BansheeEngine
 		{
 		{
 			if (!_isDisabled())
 			if (!_isDisabled())
 			{
 			{
-				GUIButtonState state = _isOn() ? GUIButtonState::HoverOn : GUIButtonState::Hover;
+				GUIElementState state = _isOn() ? GUIElementState::HoverOn : GUIElementState::Hover;
 
 
 				if (!mDraggedState)
 				if (!mDraggedState)
 				{
 				{
@@ -110,7 +110,7 @@ namespace BansheeEngine
 		{
 		{
 			if (!_isDisabled())
 			if (!_isDisabled())
 			{
 			{
-				GUIButtonState state = _isOn() ? GUIButtonState::NormalOn : GUIButtonState::Normal;
+				GUIElementState state = _isOn() ? GUIElementState::NormalOn : GUIElementState::Normal;
 
 
 				if (!mDraggedState)
 				if (!mDraggedState)
 				{
 				{
@@ -130,7 +130,7 @@ namespace BansheeEngine
 			if (!_isDisabled())
 			if (!_isDisabled())
 			{
 			{
 				if (!mDraggedState)
 				if (!mDraggedState)
-					_setState(_isOn() ? GUIButtonState::ActiveOn : GUIButtonState::Active);
+					_setState(_isOn() ? GUIElementState::ActiveOn : GUIElementState::Active);
 
 
 				_setElementDepth(0);
 				_setElementDepth(0);
 			}
 			}
@@ -143,7 +143,7 @@ namespace BansheeEngine
 			{
 			{
 				if (!mDraggedState)
 				if (!mDraggedState)
 				{
 				{
-					_setState(_isOn() ? GUIButtonState::HoverOn : GUIButtonState::Hover);
+					_setState(_isOn() ? GUIElementState::HoverOn : GUIElementState::Hover);
 
 
 					if (!onClick.empty())
 					if (!onClick.empty())
 						onClick();
 						onClick();

+ 9 - 18
BansheeEngine/Include/BsGUIButtonBase.h

@@ -9,21 +9,6 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	/**
-	 * @brief	Type of GUI button states.
-	 */
-	enum class GUIButtonState
-	{
-		Normal = 0x01, /**< Normal state when button is not being iteracted with. */
-		Hover = 0x02, /**< State when pointer is hovering over the button. */
-		Active = 0x04, /**< State when button is being clicked. */
-		Focused = 0x08, /**< State when button has been selected. */
-		NormalOn = 0x11, /**< Normal state when button is not being iteracted with and is in "on" state. */
-		HoverOn = 0x12, /**< State when pointer is hovering over the button and is in "on" state. */
-		ActiveOn = 0x14, /**< State when button is being clicked and is in "on" state. */
-		FocusedOn = 0x18 /**< State when button has been selected and is in "on" state. */
-	};
-
 	/**
 	/**
 	 * @brief	Base class for a clickable GUI button element.
 	 * @brief	Base class for a clickable GUI button element.
 	 */	
 	 */	
@@ -52,7 +37,7 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @brief	Change the internal button state, changing the button look depending on set style.
 		 * @brief	Change the internal button state, changing the button look depending on set style.
 		 */
 		 */
-		void _setState(GUIButtonState state);
+		void _setState(GUIElementState state);
 
 
 		/**
 		/**
 		 * @copydoc	GUIElement::_getOptimalSize
 		 * @copydoc	GUIElement::_getOptimalSize
@@ -123,6 +108,12 @@ namespace BansheeEngine
 		 */
 		 */
 		virtual UINT32 _getRenderElementDepth(UINT32 renderElementIdx) const override;
 		virtual UINT32 _getRenderElementDepth(UINT32 renderElementIdx) const override;
 
 
+		/**
+		 * @brief	Creates or destroys the content image sprite depending if there is a content image for the
+		 *			active state.
+		 */
+		void refreshContentSprite();
+
 		/**
 		/**
 		 * @brief	Gets the text sprite descriptor used for creating/updating the internal text sprite.
 		 * @brief	Gets the text sprite descriptor used for creating/updating the internal text sprite.
 		 */
 		 */
@@ -131,7 +122,7 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @brief	Retrieves internal button state.
 		 * @brief	Retrieves internal button state.
 		 */
 		 */
-		GUIButtonState getState() const { return mActiveState; }
+		GUIElementState getState() const { return mActiveState; }
 
 
 		/**
 		/**
 		 * @brief	Returns the active sprite texture, depending on the current state.
 		 * @brief	Returns the active sprite texture, depending on the current state.
@@ -146,7 +137,7 @@ namespace BansheeEngine
 		ImageSprite* mImageSprite;
 		ImageSprite* mImageSprite;
 		ImageSprite* mContentImageSprite;
 		ImageSprite* mContentImageSprite;
 		TextSprite* mTextSprite;
 		TextSprite* mTextSprite;
-		GUIButtonState mActiveState;
+		GUIElementState mActiveState;
 
 
 		IMAGE_SPRITE_DESC mImageDesc;
 		IMAGE_SPRITE_DESC mImageDesc;
 		GUIContent mContent;
 		GUIContent mContent;

+ 40 - 7
BansheeEngine/Include/BsGUIContent.h

@@ -3,6 +3,39 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	/**
+	 * @brief	Type of GUI element states.
+	 */
+	enum class GUIElementState
+	{
+		Normal = 0x01, /**< Normal state when button is not being iteracted with. */
+		Hover = 0x02, /**< State when pointer is hovering over the button. */
+		Active = 0x04, /**< State when button is being clicked. */
+		Focused = 0x08, /**< State when button has been selected. */
+		NormalOn = 0x11, /**< Normal state when button is not being iteracted with and is in "on" state. */
+		HoverOn = 0x12, /**< State when pointer is hovering over the button and is in "on" state. */
+		ActiveOn = 0x14, /**< State when button is being clicked and is in "on" state. */
+		FocusedOn = 0x18 /**< State when button has been selected and is in "on" state. */
+	};
+
+	/**
+	 * @brief	Contains separate GUI content images for every possible GUI element state.
+	 */
+	struct BS_EXPORT GUIContentImages
+	{
+		GUIContentImages() {}
+		GUIContentImages(const HSpriteTexture& image);
+
+		HSpriteTexture normal;
+		HSpriteTexture hover;
+		HSpriteTexture active;
+		HSpriteTexture focused;
+		HSpriteTexture normalOn;
+		HSpriteTexture hoverOn;
+		HSpriteTexture activeOn;
+		HSpriteTexture focusedOn;
+	};
+
 	/**
 	/**
 	 * @brief	Holds data used for displaying content in a GUIElement. 
 	 * @brief	Holds data used for displaying content in a GUIElement. 
 	 *			Content can consist of a string, image, a tooltip or none of those.
 	 *			Content can consist of a string, image, a tooltip or none of those.
@@ -28,7 +61,7 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @brief	Constructs content with just an image.
 		 * @brief	Constructs content with just an image.
 		 */
 		 */
-		GUIContent(const HSpriteTexture& image);
+		GUIContent(const GUIContentImages& image);
 
 
 		/**
 		/**
 		 * @brief	Constructs content with an image and a tooltip.
 		 * @brief	Constructs content with an image and a tooltip.
@@ -36,14 +69,14 @@ namespace BansheeEngine
 		GUIContent(const HSpriteTexture& image, const HString& tooltip);
 		GUIContent(const HSpriteTexture& image, const HString& tooltip);
 
 
 		/**
 		/**
-		 * @brief	Constructs content with a string and an image.
+		 * @brief	Constructs content with a string and an image. 
 		 */
 		 */
-		GUIContent(const HString& text, const HSpriteTexture& image);
+		GUIContent(const HString& text, const GUIContentImages& image);
 
 
 		/**
 		/**
-		 * @brief	Constructs content with a string, an image and a tooltip.
+		 * @brief	Constructs content with a string, an image and a tooltip. 
 		 */
 		 */
-		GUIContent(const HString& text, const HSpriteTexture& image, const HString& tooltip);
+		GUIContent(const HString& text, const GUIContentImages& image, const HString& tooltip);
 
 
 		/**
 		/**
 		 * @brief	Returns string content (if any).
 		 * @brief	Returns string content (if any).
@@ -53,7 +86,7 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @brief	Returns image content (if any).
 		 * @brief	Returns image content (if any).
 		 */
 		 */
-		const HSpriteTexture& getImage() const { return mImage; }
+		const HSpriteTexture& getImage(GUIElementState state = GUIElementState::Normal) const;
 
 
 		/**
 		/**
 		 * @brief	Returns tooltip content (if any).
 		 * @brief	Returns tooltip content (if any).
@@ -66,7 +99,7 @@ namespace BansheeEngine
 		static const UINT32 IMAGE_TEXT_SPACING;
 		static const UINT32 IMAGE_TEXT_SPACING;
 	private:
 	private:
 		HString mText;
 		HString mText;
-		HSpriteTexture mImage;
+		GUIContentImages mImages;
 		HString mTooltipText;
 		HString mTooltipText;
 	};
 	};
 }
 }

+ 3 - 1
BansheeEngine/Include/BsGUIHelper.h

@@ -27,8 +27,10 @@ namespace BansheeEngine
 		 * @param	content			Content to calculate size for.
 		 * @param	content			Content to calculate size for.
 		 * @param	style			Style to use for determining size constraints.
 		 * @param	style			Style to use for determining size constraints.
 		 * @param	dimensions		Dimension constraints of a GUI element.
 		 * @param	dimensions		Dimension constraints of a GUI element.
+		 * @param	state			State of the GUI element in case the content changes according to state.
 		 */
 		 */
-		static Vector2I calcOptimalContentsSize(const GUIContent& content, const GUIElementStyle& style, const GUIDimensions& dimensions);
+		static Vector2I calcOptimalContentsSize(const GUIContent& content, const GUIElementStyle& style, 
+			const GUIDimensions& dimensions, GUIElementState state = GUIElementState::Normal);
 
 
 		/**
 		/**
 		 * @brief	Calculates optimal content size for the provided text using the provided style and layout options for constraints.
 		 * @brief	Calculates optimal content size for the provided text using the provided style and layout options for constraints.

+ 50 - 45
BansheeEngine/Source/BsGUIButtonBase.cpp

@@ -12,14 +12,12 @@
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	GUIButtonBase::GUIButtonBase(const String& styleName, const GUIContent& content, const GUIDimensions& dimensions)
 	GUIButtonBase::GUIButtonBase(const String& styleName, const GUIContent& content, const GUIDimensions& dimensions)
-		:GUIElement(styleName, dimensions), mContent(content), mContentImageSprite(nullptr), mActiveState(GUIButtonState::Normal)
+		:GUIElement(styleName, dimensions), mContent(content), mContentImageSprite(nullptr), mActiveState(GUIElementState::Normal)
 	{
 	{
 		mImageSprite = bs_new<ImageSprite>();
 		mImageSprite = bs_new<ImageSprite>();
 		mTextSprite = bs_new<TextSprite>();
 		mTextSprite = bs_new<TextSprite>();
 
 
-		HSpriteTexture contentTex = content.getImage();
-		if(SpriteTexture::checkIsLoaded(contentTex))
-			mContentImageSprite = bs_new<ImageSprite>();
+		refreshContentSprite();
 	}
 	}
 
 
 	GUIButtonBase::~GUIButtonBase()
 	GUIButtonBase::~GUIButtonBase()
@@ -36,20 +34,7 @@ namespace BansheeEngine
 		Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 		Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 		mContent = content;
 		mContent = content;
 
 
-		HSpriteTexture contentTex = content.getImage();
-		if (SpriteTexture::checkIsLoaded(contentTex))
-		{
-			if (mContentImageSprite == nullptr)
-				mContentImageSprite = bs_new<ImageSprite>();
-		}
-		else
-		{
-			if (mContentImageSprite != nullptr)
-			{
-				bs_delete(mContentImageSprite);
-				mContentImageSprite = nullptr;
-			}
-		}
+		refreshContentSprite();
 
 
 		Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 		Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 
 
@@ -62,9 +47,9 @@ namespace BansheeEngine
 	void GUIButtonBase::_setOn(bool on) 
 	void GUIButtonBase::_setOn(bool on) 
 	{ 
 	{ 
 		if(on)
 		if(on)
-			_setState((GUIButtonState)((INT32)mActiveState | 0x10)); 
+			_setState((GUIElementState)((INT32)mActiveState | 0x10)); 
 		else
 		else
-			_setState((GUIButtonState)((INT32)mActiveState & (~0x10))); 
+			_setState((GUIElementState)((INT32)mActiveState & (~0x10))); 
 	}
 	}
 
 
 	bool GUIButtonBase::_isOn() const
 	bool GUIButtonBase::_isOn() const
@@ -137,8 +122,9 @@ namespace BansheeEngine
 		{
 		{
 			Rect2I contentBounds = getCachedContentBounds();
 			Rect2I contentBounds = getCachedContentBounds();
 
 
-			UINT32 contentWidth = mContent.getImage()->getWidth();
-			UINT32 contentHeight = mContent.getImage()->getHeight();
+			HSpriteTexture image = mContent.getImage(mActiveState);
+			UINT32 contentWidth = image->getWidth();
+			UINT32 contentHeight = image->getHeight();
 
 
 			UINT32 contentMaxWidth = std::min((UINT32)contentBounds.width, contentWidth);
 			UINT32 contentMaxWidth = std::min((UINT32)contentBounds.width, contentWidth);
 			UINT32 contentMaxHeight = std::min((UINT32)contentBounds.height, contentHeight);
 			UINT32 contentMaxHeight = std::min((UINT32)contentBounds.height, contentHeight);
@@ -158,7 +144,7 @@ namespace BansheeEngine
 			}
 			}
 
 
 			IMAGE_SPRITE_DESC contentImgDesc;
 			IMAGE_SPRITE_DESC contentImgDesc;
-			contentImgDesc.texture = mContent.getImage().getInternalPtr();
+			contentImgDesc.texture = image.getInternalPtr();
 			contentImgDesc.width = contentWidth;
 			contentImgDesc.width = contentWidth;
 			contentImgDesc.height = contentHeight;
 			contentImgDesc.height = contentHeight;
 			contentImgDesc.color = getTint();
 			contentImgDesc.color = getTint();
@@ -181,7 +167,7 @@ namespace BansheeEngine
 			imageHeight = activeTex->getHeight();
 			imageHeight = activeTex->getHeight();
 		}
 		}
 
 
-		Vector2I contentSize = GUIHelper::calcOptimalContentsSize(mContent, *_getStyle(), _getDimensions());
+		Vector2I contentSize = GUIHelper::calcOptimalContentsSize(mContent, *_getStyle(), _getDimensions(), mActiveState);
 		UINT32 contentWidth = std::max(imageWidth, (UINT32)contentSize.x);
 		UINT32 contentWidth = std::max(imageWidth, (UINT32)contentSize.x);
 		UINT32 contentHeight = std::max(imageHeight, (UINT32)contentSize.y);
 		UINT32 contentHeight = std::max(imageHeight, (UINT32)contentSize.y);
 
 
@@ -299,7 +285,7 @@ namespace BansheeEngine
 		{
 		{
 			if (!_isDisabled())
 			if (!_isDisabled())
 			{
 			{
-				_setState(_isOn() ? GUIButtonState::HoverOn : GUIButtonState::Hover);
+				_setState(_isOn() ? GUIElementState::HoverOn : GUIElementState::Hover);
 				onHover();
 				onHover();
 			}
 			}
 
 
@@ -309,7 +295,7 @@ namespace BansheeEngine
 		{
 		{
 			if (!_isDisabled())
 			if (!_isDisabled())
 			{
 			{
-				_setState(_isOn() ? GUIButtonState::NormalOn : GUIButtonState::Normal);
+				_setState(_isOn() ? GUIElementState::NormalOn : GUIElementState::Normal);
 				onOut();
 				onOut();
 			}
 			}
 
 
@@ -318,7 +304,7 @@ namespace BansheeEngine
 		else if(ev.getType() == GUIMouseEventType::MouseDown)
 		else if(ev.getType() == GUIMouseEventType::MouseDown)
 		{
 		{
 			if (!_isDisabled())
 			if (!_isDisabled())
-				_setState(_isOn() ? GUIButtonState::ActiveOn : GUIButtonState::Active);
+				_setState(_isOn() ? GUIElementState::ActiveOn : GUIElementState::Active);
 
 
 			return true;
 			return true;
 		}
 		}
@@ -326,7 +312,7 @@ namespace BansheeEngine
 		{
 		{
 			if (!_isDisabled())
 			if (!_isDisabled())
 			{
 			{
-				_setState(_isOn() ? GUIButtonState::HoverOn : GUIButtonState::Hover);
+				_setState(_isOn() ? GUIElementState::HoverOn : GUIElementState::Hover);
 				onClick();
 				onClick();
 			}
 			}
 
 
@@ -341,6 +327,24 @@ namespace BansheeEngine
 		return false;
 		return false;
 	}
 	}
 
 
+	void GUIButtonBase::refreshContentSprite()
+	{
+		HSpriteTexture contentTex = mContent.getImage(mActiveState);
+		if (SpriteTexture::checkIsLoaded(contentTex))
+		{
+			if (mContentImageSprite == nullptr)
+				mContentImageSprite = bs_new<ImageSprite>();
+		}
+		else
+		{
+			if (mContentImageSprite != nullptr)
+			{
+				bs_delete(mContentImageSprite);
+				mContentImageSprite = nullptr;
+			}
+		}
+	}
+
 	TEXT_SPRITE_DESC GUIButtonBase::getTextDesc() const
 	TEXT_SPRITE_DESC GUIButtonBase::getTextDesc() const
 	{
 	{
 		TEXT_SPRITE_DESC textDesc;
 		TEXT_SPRITE_DESC textDesc;
@@ -359,10 +363,11 @@ namespace BansheeEngine
 		return textDesc;
 		return textDesc;
 	}
 	}
 
 
-	void GUIButtonBase::_setState(GUIButtonState state)
+	void GUIButtonBase::_setState(GUIElementState state)
 	{
 	{
 		Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 		Vector2I origSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 		mActiveState = state;
 		mActiveState = state;
+		refreshContentSprite();
 		Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 		Vector2I newSize = mDimensions.calculateSizeRange(_getOptimalSize()).optimal;
 
 
 		if (origSize != newSize)
 		if (origSize != newSize)
@@ -375,21 +380,21 @@ namespace BansheeEngine
 	{
 	{
 		switch(mActiveState)
 		switch(mActiveState)
 		{
 		{
-		case GUIButtonState::Normal:
+		case GUIElementState::Normal:
 			return _getStyle()->normal.texture;
 			return _getStyle()->normal.texture;
-		case GUIButtonState::Hover:
+		case GUIElementState::Hover:
 			return _getStyle()->hover.texture;
 			return _getStyle()->hover.texture;
-		case GUIButtonState::Active:
+		case GUIElementState::Active:
 			return _getStyle()->active.texture;
 			return _getStyle()->active.texture;
-		case GUIButtonState::Focused:
+		case GUIElementState::Focused:
 			return _getStyle()->focused.texture;
 			return _getStyle()->focused.texture;
-		case GUIButtonState::NormalOn:
+		case GUIElementState::NormalOn:
 			return _getStyle()->normalOn.texture;
 			return _getStyle()->normalOn.texture;
-		case GUIButtonState::HoverOn:
+		case GUIElementState::HoverOn:
 			return _getStyle()->hoverOn.texture;
 			return _getStyle()->hoverOn.texture;
-		case GUIButtonState::ActiveOn:
+		case GUIElementState::ActiveOn:
 			return _getStyle()->activeOn.texture;
 			return _getStyle()->activeOn.texture;
-		case GUIButtonState::FocusedOn:
+		case GUIElementState::FocusedOn:
 			return _getStyle()->focusedOn.texture;
 			return _getStyle()->focusedOn.texture;
 		}
 		}
 
 
@@ -400,21 +405,21 @@ namespace BansheeEngine
 	{
 	{
 		switch (mActiveState)
 		switch (mActiveState)
 		{
 		{
-		case GUIButtonState::Normal:
+		case GUIElementState::Normal:
 			return _getStyle()->normal.textColor;
 			return _getStyle()->normal.textColor;
-		case GUIButtonState::Hover:
+		case GUIElementState::Hover:
 			return _getStyle()->hover.textColor;
 			return _getStyle()->hover.textColor;
-		case GUIButtonState::Active:
+		case GUIElementState::Active:
 			return _getStyle()->active.textColor;
 			return _getStyle()->active.textColor;
-		case GUIButtonState::Focused:
+		case GUIElementState::Focused:
 			return _getStyle()->focused.textColor;
 			return _getStyle()->focused.textColor;
-		case GUIButtonState::NormalOn:
+		case GUIElementState::NormalOn:
 			return _getStyle()->normalOn.textColor;
 			return _getStyle()->normalOn.textColor;
-		case GUIButtonState::HoverOn:
+		case GUIElementState::HoverOn:
 			return _getStyle()->hoverOn.textColor;
 			return _getStyle()->hoverOn.textColor;
-		case GUIButtonState::ActiveOn:
+		case GUIElementState::ActiveOn:
 			return _getStyle()->activeOn.textColor;
 			return _getStyle()->activeOn.textColor;
-		case GUIButtonState::FocusedOn:
+		case GUIElementState::FocusedOn:
 			return _getStyle()->focusedOn.textColor;
 			return _getStyle()->focusedOn.textColor;
 		}
 		}
 
 

+ 37 - 7
BansheeEngine/Source/BsGUIContent.cpp

@@ -4,6 +4,11 @@ namespace BansheeEngine
 {
 {
 	const UINT32 GUIContent::IMAGE_TEXT_SPACING = 3;
 	const UINT32 GUIContent::IMAGE_TEXT_SPACING = 3;
 
 
+	GUIContentImages::GUIContentImages(const HSpriteTexture& image)
+		:normal(image), hover(image), active(image), focused(image), 
+		normalOn(image), hoverOn(image), activeOn(image), focusedOn(image)
+	{ }
+
 	GUIContent::GUIContent()
 	GUIContent::GUIContent()
 		:mText(L"")
 		:mText(L"")
 	{ }
 	{ }
@@ -16,19 +21,44 @@ namespace BansheeEngine
 		:mText(text), mTooltipText(tooltip)
 		:mText(text), mTooltipText(tooltip)
 	{ }
 	{ }
 
 
-	GUIContent::GUIContent(const HSpriteTexture& image)
-		:mImage(image)
+	GUIContent::GUIContent(const GUIContentImages& image)
+		:mImages(image)
 	{ }
 	{ }
 
 
 	GUIContent::GUIContent(const HSpriteTexture& image, const HString& tooltip)
 	GUIContent::GUIContent(const HSpriteTexture& image, const HString& tooltip)
-		:mImage(image), mTooltipText(tooltip)
+		:mImages(image), mTooltipText(tooltip)
 	{ }
 	{ }
 
 
-	GUIContent::GUIContent(const HString& text, const HSpriteTexture& image)
-		:mText(text), mImage(image)
+	GUIContent::GUIContent(const HString& text, const GUIContentImages& image)
+		:mText(text), mImages(image)
 	{ }
 	{ }
 
 
-	GUIContent::GUIContent(const HString& text, const HSpriteTexture& image, const HString& tooltip)
-		:mText(text), mImage(image), mTooltipText(tooltip)
+	GUIContent::GUIContent(const HString& text, const GUIContentImages& image, const HString& tooltip)
+		:mText(text), mImages(image), mTooltipText(tooltip)
 	{ }
 	{ }
+
+	const HSpriteTexture& GUIContent::getImage(GUIElementState state) const
+	{
+		switch (state)
+		{
+		case GUIElementState::Normal:
+			return mImages.normal;
+		case GUIElementState::Hover:
+			return mImages.hover;
+		case GUIElementState::Active:
+			return mImages.active;
+		case GUIElementState::Focused:
+			return mImages.focused;
+		case GUIElementState::NormalOn:
+			return mImages.normalOn;
+		case GUIElementState::HoverOn:
+			return mImages.hoverOn;
+		case GUIElementState::ActiveOn:
+			return mImages.activeOn;
+		case GUIElementState::FocusedOn:
+			return mImages.focusedOn;
+		default:
+			return mImages.normal;
+		}
+	}
 }
 }

+ 4 - 4
BansheeEngine/Source/BsGUIDropDownContent.cpp

@@ -271,16 +271,16 @@ namespace BansheeEngine
 		if (mSelectedIdx != UINT_MAX)
 		if (mSelectedIdx != UINT_MAX)
 		{
 		{
 			if (mVisibleElements[mSelectedIdx].button->_isOn())
 			if (mVisibleElements[mSelectedIdx].button->_isOn())
-				mVisibleElements[mSelectedIdx].button->_setState(GUIButtonState::NormalOn);
+				mVisibleElements[mSelectedIdx].button->_setState(GUIElementState::NormalOn);
 			else
 			else
-				mVisibleElements[mSelectedIdx].button->_setState(GUIButtonState::Normal);
+				mVisibleElements[mSelectedIdx].button->_setState(GUIElementState::Normal);
 		}
 		}
 
 
 		mSelectedIdx = idx;
 		mSelectedIdx = idx;
 		if (mVisibleElements[mSelectedIdx].button->_isOn())
 		if (mVisibleElements[mSelectedIdx].button->_isOn())
-			mVisibleElements[mSelectedIdx].button->_setState(GUIButtonState::HoverOn);
+			mVisibleElements[mSelectedIdx].button->_setState(GUIElementState::HoverOn);
 		else
 		else
-			mVisibleElements[mSelectedIdx].button->_setState(GUIButtonState::Hover);
+			mVisibleElements[mSelectedIdx].button->_setState(GUIElementState::Hover);
 
 
 		mParent->elementSelected(mVisibleElements[mSelectedIdx].idx);
 		mParent->elementSelected(mVisibleElements[mSelectedIdx].idx);
 	}
 	}

+ 10 - 6
BansheeEngine/Source/BsGUIHelper.cpp

@@ -6,7 +6,8 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	Vector2I GUIHelper::calcOptimalContentsSize(const Vector2I& contentSize, const GUIElementStyle& style, const GUIDimensions& dimensions)
+	Vector2I GUIHelper::calcOptimalContentsSize(const Vector2I& contentSize, const GUIElementStyle& style, 
+		const GUIDimensions& dimensions)
 	{
 	{
 		UINT32 contentWidth = style.margins.left + style.margins.right + style.contentOffset.left + style.contentOffset.right;
 		UINT32 contentWidth = style.margins.left + style.margins.right + style.contentOffset.left + style.contentOffset.right;
 		UINT32 contentHeight = style.margins.top + style.margins.bottom + style.contentOffset.top + style.contentOffset.bottom;
 		UINT32 contentHeight = style.margins.top + style.margins.bottom + style.contentOffset.top + style.contentOffset.bottom;
@@ -14,20 +15,23 @@ namespace BansheeEngine
 		return Vector2I(std::max((UINT32)contentSize.x, contentWidth), std::max((UINT32)contentSize.y, contentHeight));
 		return Vector2I(std::max((UINT32)contentSize.x, contentWidth), std::max((UINT32)contentSize.y, contentHeight));
 	}
 	}
 
 
-	Vector2I GUIHelper::calcOptimalContentsSize(const GUIContent& content, const GUIElementStyle& style, const GUIDimensions& dimensions)
+	Vector2I GUIHelper::calcOptimalContentsSize(const GUIContent& content, const GUIElementStyle& style, 
+		const GUIDimensions& dimensions, GUIElementState state)
 	{
 	{
 		Vector2I contentBounds = calcOptimalContentsSize((const WString&)content.getText(), style, dimensions);
 		Vector2I contentBounds = calcOptimalContentsSize((const WString&)content.getText(), style, dimensions);
 
 
-		if(content.getImage() != nullptr)
+		HSpriteTexture image = content.getImage(state);
+		if (image != nullptr)
 		{
 		{
-			contentBounds.x += content.getImage()->getWidth() + GUIContent::IMAGE_TEXT_SPACING;
-			contentBounds.y = std::max(content.getImage()->getHeight(), (UINT32)contentBounds.y);
+			contentBounds.x += image->getWidth() + GUIContent::IMAGE_TEXT_SPACING;
+			contentBounds.y = std::max(image->getHeight(), (UINT32)contentBounds.y);
 		}
 		}
 
 
 		return contentBounds;
 		return contentBounds;
 	}
 	}
 
 
-	Vector2I GUIHelper::calcOptimalContentsSize(const WString& text, const GUIElementStyle& style, const GUIDimensions& dimensions)
+	Vector2I GUIHelper::calcOptimalContentsSize(const WString& text, const GUIElementStyle& style, const 
+		GUIDimensions& dimensions)
 	{
 	{
 		UINT32 wordWrapWidth = 0;
 		UINT32 wordWrapWidth = 0;
 
 

+ 102 - 12
MBansheeEngine/GUI/GUIContent.cs

@@ -3,14 +3,37 @@
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
     /// <summary>
     /// <summary>
-    /// Holds data used for displaying content in a GUIElement.  Content can consist of a string, image, a tooltip or none 
+    /// Type of GUI element states.
+    /// </summary>
+	public enum GUIElementState
+	{
+        /// <summary>Normal state when button is not being iteracted with.</summary>
+		Normal = 0x01,
+        /// <summary>State when pointer is hovering over the button.</summary>
+		Hover = 0x02,
+        /// <summary>State when button is being clicked.</summary>
+		Active = 0x04,
+        /// <summary>State when button has been selected.</summary>
+		Focused = 0x08,
+        /// <summary>Normal state when button is not being iteracted with and is in "on" state.</summary>
+		NormalOn = 0x11,
+        /// <summary>State when pointer is hovering over the button and is in "on" state.</summary>
+		HoverOn = 0x12,
+        /// <summary>State when button is being clicked and is in "on" state.</summary>
+		ActiveOn = 0x14,
+        /// <summary>State when button has been selected and is in "on" state.</summary>
+		FocusedOn = 0x18
+	};
+
+    /// <summary>
+    /// Holds data used for displaying content in a GUIElement. Content can consist of a string, image, a tooltip or none 
     /// of those.
     /// of those.
     /// </summary>
     /// </summary>
     public sealed class GUIContent
     public sealed class GUIContent
     {
     {
         private LocString text;
         private LocString text;
         private LocString tooltip;
         private LocString tooltip;
-        private SpriteTexture image;
+        private GUIContentImages images;
 
 
         /// <summary>
         /// <summary>
         /// Returns string content (if any).
         /// Returns string content (if any).
@@ -23,9 +46,29 @@ namespace BansheeEngine
         /// <summary>
         /// <summary>
         /// Returns image content (if any).
         /// Returns image content (if any).
         /// </summary>
         /// </summary>
-        public SpriteTexture Image
+        public SpriteTexture GetImage(GUIElementState state = GUIElementState.Normal)
         {
         {
-            get { return image; }
+            switch (state)
+		    {
+		    case GUIElementState.Normal:
+			    return images.normal;
+		    case GUIElementState.Hover:
+                return images.hover;
+		    case GUIElementState.Active:
+                return images.active;
+		    case GUIElementState.Focused:
+                return images.focused;
+		    case GUIElementState.NormalOn:
+                return images.normalOn;
+		    case GUIElementState.HoverOn:
+                return images.hoverOn;
+		    case GUIElementState.ActiveOn:
+                return images.activeOn;
+		    case GUIElementState.FocusedOn:
+                return images.focusedOn;
+		    default:
+                return images.normal;
+		    }
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -60,9 +103,9 @@ namespace BansheeEngine
         /// Constructs content with just an image.
         /// Constructs content with just an image.
         /// </summary>
         /// </summary>
         /// <param name="image">Image to be displayed on top of the GUI element.</param>
         /// <param name="image">Image to be displayed on top of the GUI element.</param>
-        public GUIContent(SpriteTexture image)
+        public GUIContent(GUIContentImages image)
         {
         {
-            this.image = image;
+            this.images = image;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -70,9 +113,9 @@ namespace BansheeEngine
         /// </summary>
         /// </summary>
         /// <param name="image">Image to be displayed on top of the GUI element.</param>
         /// <param name="image">Image to be displayed on top of the GUI element.</param>
         /// <param name="tooltip">Tooltip to be displayed when user hovers over a GUI element.</param>
         /// <param name="tooltip">Tooltip to be displayed when user hovers over a GUI element.</param>
-        public GUIContent(SpriteTexture image, LocString tooltip)
+        public GUIContent(GUIContentImages image, LocString tooltip)
         {
         {
-            this.image = image;
+            this.images = image;
             this.tooltip = tooltip;
             this.tooltip = tooltip;
         }
         }
 
 
@@ -82,10 +125,10 @@ namespace BansheeEngine
         /// <param name="text">Textual portion of the content to be displayed as label in GUI elements.</param>
         /// <param name="text">Textual portion of the content to be displayed as label in GUI elements.</param>
         /// <param name="image">Image to be displayed on top of the GUI element. Image will be placed to the right or to the 
         /// <param name="image">Image to be displayed on top of the GUI element. Image will be placed to the right or to the 
         ///                     left of the text depending on active GUI style.</param>
         ///                     left of the text depending on active GUI style.</param>
-        public GUIContent(LocString text, SpriteTexture image)
+        public GUIContent(LocString text, GUIContentImages image)
         {
         {
             this.text = text;
             this.text = text;
-            this.image = image;
+            this.images = image;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -95,10 +138,10 @@ namespace BansheeEngine
         /// <param name="image">Image to be displayed on top of the GUI element. Image will be placed to the right or to the 
         /// <param name="image">Image to be displayed on top of the GUI element. Image will be placed to the right or to the 
         ///                     left of the text depending on active GUI style.</param>
         ///                     left of the text depending on active GUI style.</param>
         /// <param name="tooltip">Tooltip to be displayed when user hovers over a GUI element.</param>
         /// <param name="tooltip">Tooltip to be displayed when user hovers over a GUI element.</param>
-        public GUIContent(LocString text, SpriteTexture image, LocString tooltip)
+        public GUIContent(LocString text, GUIContentImages image, LocString tooltip)
         {
         {
             this.text = text;
             this.text = text;
-            this.image = image;
+            this.images = image;
             this.tooltip = tooltip;
             this.tooltip = tooltip;
         }
         }
 
 
@@ -122,4 +165,51 @@ namespace BansheeEngine
             return new GUIContent(new LocString(text));
             return new GUIContent(new LocString(text));
         }
         }
     }
     }
+
+    /// <summary>
+    /// Contains separate GUI content images for every possible GUI element state.
+    /// </summary>
+    public sealed class GUIContentImages
+    {
+        /// <summary>
+        /// Creates an empty content image object referencing no images.
+        /// </summary>
+        public GUIContentImages()
+        { }
+
+        /// <summary>
+        /// Creates a new object where content images for all states are the same.
+        /// </summary>
+        /// <param name="image">Image to assign to all states.</param>
+        public GUIContentImages(SpriteTexture image)
+        {
+            normal = image;
+            hover = image;
+            active = image;
+            focused = image;
+            normalOn = image;
+            hoverOn = image;
+            activeOn = image;
+            focusedOn = image;
+        }
+
+        /// <summary>
+        /// Implicitly converts a sprite texture into a GUI content images object.
+        /// </summary>
+        /// <param name="image">Image to instantiate the GUI content images with.</param>
+        /// <returns>GUI content images with all states set to the provided image.</returns>
+        public static implicit operator GUIContentImages(SpriteTexture image)
+        {
+            return new GUIContentImages(image);
+        }
+
+        public SpriteTexture normal;
+        public SpriteTexture hover;
+        public SpriteTexture active;
+        public SpriteTexture focused;
+        public SpriteTexture normalOn;
+        public SpriteTexture hoverOn;
+        public SpriteTexture activeOn;
+        public SpriteTexture focusedOn;
+    }
 }
 }

+ 3 - 2
SBansheeEngine/Include/BsScriptGUIContent.h

@@ -2,6 +2,7 @@
 
 
 #include "BsScriptEnginePrerequisites.h"
 #include "BsScriptEnginePrerequisites.h"
 #include "BsScriptObject.h"
 #include "BsScriptObject.h"
+#include "BsGUIContent.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -26,13 +27,13 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @brief	Retrieves the content image in a managed GUIContent instance.
 		 * @brief	Retrieves the content image in a managed GUIContent instance.
 		 */
 		 */
-		static HSpriteTexture getImage(MonoObject* instance);
+		static GUIContentImages getImage(MonoObject* instance);
 
 
 	private:
 	private:
 		ScriptGUIContent(MonoObject* instance);
 		ScriptGUIContent(MonoObject* instance);
 
 
 		static MonoField* mTextField;
 		static MonoField* mTextField;
 		static MonoField* mTooltipField;
 		static MonoField* mTooltipField;
-		static MonoField* mImageField;
+		static MonoField* mImagesField;
 	};
 	};
 }
 }

+ 39 - 0
SBansheeEngine/Include/BsScriptGUIContentImages.h

@@ -0,0 +1,39 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptObject.h"
+#include "BsGUIContent.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Interop class between C++ & CLR for GUIContentImages.
+	 */
+	class BS_SCR_BE_EXPORT ScriptGUIContentImages : public ScriptObject<ScriptGUIContentImages>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "GUIContentImages")
+
+		/**
+		 * @brief	Converts a managed GUIContentImages instance to a native one.
+		 */
+		static GUIContentImages getNative(MonoObject* instance);
+
+		/**
+		 * @brief	Converts a native GUIContentImages instance to a managed one.
+		 */
+		static MonoObject* getManaged(const GUIContentImages& images);
+
+	private:
+		ScriptGUIContentImages(MonoObject* instance);
+
+		static MonoField* mNormalField;
+		static MonoField* mHoverField;
+		static MonoField* mActiveField;
+		static MonoField* mFocusedField;
+		static MonoField* mNormalOnField;
+		static MonoField* mHoverOnField;
+		static MonoField* mActiveOnField;
+		static MonoField* mFocusedOnField;
+	};
+}

+ 2 - 0
SBansheeEngine/SBansheeEngine.vcxproj

@@ -286,6 +286,7 @@
     <ClInclude Include="Include\BsScriptGameObject.h" />
     <ClInclude Include="Include\BsScriptGameObject.h" />
     <ClInclude Include="Include\BsScriptGameObjectManager.h" />
     <ClInclude Include="Include\BsScriptGameObjectManager.h" />
     <ClInclude Include="Include\BsScriptGUIButton.h" />
     <ClInclude Include="Include\BsScriptGUIButton.h" />
+    <ClInclude Include="Include\BsScriptGUIContentImages.h" />
     <ClInclude Include="Include\BsScriptGUIElement.h" />
     <ClInclude Include="Include\BsScriptGUIElement.h" />
     <ClInclude Include="Include\BsScriptGUIFixedSpace.h" />
     <ClInclude Include="Include\BsScriptGUIFixedSpace.h" />
     <ClInclude Include="Include\BsScriptGUIFlexibleSpace.h" />
     <ClInclude Include="Include\BsScriptGUIFlexibleSpace.h" />
@@ -382,6 +383,7 @@
     <ClCompile Include="Source\BsScriptGameObject.cpp" />
     <ClCompile Include="Source\BsScriptGameObject.cpp" />
     <ClCompile Include="Source\BsScriptGameObjectManager.cpp" />
     <ClCompile Include="Source\BsScriptGameObjectManager.cpp" />
     <ClCompile Include="Source\BsScriptGUIButton.cpp" />
     <ClCompile Include="Source\BsScriptGUIButton.cpp" />
+    <ClCompile Include="Source\BsScriptGUIContentImages.cpp" />
     <ClCompile Include="Source\BsScriptGUIElement.cpp" />
     <ClCompile Include="Source\BsScriptGUIElement.cpp" />
     <ClCompile Include="Source\BsScriptGUIFixedSpace.cpp" />
     <ClCompile Include="Source\BsScriptGUIFixedSpace.cpp" />
     <ClCompile Include="Source\BsScriptGUIFlexibleSpace.cpp" />
     <ClCompile Include="Source\BsScriptGUIFlexibleSpace.cpp" />

+ 6 - 0
SBansheeEngine/SBansheeEngine.vcxproj.filters

@@ -354,6 +354,9 @@
     <ClInclude Include="Include\BsScriptLogEntry.h">
     <ClInclude Include="Include\BsScriptLogEntry.h">
       <Filter>Header Files</Filter>
       <Filter>Header Files</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptGUIContentImages.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
@@ -647,5 +650,8 @@
     <ClCompile Include="Source\BsScriptLogEntry.cpp">
     <ClCompile Include="Source\BsScriptLogEntry.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptGUIContentImages.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 9 - 9
SBansheeEngine/Source/BsScriptGUIContent.cpp

@@ -7,12 +7,13 @@
 #include "BsScriptHString.h"
 #include "BsScriptHString.h"
 #include "BsScriptSpriteTexture.h"
 #include "BsScriptSpriteTexture.h"
 #include "BsSpriteTexture.h"
 #include "BsSpriteTexture.h"
+#include "BsScriptGUIContentImages.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	MonoField* ScriptGUIContent::mTextField;
 	MonoField* ScriptGUIContent::mTextField;
 	MonoField* ScriptGUIContent::mTooltipField;
 	MonoField* ScriptGUIContent::mTooltipField;
-	MonoField* ScriptGUIContent::mImageField;
+	MonoField* ScriptGUIContent::mImagesField;
 
 
 	ScriptGUIContent::ScriptGUIContent(MonoObject* instance)
 	ScriptGUIContent::ScriptGUIContent(MonoObject* instance)
 		:ScriptObject(instance)
 		:ScriptObject(instance)
@@ -22,7 +23,7 @@ namespace BansheeEngine
 	{
 	{
 		mTextField = metaData.scriptClass->getField("text");
 		mTextField = metaData.scriptClass->getField("text");
 		mTooltipField = metaData.scriptClass->getField("tooltip");
 		mTooltipField = metaData.scriptClass->getField("tooltip");
-		mImageField = metaData.scriptClass->getField("image");
+		mImagesField = metaData.scriptClass->getField("images");
 	}
 	}
 
 
 	const HString& ScriptGUIContent::getText(MonoObject* instance)
 	const HString& ScriptGUIContent::getText(MonoObject* instance)
@@ -49,15 +50,14 @@ namespace BansheeEngine
 		return tooltipScript->getInternalValue();
 		return tooltipScript->getInternalValue();
 	}
 	}
 
 
-	HSpriteTexture ScriptGUIContent::getImage(MonoObject* instance)
+	GUIContentImages ScriptGUIContent::getImage(MonoObject* instance)
 	{
 	{
-		MonoObject* imageManaged = nullptr;
-		mImageField->getValue(instance, &imageManaged);
+		MonoObject* imagesManaged = nullptr;
+		mImagesField->getValue(instance, &imagesManaged);
 
 
-		if(imageManaged == nullptr)
-			return HSpriteTexture();
+		if(imagesManaged == nullptr)
+			return GUIContentImages();
 
 
-		ScriptSpriteTexture* imageScript = ScriptSpriteTexture::toNative(imageManaged);
-		return imageScript->getHandle();
+		return ScriptGUIContentImages::getNative(imagesManaged);
 	}
 	}
 }
 }

+ 111 - 0
SBansheeEngine/Source/BsScriptGUIContentImages.cpp

@@ -0,0 +1,111 @@
+#include "BsScriptGUIContentImages.h"
+#include "BsScriptSpriteTexture.h"
+#include "BsScriptResourceManager.h"
+
+namespace BansheeEngine
+{
+	MonoField* ScriptGUIContentImages::mNormalField;
+	MonoField* ScriptGUIContentImages::mHoverField;
+	MonoField* ScriptGUIContentImages::mActiveField;
+	MonoField* ScriptGUIContentImages::mFocusedField;
+	MonoField* ScriptGUIContentImages::mNormalOnField;
+	MonoField* ScriptGUIContentImages::mHoverOnField;
+	MonoField* ScriptGUIContentImages::mActiveOnField;
+	MonoField* ScriptGUIContentImages::mFocusedOnField;
+
+	ScriptGUIContentImages::ScriptGUIContentImages(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptGUIContentImages::initRuntimeData()
+	{
+		mNormalField = metaData.scriptClass->getField("normal");
+		mHoverField = metaData.scriptClass->getField("hover");
+		mActiveField = metaData.scriptClass->getField("active");
+		mFocusedField = metaData.scriptClass->getField("focused");
+		mNormalOnField = metaData.scriptClass->getField("normalOn");
+		mHoverOnField = metaData.scriptClass->getField("hoverOn");
+		mActiveOnField = metaData.scriptClass->getField("activeOn");
+		mFocusedOnField = metaData.scriptClass->getField("focusedOn");
+	}
+
+	GUIContentImages ScriptGUIContentImages::getNative(MonoObject* instance)
+	{
+		GUIContentImages output;
+
+		struct Entry
+		{
+			Entry(MonoField* field, HSpriteTexture& outputImage)
+				:field(field), outputImage(outputImage)
+			{ }
+
+			MonoField* field;
+			HSpriteTexture& outputImage;
+		};
+
+		Entry entries[8] = 
+		{ 
+			{ mNormalField, output.normal },
+			{ mHoverField, output.hover },
+			{ mActiveField, output.active },
+			{ mFocusedField, output.focused },
+			{ mNormalOnField, output.normalOn },
+			{ mHoverOnField, output.hoverOn },
+			{ mActiveOnField, output.activeOn },
+			{ mFocusedOnField, output.focusedOn },
+		};
+
+		for (auto& entry : entries)
+		{
+			MonoObject* managedImage;
+			entry.field->getValue(instance, &managedImage);
+
+			if (managedImage != nullptr)
+				entry.outputImage = ScriptSpriteTexture::toNative(managedImage)->getHandle();
+		}
+
+		return output;
+	}
+
+	MonoObject* ScriptGUIContentImages::getManaged(const GUIContentImages& images)
+	{
+		struct Entry
+		{
+			Entry(MonoField* field, const HSpriteTexture& outputImage)
+				:field(field), image(outputImage)
+			{ }
+
+			MonoField* field;
+			const HSpriteTexture& image;
+		};
+
+		Entry entries[8] =
+		{
+			{ mNormalField, images.normal },
+			{ mHoverField, images.hover },
+			{ mActiveField, images.active },
+			{ mFocusedField, images.focused },
+			{ mNormalOnField, images.normalOn },
+			{ mHoverOnField, images.hoverOn },
+			{ mActiveOnField, images.activeOn },
+			{ mFocusedOnField, images.focusedOn },
+		};
+
+		MonoObject* output = metaData.scriptClass->createInstance();
+		for (auto& entry : entries)
+		{
+			MonoObject* managedImage = nullptr;
+			if (entry.image != nullptr)
+			{
+				ScriptSpriteTexture* scriptImage;
+				ScriptResourceManager::instance().getScriptResource(entry.image, &scriptImage, true);
+
+				managedImage = scriptImage->getManagedInstance();
+			}
+
+			entry.field->setValue(output, managedImage);
+		}
+
+		return output;
+	}
+}