Просмотр исходного кода

GUI slider and progress bar WIP

Marko Pintera 11 лет назад
Родитель
Сommit
dd31dc8f1c

+ 0 - 1
BansheeEditor/Source/BsGUIFieldBase.cpp

@@ -33,7 +33,6 @@ namespace BansheeEngine
 		return GUILayoutUtility::calcOptimalSize(mLayout);
 	}
 
-
 	void GUIFieldBase::styleUpdated()
 	{
 		if (mLabel != nullptr)

+ 8 - 4
BansheeEditor/Source/BsGUITabbedTitleBar.cpp

@@ -42,12 +42,15 @@ namespace BansheeEngine
 			mTabBtnStyle = "TabbedBarBtn";
 
 		mBackgroundImage = GUITexture::create(mBackgroundStyle);
+		mBackgroundImage->_setElementDepth(2);
 		_registerChildElement(mBackgroundImage);
 
 		mMinBtn = GUIButton::create(HString(L""), mMinimizeBtnStyle);
+		mMinBtn->_setElementDepth(1);
 		_registerChildElement(mMinBtn);
 
 		mCloseBtn = GUIButton::create(HString(L""), mCloseBtnStyle);
+		mCloseBtn->_setElementDepth(1);
 		_registerChildElement(mCloseBtn);
 
 		mCloseBtn->onClick.connect(std::bind(&GUITabbedTitleBar::tabClosed, this));
@@ -82,6 +85,7 @@ namespace BansheeEngine
 	UINT32 GUITabbedTitleBar::insertTab(UINT32 position, const HString& name)
 	{
 		GUITabButton* newTabToggle = GUITabButton::create(mTabToggleGroup, mUniqueTabIdx, name, mTabBtnStyle);
+		newTabToggle->_setElementDepth(1);
 		_registerChildElement(newTabToggle);
 
 		position = Math::clamp(position, 0U, (UINT32)mTabButtons.size());
@@ -247,7 +251,7 @@ namespace BansheeEngine
 			mBackgroundImage->_setOffset(offset);
 			mBackgroundImage->_setWidth(width - 2);
 			mBackgroundImage->_setHeight(optimalSize.y);
-			mBackgroundImage->_setAreaDepth(areaDepth + 2);
+			mBackgroundImage->_setAreaDepth(areaDepth);
 			mBackgroundImage->_setWidgetDepth(widgetDepth);
 
 			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
@@ -279,7 +283,7 @@ namespace BansheeEngine
 			btn->_setOffset(offset);
 			btn->_setWidth(optimalSize.x);
 			btn->_setHeight(optimalSize.y);
-			btn->_setAreaDepth(areaDepth + 1);
+			btn->_setAreaDepth(areaDepth);
 			btn->_setWidgetDepth(widgetDepth);
 
 			Rect2I elemClipRect(tabClipRect.x - offset.x, tabClipRect.y - offset.y, tabClipRect.width, tabClipRect.height);
@@ -296,7 +300,7 @@ namespace BansheeEngine
 			mMinBtn->_setOffset(offset);
 			mMinBtn->_setWidth(minBtnOptimalSize.x);
 			mMinBtn->_setHeight(minBtnOptimalSize.y);
-			mMinBtn->_setAreaDepth(areaDepth + 1);
+			mMinBtn->_setAreaDepth(areaDepth);
 			mMinBtn->_setWidgetDepth(widgetDepth);
 
 			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
@@ -311,7 +315,7 @@ namespace BansheeEngine
 			mCloseBtn->_setOffset(offset);
 			mCloseBtn->_setWidth(closeBtnOptimalSize.x);
 			mCloseBtn->_setHeight(closeBtnOptimalSize.y);
-			mCloseBtn->_setAreaDepth(areaDepth + 1);
+			mCloseBtn->_setAreaDepth(areaDepth);
 			mCloseBtn->_setWidgetDepth(widgetDepth);
 
 			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);

+ 7 - 3
BansheeEditor/Source/BsGUITreeView.cpp

@@ -123,6 +123,9 @@ namespace BansheeEngine
 		mDragHighlight->disableRecursively();
 		mDragSepHighlight->disableRecursively();
 
+		mDragHighlight->_setElementDepth(1);
+		mDragSepHighlight->_setElementDepth(1);
+
 		_registerChildElement(mBackgroundImage);
 		_registerChildElement(mNameEditBox);
 		_registerChildElement(mDragHighlight);
@@ -497,6 +500,7 @@ namespace BansheeEngine
 		if(iterFind == mSelectedElements.end())
 		{
 			GUITexture* background = GUITexture::create(mSelectionBackgroundStyle);
+			background->_setElementDepth(1);
 			_registerChildElement(background);
 
 			element->mIsSelected = true;
@@ -941,7 +945,7 @@ namespace BansheeEngine
 			selectedElem.background->_setOffset(offset);
 			selectedElem.background->_setWidth(width);
 			selectedElem.background->_setHeight(targetElement->_getHeight());
-			selectedElem.background->_setAreaDepth(areaDepth + 1);
+			selectedElem.background->_setAreaDepth(areaDepth);
 			selectedElem.background->_setWidgetDepth(widgetDepth);
 
 			Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
@@ -992,7 +996,7 @@ namespace BansheeEngine
 					mDragHighlight->_setOffset(offset);
 					mDragHighlight->_setWidth(interactableElement->bounds.width);
 					mDragHighlight->_setHeight(interactableElement->bounds.height);
-					mDragHighlight->_setAreaDepth(areaDepth + 1);
+					mDragHighlight->_setAreaDepth(areaDepth);
 					mDragHighlight->_setWidgetDepth(widgetDepth);
 
 					Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
@@ -1010,7 +1014,7 @@ namespace BansheeEngine
 					mDragSepHighlight->_setOffset(offset);
 					mDragSepHighlight->_setWidth(interactableElement->bounds.width);
 					mDragSepHighlight->_setHeight(interactableElement->bounds.height);
-					mDragSepHighlight->_setAreaDepth(areaDepth + 1);
+					mDragSepHighlight->_setAreaDepth(areaDepth);
 					mDragSepHighlight->_setWidgetDepth(widgetDepth);
 
 					Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);

+ 6 - 2
BansheeEngine/BansheeEngine.vcxproj

@@ -236,6 +236,8 @@
     <ClCompile Include="Source\BsCursor.cpp" />
     <ClCompile Include="Source\BsDrawHelper.cpp" />
     <ClCompile Include="Source\BsGUILayoutUtility.cpp" />
+    <ClCompile Include="Source\BsGUIProgressBar.cpp" />
+    <ClCompile Include="Source\BsGUISlider.cpp" />
     <ClCompile Include="Source\BsInputConfiguration.cpp" />
     <ClCompile Include="Source\BsRenderableController.cpp" />
     <ClCompile Include="Source\BsRenderableHandler.cpp" />
@@ -247,6 +249,8 @@
     <ClInclude Include="Include\BsCameraHandlerRTTI.h" />
     <ClInclude Include="Include\BsCursor.h" />
     <ClInclude Include="Include\BsDrawHelper.h" />
+    <ClInclude Include="Include\BsGUIProgressBar.h" />
+    <ClInclude Include="Include\BsGUISlider.h" />
     <ClInclude Include="Include\BsRenderableElement.h" />
     <ClInclude Include="Include\BsRenderableHandler.h" />
     <ClInclude Include="Include\BsRenderableHandlerRTTI.h" />
@@ -285,7 +289,7 @@
     <ClInclude Include="Include\BsGUILayoutY.h" />
     <ClInclude Include="Include\BsGUIMenu.h" />
     <ClInclude Include="Include\BsGUIScrollBar.h" />
-    <ClInclude Include="Include\BsGUIScrollBarHandle.h" />
+    <ClInclude Include="Include\BsGUISliderHandle.h" />
     <ClInclude Include="Include\BsGUIScrollBarHorz.h" />
     <ClInclude Include="Include\BsGUIScrollBarVert.h" />
     <ClInclude Include="Include\BsGUISpace.h" />
@@ -359,7 +363,7 @@
     <ClCompile Include="Source\BsGUIMaterialManager.cpp" />
     <ClCompile Include="Source\BsGUIMouseEvent.cpp" />
     <ClCompile Include="Source\BsGUIScrollBar.cpp" />
-    <ClCompile Include="Source\BsGUIScrollBarHandle.cpp" />
+    <ClCompile Include="Source\BsGUISliderHandle.cpp" />
     <ClCompile Include="Source\BsGUIScrollBarHorz.cpp" />
     <ClCompile Include="Source\BsGUIScrollBarVert.cpp" />
     <ClCompile Include="Source\BsGUISkin.cpp" />

+ 18 - 6
BansheeEngine/BansheeEngine.vcxproj.filters

@@ -149,9 +149,6 @@
     <ClInclude Include="Include\BsGUIScrollBarHorz.h">
       <Filter>Header Files\GUI</Filter>
     </ClInclude>
-    <ClInclude Include="Include\BsGUIScrollBarHandle.h">
-      <Filter>Header Files\GUI</Filter>
-    </ClInclude>
     <ClInclude Include="Include\BsGUIScrollArea.h">
       <Filter>Header Files\GUI</Filter>
     </ClInclude>
@@ -284,6 +281,15 @@
     <ClInclude Include="Include\BsRenderer.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsGUISliderHandle.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsGUISlider.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsGUIProgressBar.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsGUIElement.cpp">
@@ -382,9 +388,6 @@
     <ClCompile Include="Source\BsGUIScrollBarHorz.cpp">
       <Filter>Source Files\GUI</Filter>
     </ClCompile>
-    <ClCompile Include="Source\BsGUIScrollBarHandle.cpp">
-      <Filter>Source Files\GUI</Filter>
-    </ClCompile>
     <ClCompile Include="Source\BsGUIScrollArea.cpp">
       <Filter>Source Files\GUI</Filter>
     </ClCompile>
@@ -487,5 +490,14 @@
     <ClCompile Include="Source\BsRenderer.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsGUISliderHandle.cpp">
+      <Filter>Source Files\GUI</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsGUISlider.cpp">
+      <Filter>Source Files\GUI</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsGUIProgressBar.cpp">
+      <Filter>Source Files\GUI</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 8 - 0
BansheeEngine/Include/BsGUIElement.h

@@ -169,6 +169,14 @@ namespace BansheeEngine
 		 */
 		void _setAreaDepth(UINT16 depth);
 
+/**
+		 * @brief	Set element part of element depth. Less significant than both
+		 *			widget and area depth.
+		 *
+		 * @note	Internal method.
+		 */
+		void _setElementDepth(UINT8 depth);
+
 		/**
 		 * @brief	Sets element position relative to widget origin.
 		 *

+ 84 - 0
BansheeEngine/Include/BsGUIProgressBar.h

@@ -0,0 +1,84 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsGUIElementContainer.h"
+#include "BsEvent.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Contains a background image and a fill image that
+	 *			is scaled depending on the percentage set by the user.
+	 */
+	class BS_EXPORT GUIProgressBar : public GUIElementContainer
+	{
+	public:
+		/**
+		 * Returns type name of the GUI element used for finding GUI element styles. 
+		 */
+		static const String& getGUITypeName();
+
+		/**
+		 * @brief	Name of the style for the fill image used by the progress bar.
+		 */
+		static const String& getBarStyleType();
+
+		/**
+		 * @brief	Name of the style for the background image used by the progress bar.
+		 */
+		static const String& getBackgroundStyleType();
+
+		/**
+		 * @brief	Creates a new progress bar.
+		 *
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUIProgressBar* create(const String& styleName = StringUtil::BLANK);
+
+		/**
+		 * @brief	Creates a new progress bar.
+		 *
+		 * @param	layoutOptions	Options that allows you to control how is the element positioned in
+		 *							GUI layout. This will override any similar options set by style.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUIProgressBar* create(const GUIOptions& layoutOptions, const String& styleName = StringUtil::BLANK);
+
+		/**
+		 * @brief	Fills up the progress bar up to the specified percentage.
+		 *
+		 * @param	pct	How far to extend the fill image, in percent ranging [0.0f, 1.0f]
+		 */
+		void setPercent(float pct);
+
+		/**
+		 * @brief	Gets the percentage of how full is the progress bar currently.
+		 */
+		float getPercent() const { return mPercent; }
+
+		/**
+		 * @copydoc	GUIElementContainer::_getOptimalSize
+		 */
+		virtual Vector2I _getOptimalSize() const;
+
+		Event<void(float percent)> onChanged;
+	protected:
+		GUIProgressBar(const String& styleName, const GUILayoutOptions& layoutOptions);
+
+		/**
+		 * @copydoc	GUIElementContainer::_getOptimalSize
+		 */
+		virtual void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
+			Rect2I clipRect, UINT8 widgetDepth, UINT16 areaDepth);
+
+	private:
+		GUITexture* mBar;
+		GUITexture* mBackground;
+
+		float mPercent;
+	};
+}

+ 1 - 1
BansheeEngine/Include/BsGUIScrollBar.h

@@ -126,7 +126,7 @@ namespace BansheeEngine
 
 		GUIButton* mUpBtn;
 		GUIButton* mDownBtn;
-		GUIScrollBarHandle* mHandleBtn;
+		GUISliderHandle* mHandleBtn;
 		bool mHorizontal;
 
 		static const UINT32 ButtonScrollAmount;

+ 134 - 0
BansheeEngine/Include/BsGUISlider.h

@@ -0,0 +1,134 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsGUIElementContainer.h"
+#include "BsEvent.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	A slider with a draggable handle that can be vertical or horizontal.
+	 */
+	class BS_EXPORT GUISlider : public GUIElementContainer
+	{
+	public:
+		/**
+		 * @brief	Name of the style for the handle button used by the slider.
+		 */
+		static const String& getHandleStyleType();
+
+		/**
+		 * @brief	Name of the style for the background image used by the slider.
+		 */
+		static const String& getBackgroundStyleType();
+
+		/**
+		 * @brief	Moves the slider handle the the specified position in the handle area.
+		 *
+		 * @param	pct	Position to move the handle to, in percent ranging [0.0f, 1.0f]
+		 */
+		void setPercent(float pct);
+
+		/**
+		 * @brief	Gets the current position of the slider handle, in percent ranging [0.0f, 1.0f].
+		 */
+		float getPercent() const;
+
+		/**
+		 * @copydoc	GUIElementContainer::_getOptimalSize
+		 */
+		virtual Vector2I _getOptimalSize() const;
+
+		Event<void(float percent)> onChanged;
+	protected:
+		GUISlider(bool horizontal, const String& styleName, const GUILayoutOptions& layoutOptions);
+		virtual ~GUISlider();
+
+		/**
+		 * @copydoc	GUIElementContainer::_getOptimalSize
+		 */
+		virtual void _updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
+			Rect2I clipRect, UINT8 widgetDepth, UINT16 areaDepth);
+
+		/**
+		 * @brief	Triggered when the slider handles moves.
+		 */
+		void onHandleMoved(float newPosition);
+
+	private:
+		GUISliderHandle* mSliderHandle;
+		GUITexture* mBackground;
+
+		HEvent mHandleMovedConn;
+	};
+
+	/**
+	 * @brief	A horizontal slider with a draggable handle.
+	 */
+	class BS_EXPORT GUISliderHorz : public GUISlider
+	{
+	public:
+		/**
+		 * Returns type name of the GUI element used for finding GUI element styles. 
+		 */
+		static const String& getGUITypeName();
+
+		/**
+		 * @brief	Creates a new horizontal slider.
+		 *
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUISliderHorz* create(const String& styleName = StringUtil::BLANK);
+
+		/**
+		 * @brief	Creates a new horizontal slider.
+		 *
+		 * @param	layoutOptions	Options that allows you to control how is the element positioned in
+		 *							GUI layout. This will override any similar options set by style.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUISliderHorz* create(const GUIOptions& layoutOptions, const String& styleName = StringUtil::BLANK);
+
+	private:
+		GUISliderHorz(const String& styleName, const GUILayoutOptions& layoutOptions);
+	};
+
+	/**
+	 * @brief	A vertical slider with a draggable handle.
+	 */
+	class BS_EXPORT GUISliderVert : public GUISlider
+	{
+	public:
+		/**
+		 * Returns type name of the GUI element used for finding GUI element styles. 
+		 */
+		static const String& getGUITypeName();
+
+		/**
+		 * @brief	Creates a new vertical slider.
+		 *
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUISliderVert* create(const String& styleName = StringUtil::BLANK);
+
+		/**
+		 * @brief	Creates a new vertical slider.
+		 *
+		 * @param	layoutOptions	Options that allows you to control how is the element positioned in
+		 *							GUI layout. This will override any similar options set by style.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUISliderVert* create(const GUIOptions& layoutOptions, const String& styleName = StringUtil::BLANK);
+
+	private:
+		GUISliderVert(const String& styleName, const GUILayoutOptions& layoutOptions);
+	};
+}

+ 148 - 147
BansheeEngine/Include/BsGUIScrollBarHandle.h → BansheeEngine/Include/BsGUISliderHandle.h

@@ -1,148 +1,149 @@
-#pragma once
-
-#include "BsPrerequisites.h"
-#include "BsGUIElement.h"
-#include "BsImageSprite.h"
-#include "BsEvent.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	A draggable handle used in a GUI scroll bar element.
-	 */
-	class BS_EXPORT GUIScrollBarHandle : public GUIElement
-	{
-		/**
-		 * @brief	Visual state of the handle
-		 */
-		enum class State
-		{
-			Normal, Hover, Active
-		};
-
-	public:
-		/**
-		 * Returns type name of the GUI element used for finding GUI element styles. 
-		 */
-		static const String& getGUITypeName();
-
-		/**
-		 * @brief	Creates a new handle.
-		 *
-		 * @param	horizontal		Should the handle be movable vertically or horizontally.
-		 * @param	styleName		Optional style to use for the element. Style will be retrieved
-		 *							from GUISkin of the GUIWidget the element is used on. If not specified
-		 *							default style is used.
-		 */
-		static GUIScrollBarHandle* create(bool horizontal, const String& styleName = StringUtil::BLANK);
-
-		/**
-		 * @brief	Creates a new handle.
-		 *
-		 * @param	horizontal		Should the handle be movable vertically or horizontally.
-		 * @param	layoutOptions	Options that allows you to control how is the element positioned in
-		 *							GUI layout. This will override any similar options set by style.
-		 * @param	styleName		Optional style to use for the element. Style will be retrieved
-		 *							from GUISkin of the GUIWidget the element is used on. If not specified
-		 *							default style is used.
-		 */
-		static GUIScrollBarHandle* create(bool horizontal, const GUIOptions& layoutOptions, 
-			const String& styleName = StringUtil::BLANK);
-
-		/**
-		 * @brief	Size of the handle in pixels, along the handle drag direction.
-		 */
-		void setHandleSize(UINT32 size);
-
-		/**
-		 * @brief	Moves the handle the the specified position in the handle area.
-		 *
-		 * @param	pct	Position to move the handle to, in percent ranging [0.0f, 1.0f]
-		 */
-		void setHandlePos(float pct);
-
-		/**
-		 * @brief	Gets the current position of the handle, in percent ranging [0.0f, 1.0f].
-		 */
-		float getHandlePos() const;
-
-		/**
-		 * @brief	Returns remaining length of the scrollable area not covered by the handle, in pixels.
-		 */
-		UINT32 getScrollableSize() const;
-
-		/**
-		 * @brief	Returns the total length of the area the handle can move in, in pixels.
-		 */
-		UINT32 getMaxSize() const;
-
-		/**
-		 * @copydoc	GUIElement::_getOptimalSize
-		 */
-		virtual Vector2I _getOptimalSize() const;
-
-		Event<void(float newPosition)> onHandleMoved;
-	protected:
-		~GUIScrollBarHandle();
-
-		/**
-		 * @copydoc GUIElement::getNumRenderElements()
-		 */
-		virtual UINT32 getNumRenderElements() const;
-
-		/**
-		 * @copydoc GUIElement::getMaterial()
-		 */
-		virtual const GUIMaterialInfo& getMaterial(UINT32 renderElementIdx) const;
-
-		/**
-		 * @copydoc GUIElement::getNumQuads()
-		 */
-		virtual UINT32 getNumQuads(UINT32 renderElementIdx) const;
-
-		/**
-		 * @copydoc GUIElement::fillBuffer()
-		 */
-		virtual void fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, 
-			UINT32 maxNumQuads, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const;
-
-		/**
-		 * @copydoc GUIElement::updateRenderElementsInternal()
-		 */
-		virtual void updateRenderElementsInternal();
-
-		/**
-		 * @copydoc GUIElement::updateBounds()
-		 */
-		virtual void updateClippedBounds();
-	private:
-		GUIScrollBarHandle(bool horizontal, const String& styleName, const GUILayoutOptions& layoutOptions);
-
-		/**
-		 * @copydoc	GUIElement::mouseEvent
-		 */
-		virtual bool mouseEvent(const GUIMouseEvent& ev);
-
-		/**
-		 * @brief	Checks are the specified over the scroll handle. Coordinates are relative
-		 *			to the parent widget.
-		 */
-		bool isOnHandle(const Vector2I& pos) const;
-
-		/**
-		 * @brief	Gets the currently active texture, depending on handle state.
-		 */
-		const HSpriteTexture& getActiveTexture() const;
-
-		ImageSprite* mImageSprite;
-		UINT32 mHandleSize;
-
-		bool mHorizontal; // Otherwise its vertical
-		float mHandlePos;
-		INT32 mDragStartPos;
-		bool mMouseOverHandle;
-		bool mHandleDragged;
-		State mState;
-
-	};
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsGUIElement.h"
+#include "BsImageSprite.h"
+#include "BsEvent.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	A handle that can be dragged from its predefined minimum and maximum position,
+	 *			either horizontally or vertically.
+	 */
+	class BS_EXPORT GUISliderHandle : public GUIElement
+	{
+		/**
+		 * @brief	Visual state of the handle
+		 */
+		enum class State
+		{
+			Normal, Hover, Active
+		};
+
+	public:
+		/**
+		 * Returns type name of the GUI element used for finding GUI element styles. 
+		 */
+		static const String& getGUITypeName();
+
+		/**
+		 * @brief	Creates a new handle.
+		 *
+		 * @param	horizontal		Should the handle be movable vertically or horizontally.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUISliderHandle* create(bool horizontal, const String& styleName = StringUtil::BLANK);
+
+		/**
+		 * @brief	Creates a new handle.
+		 *
+		 * @param	horizontal		Should the handle be movable vertically or horizontally.
+		 * @param	layoutOptions	Options that allows you to control how is the element positioned in
+		 *							GUI layout. This will override any similar options set by style.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUISliderHandle* create(bool horizontal, const GUIOptions& layoutOptions, 
+			const String& styleName = StringUtil::BLANK);
+
+		/**
+		 * @brief	Size of the handle in pixels, along the handle drag direction.
+		 */
+		void setHandleSize(UINT32 size);
+
+		/**
+		 * @brief	Moves the handle the the specified position in the handle area.
+		 *
+		 * @param	pct	Position to move the handle to, in percent ranging [0.0f, 1.0f]
+		 */
+		void setHandlePos(float pct);
+
+		/**
+		 * @brief	Gets the current position of the handle, in percent ranging [0.0f, 1.0f].
+		 */
+		float getHandlePos() const;
+
+		/**
+		 * @brief	Returns remaining length of the scrollable area not covered by the handle, in pixels.
+		 */
+		UINT32 getScrollableSize() const;
+
+		/**
+		 * @brief	Returns the total length of the area the handle can move in, in pixels.
+		 */
+		UINT32 getMaxSize() const;
+
+		/**
+		 * @copydoc	GUIElement::_getOptimalSize
+		 */
+		virtual Vector2I _getOptimalSize() const;
+
+		Event<void(float newPosition)> onHandleMoved;
+	protected:
+		~GUISliderHandle();
+
+		/**
+		 * @copydoc GUIElement::getNumRenderElements()
+		 */
+		virtual UINT32 getNumRenderElements() const;
+
+		/**
+		 * @copydoc GUIElement::getMaterial()
+		 */
+		virtual const GUIMaterialInfo& getMaterial(UINT32 renderElementIdx) const;
+
+		/**
+		 * @copydoc GUIElement::getNumQuads()
+		 */
+		virtual UINT32 getNumQuads(UINT32 renderElementIdx) const;
+
+		/**
+		 * @copydoc GUIElement::fillBuffer()
+		 */
+		virtual void fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, 
+			UINT32 maxNumQuads, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const;
+
+		/**
+		 * @copydoc GUIElement::updateRenderElementsInternal()
+		 */
+		virtual void updateRenderElementsInternal();
+
+		/**
+		 * @copydoc GUIElement::updateBounds()
+		 */
+		virtual void updateClippedBounds();
+	private:
+		GUISliderHandle(bool horizontal, const String& styleName, const GUILayoutOptions& layoutOptions);
+
+		/**
+		 * @copydoc	GUIElement::mouseEvent
+		 */
+		virtual bool mouseEvent(const GUIMouseEvent& ev);
+
+		/**
+		 * @brief	Checks are the specified over the scroll handle. Coordinates are relative
+		 *			to the parent widget.
+		 */
+		bool isOnHandle(const Vector2I& pos) const;
+
+		/**
+		 * @brief	Gets the currently active texture, depending on handle state.
+		 */
+		const HSpriteTexture& getActiveTexture() const;
+
+		ImageSprite* mImageSprite;
+		UINT32 mHandleSize;
+
+		bool mHorizontal; // Otherwise its vertical
+		float mHandlePos;
+		INT32 mDragStartPos;
+		bool mMouseOverHandle;
+		bool mHandleDragged;
+		State mState;
+
+	};
 }

+ 1 - 1
BansheeEngine/Include/BsPrerequisites.h

@@ -44,7 +44,7 @@ namespace BansheeEngine
 	class GUITexture;
 	class GUIToggle;
 	class GUIInputBox;
-	class GUIScrollBarHandle;
+	class GUISliderHandle;
 	class GUIScrollBarVert;
 	class GUIScrollBarHorz;
 	class GUIScrollArea;

+ 6 - 0
BansheeEngine/Source/BsGUIElement.cpp

@@ -83,6 +83,12 @@ namespace BansheeEngine
 		markMeshAsDirty();
 	}
 
+	void GUIElement::_setElementDepth(UINT8 depth)
+	{
+		mDepth |= depth;
+		markMeshAsDirty();
+	}
+
 	void GUIElement::_setOffset(const Vector2I& offset) 
 	{ 
 		if(mOffset != offset)

+ 4 - 4
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -346,13 +346,13 @@ namespace BansheeEngine
 		Sprite* sprite = renderElemToSprite(renderElementIdx, localRenderElementIdx);
 
 		if(sprite == mImageSprite)
-			return _getDepth();
+			return _getDepth() + 3;
 		else if(sprite == mTextSprite)
-			return _getDepth() - 2;
+			return _getDepth() + 1;
 		else if(sprite == gGUIManager().getInputCaretTool()->getSprite())
-			return _getDepth() - 3;
+			return _getDepth();
 		else // Selection sprites
-			return _getDepth() - 1;
+			return _getDepth() + 2;
 	}
 
 	bool GUIInputBox::_hasCustomCursor(const Vector2I position, CursorType& type) const

+ 98 - 0
BansheeEngine/Source/BsGUIProgressBar.cpp

@@ -0,0 +1,98 @@
+#include "BsGUIProgressBar.h"
+#include "BsGUIWidget.h"
+#include "BsGUISkin.h"
+#include "BsGUITexture.h"
+#include "BsSpriteTexture.h"
+#include "BsGUILayoutOptions.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	GUIProgressBar::GUIProgressBar(const String& styleName, const GUILayoutOptions& layoutOptions)
+		:GUIElementContainer(layoutOptions, styleName), mPercent(0)
+	{
+		mBar = GUITexture::create(getSubStyleName(getBarStyleType()));
+		mBackground = GUITexture::create(getSubStyleName(getBackgroundStyleType()));
+
+		mBackground->_setElementDepth(1);
+
+		_registerChildElement(mBar);
+		_registerChildElement(mBackground);
+	}
+
+	const String& GUIProgressBar::getBarStyleType()
+	{
+		static String HANDLE_STYLE_TYPE = "ProgressBarFill";
+		return HANDLE_STYLE_TYPE;
+	}
+
+	const String& GUIProgressBar::getBackgroundStyleType()
+	{
+		static String BACKGROUND_STYLE_TYPE = "ProgressBarBackground";
+		return BACKGROUND_STYLE_TYPE;
+	}
+
+	Vector2I GUIProgressBar::_getOptimalSize() const
+	{
+		Vector2I optimalSize = mBar->_getOptimalSize();
+
+		Vector2I backgroundSize = mBackground->_getOptimalSize();
+		optimalSize.x = std::max(optimalSize.x, backgroundSize.x);
+		optimalSize.y = std::max(optimalSize.y, backgroundSize.y);
+
+		return optimalSize;
+	}
+
+	void GUIProgressBar::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
+		Rect2I clipRect, UINT8 widgetDepth, UINT16 areaDepth)
+	{
+		Vector2I bgOffset(x, y);
+		Rect2I bgClipRect(clipRect.x - bgOffset.x, clipRect.y - bgOffset.y, clipRect.width, clipRect.height);
+
+		mBackground->_setOffset(bgOffset);
+		mBackground->_setWidth(width);
+		mBackground->_setHeight(height);
+		mBackground->_setAreaDepth(areaDepth);
+		mBackground->_setWidgetDepth(widgetDepth);
+		mBackground->_setClipRect(bgClipRect);
+
+		const GUIElementStyle* style = _getStyle();
+		
+
+		Vector2I barOffset(x + style->margins.left, y + style->margins.top);
+		Rect2I barClipRect(clipRect.x - barOffset.x, clipRect.y - barOffset.y, clipRect.width, clipRect.height);
+
+		UINT32 maxProgressBarWidth = std::max((UINT32)0, (UINT32)(width - style->margins.left - style->margins.right));
+		UINT32 progressBarHeight = std::max((UINT32)0, (UINT32)(height - style->margins.top - style->margins.bottom)); 
+
+		mBar->_setOffset(barOffset);
+		mBar->_setWidth((UINT32)Math::floorToInt(maxProgressBarWidth * mPercent));
+		mBar->_setHeight(progressBarHeight);
+		mBar->_setAreaDepth(areaDepth);
+		mBar->_setWidgetDepth(widgetDepth);
+		mBar->_setClipRect(barClipRect);
+	}
+
+	void GUIProgressBar::setPercent(float pct)
+	{
+		mPercent = pct;
+		markContentAsDirty();
+	}
+
+	GUIProgressBar* GUIProgressBar::create(const String& styleName)
+	{
+		return new (bs_alloc<GUIProgressBar, PoolAlloc>()) GUIProgressBar(getStyleName<GUIProgressBar>(styleName), GUILayoutOptions::create());
+	}
+
+	GUIProgressBar* GUIProgressBar::create(const GUIOptions& layoutOptions, const String& styleName)
+	{
+		return new (bs_alloc<GUIProgressBar, PoolAlloc>()) GUIProgressBar(getStyleName<GUIProgressBar>(styleName), GUILayoutOptions::create(layoutOptions));
+	}
+
+	const String& GUIProgressBar::getGUITypeName()
+	{
+		static String typeName = "ProgressBar";
+		return typeName;
+	}
+}

+ 3 - 3
BansheeEngine/Source/BsGUIScrollBar.cpp

@@ -7,7 +7,7 @@
 #include "BsGUILayout.h"
 #include "BsGUISkin.h"
 #include "BsGUIButton.h"
-#include "BsGUIScrollBarHandle.h"
+#include "BsGUISliderHandle.h"
 #include "BsGUISpace.h"
 #include "BsException.h"
 
@@ -29,7 +29,7 @@ namespace BansheeEngine
 			mUpBtn = GUIButton::create(HString(L""), "ScrollLeftBtn");
 			mDownBtn = GUIButton::create(HString(L""), "ScrollRightBtn");
 
-			mHandleBtn = GUIScrollBarHandle::create(mHorizontal, 
+			mHandleBtn = GUISliderHandle::create(mHorizontal, 
 				GUIOptions(GUIOption::flexibleWidth(), GUIOption::fixedHeight(6)), "ScrollBarHorzBtn");
 		}
 		else
@@ -39,7 +39,7 @@ namespace BansheeEngine
 			mUpBtn = GUIButton::create(HString(L""), "ScrollUpBtn");
 			mDownBtn = GUIButton::create(HString(L""), "ScrollDownBtn");
 
-			mHandleBtn = GUIScrollBarHandle::create(mHorizontal, 
+			mHandleBtn = GUISliderHandle::create(mHorizontal, 
 				GUIOptions(GUIOption::fixedWidth(6), GUIOption::flexibleHeight()), "ScrollBarVertBtn");
 		}
 

+ 1 - 1
BansheeEngine/Source/BsGUIScrollBarHorz.cpp

@@ -6,7 +6,7 @@
 #include "BsGUILayout.h"
 #include "BsGUISkin.h"
 #include "BsGUIButton.h"
-#include "BsGUIScrollBarHandle.h"
+#include "BsGUISliderHandle.h"
 #include "BsGUISpace.h"
 #include "BsException.h"
 

+ 1 - 1
BansheeEngine/Source/BsGUIScrollBarVert.cpp

@@ -6,7 +6,7 @@
 #include "BsGUILayout.h"
 #include "BsGUISkin.h"
 #include "BsGUIButton.h"
-#include "BsGUIScrollBarHandle.h"
+#include "BsGUISliderHandle.h"
 #include "BsGUISpace.h"
 #include "BsException.h"
 

+ 134 - 0
BansheeEngine/Source/BsGUISlider.cpp

@@ -0,0 +1,134 @@
+#include "BsGUISlider.h"
+#include "BsGUIWidget.h"
+#include "BsGUISkin.h"
+#include "BsGUISliderHandle.h"
+#include "BsGUITexture.h"
+#include "BsSpriteTexture.h"
+#include "BsGUILayoutOptions.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	GUISlider::GUISlider(bool horizontal, const String& styleName, const GUILayoutOptions& layoutOptions)
+		:GUIElementContainer(layoutOptions, styleName)
+	{
+		mSliderHandle = GUISliderHandle::create(horizontal, getSubStyleName(getHandleStyleType()));
+		mBackground = GUITexture::create(getSubStyleName(getBackgroundStyleType()));
+
+		mBackground->_setElementDepth(1);
+
+		_registerChildElement(mSliderHandle);
+		_registerChildElement(mBackground);
+
+		mHandleMovedConn = mSliderHandle->onHandleMoved.connect(std::bind(&GUISlider::onHandleMoved, this, _1));
+	}
+
+	GUISlider::~GUISlider()
+	{
+		mHandleMovedConn.disconnect();
+	}
+
+	const String& GUISlider::getHandleStyleType()
+	{
+		static String HANDLE_STYLE_TYPE = "SliderHandle";
+		return HANDLE_STYLE_TYPE;
+	}
+
+	const String& GUISlider::getBackgroundStyleType()
+	{
+		static String BACKGROUND_STYLE_TYPE = "SliderBackground";
+		return BACKGROUND_STYLE_TYPE;
+	}
+
+	Vector2I GUISlider::_getOptimalSize() const
+	{
+		Vector2I optimalSize = mSliderHandle->_getOptimalSize();
+
+		Vector2I backgroundSize = mBackground->_getOptimalSize();
+		optimalSize.x = std::max(optimalSize.x, backgroundSize.x);
+		optimalSize.y = std::max(optimalSize.y, backgroundSize.y);
+
+		return optimalSize;
+	}
+
+	void GUISlider::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
+		Rect2I clipRect, UINT8 widgetDepth, UINT16 areaDepth)
+	{
+		Vector2I offset(x, y);
+		Rect2I elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
+
+		mBackground->_setOffset(offset);
+		mBackground->_setWidth(width);
+		mBackground->_setHeight(height);
+		mBackground->_setAreaDepth(areaDepth);
+		mBackground->_setWidgetDepth(widgetDepth);
+		mBackground->_setClipRect(elemClipRect);
+
+		mSliderHandle->_setOffset(offset);
+		mSliderHandle->_setWidth(width);
+		mSliderHandle->_setHeight(height);
+		mSliderHandle->_setAreaDepth(areaDepth);
+		mSliderHandle->_setWidgetDepth(widgetDepth);
+		mSliderHandle->_setClipRect(elemClipRect);
+	}
+
+	void GUISlider::setPercent(float pct)
+	{
+		mSliderHandle->setHandlePos(pct);
+	}
+
+	float GUISlider::getPercent() const
+	{
+		return mSliderHandle->getHandlePos();
+	}
+
+	void GUISlider::onHandleMoved(float newPosition)
+	{
+		onChanged(newPosition);
+	}
+
+	GUISliderHorz::GUISliderHorz(const String& styleName, const GUILayoutOptions& layoutOptions)
+		:GUISlider(true, styleName, layoutOptions)
+	{
+
+	}
+
+	GUISliderHorz* GUISliderHorz::create(const String& styleName)
+	{
+		return new (bs_alloc<GUISliderHorz, PoolAlloc>()) GUISliderHorz(getStyleName<GUISliderHorz>(styleName), GUILayoutOptions::create());
+	}
+
+	GUISliderHorz* GUISliderHorz::create(const GUIOptions& layoutOptions, const String& styleName)
+	{
+		return new (bs_alloc<GUISliderHorz, PoolAlloc>()) GUISliderHorz(getStyleName<GUISliderHorz>(styleName), GUILayoutOptions::create(layoutOptions));
+	}
+
+	const String& GUISliderHorz::getGUITypeName()
+	{
+		static String typeName = "SliderHorz";
+		return typeName;
+	}
+
+	GUISliderVert::GUISliderVert(const String& styleName, const GUILayoutOptions& layoutOptions)
+		:GUISlider(false, styleName, layoutOptions)
+	{
+
+	}
+
+	GUISliderVert* GUISliderVert::create(const String& styleName)
+	{
+		return new (bs_alloc<GUISliderVert, PoolAlloc>()) GUISliderVert(getStyleName<GUISliderVert>(styleName), GUILayoutOptions::create());
+	}
+
+	GUISliderVert* GUISliderVert::create(const GUIOptions& layoutOptions, const String& styleName)
+	{
+		return new (bs_alloc<GUISliderVert, PoolAlloc>()) GUISliderVert(getStyleName<GUISliderVert>(styleName), GUILayoutOptions::create(layoutOptions));
+	}
+
+	const String& GUISliderVert::getGUITypeName()
+	{
+		static String typeName = "SliderVert";
+		return typeName;
+	}
+}

+ 349 - 343
BansheeEngine/Source/BsGUIScrollBarHandle.cpp → BansheeEngine/Source/BsGUISliderHandle.cpp

@@ -1,344 +1,350 @@
-#include "BsGUIScrollBarHandle.h"
-#include "BsImageSprite.h"
-#include "BsGUIWidget.h"
-#include "BsGUISkin.h"
-#include "BsSpriteTexture.h"
-#include "BsTextSprite.h"
-#include "BsGUILayoutOptions.h"
-#include "BsGUIMouseEvent.h"
-#include "BsDebug.h"
-#include "BsTexture.h"
-
-namespace BansheeEngine
-{
-	const String& GUIScrollBarHandle::getGUITypeName()
-	{
-		static String name = "ScrollBarHandle";
-		return name;
-	}
-
-	GUIScrollBarHandle::GUIScrollBarHandle(bool horizontal, const String& styleName, const GUILayoutOptions& layoutOptions)
-		:GUIElement(styleName, layoutOptions), mHorizontal(horizontal), mHandleSize(2), mMouseOverHandle(false), mHandlePos(0), mDragStartPos(0),
-		mHandleDragged(false), mState(State::Normal)
-	{
-		mImageSprite = bs_new<ImageSprite, PoolAlloc>();
-	}
-
-	GUIScrollBarHandle::~GUIScrollBarHandle()
-	{
-		bs_delete<PoolAlloc>(mImageSprite);
-	}
-
-	GUIScrollBarHandle* GUIScrollBarHandle::create(bool horizontal, const String& styleName)
-	{
-		return new (bs_alloc<GUIScrollBarHandle, PoolAlloc>()) GUIScrollBarHandle(horizontal, getStyleName<GUIScrollBarHandle>(styleName), GUILayoutOptions::create());
-	}
-
-	GUIScrollBarHandle* GUIScrollBarHandle::create(bool horizontal, const GUIOptions& layoutOptions, const String& styleName)
-	{
-		return new (bs_alloc<GUIScrollBarHandle, PoolAlloc>()) GUIScrollBarHandle(horizontal, getStyleName<GUIScrollBarHandle>(styleName), GUILayoutOptions::create(layoutOptions));
-	}
-
-	void GUIScrollBarHandle::setHandleSize(UINT32 size)
-	{
-		mHandleSize = std::min(getMaxSize(), size);
-		markContentAsDirty();
-	}
-
-	void GUIScrollBarHandle::setHandlePos(float pct)
-	{
-		pct = Math::clamp01(pct);
-
-		UINT32 maxScrollAmount = getMaxSize() - mHandleSize;
-		mHandlePos = pct * maxScrollAmount;
-
-		markContentAsDirty();
-	}
-
-	float GUIScrollBarHandle::getHandlePos() const
-	{
-		UINT32 maxScrollAmount = getMaxSize() - mHandleSize;
-
-		if(maxScrollAmount > 0.0f)
-			return mHandlePos / maxScrollAmount;
-		else
-			return 0.0f;
-	}
-
-	UINT32 GUIScrollBarHandle::getScrollableSize() const
-	{
-		return getMaxSize() - mHandleSize;
-	}
-
-	UINT32 GUIScrollBarHandle::getNumRenderElements() const
-	{
-		return mImageSprite->getNumRenderElements();
-	}
-
-	const GUIMaterialInfo& GUIScrollBarHandle::getMaterial(UINT32 renderElementIdx) const
-	{
-		return mImageSprite->getMaterial(renderElementIdx);
-	}
-
-	UINT32 GUIScrollBarHandle::getNumQuads(UINT32 renderElementIdx) const
-	{
-		return mImageSprite->getNumQuads(renderElementIdx);
-	}
-
-	void GUIScrollBarHandle::updateRenderElementsInternal()
-	{		
-		IMAGE_SPRITE_DESC desc;
-
-		HSpriteTexture activeTex = getActiveTexture();
-		if(SpriteTexture::checkIsLoaded(activeTex))
-			desc.texture = activeTex.getInternalPtr();
-
-		if(mHorizontal)
-		{
-			desc.width = mHandleSize;
-			desc.height = mHeight;
-		}
-		else
-		{
-			desc.width = mWidth;
-			desc.height = mHandleSize;
-		}
-
-		mImageSprite->update(desc, (UINT64)_getParentWidget());
-		
-		GUIElement::updateRenderElementsInternal();
-	}
-
-	void GUIScrollBarHandle::updateClippedBounds()
-	{
-		mClippedBounds = Rect2I(mOffset.x, mOffset.y, mWidth, mHeight);
-
-		Rect2I localClipRect(mClipRect.x + mOffset.x, mClipRect.y + mOffset.y, mClipRect.width, mClipRect.height);
-		mClippedBounds.clip(localClipRect);
-	}
-
-	Vector2I GUIScrollBarHandle::_getOptimalSize() const
-	{
-		HSpriteTexture activeTex = getActiveTexture();
-
-		if(SpriteTexture::checkIsLoaded(activeTex))
-			return Vector2I(activeTex->getWidth(), activeTex->getHeight());
-
-		return Vector2I();
-	}
-
-	void GUIScrollBarHandle::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
-		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
-	{
-		Vector2I offset = mOffset;
-		if(mHorizontal)
-			offset.x += Math::floorToInt(mHandlePos);
-		else
-			offset.y += Math::floorToInt(mHandlePos);
-
-		Rect2I clipRect = mClipRect;
-		if(mHorizontal)
-			clipRect.x -= Math::floorToInt(mHandlePos);
-		else
-			clipRect.y -= Math::floorToInt(mHandlePos);
-
-		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, 
-			vertexStride, indexStride, renderElementIdx, offset, clipRect);
-	}
-
-	bool GUIScrollBarHandle::mouseEvent(const GUIMouseEvent& ev)
-	{
-		if(ev.getType() == GUIMouseEventType::MouseMove)
-		{
-			if(mMouseOverHandle)
-			{
-				if(!isOnHandle(ev.getPosition()))
-				{
-					mMouseOverHandle = false;
-
-					mState = State::Normal;
-					markContentAsDirty();
-
-					return true;
-				}
-			}
-			else
-			{
-				if(isOnHandle(ev.getPosition()))
-				{
-					mMouseOverHandle = true;
-
-					mState = State::Hover;
-					markContentAsDirty();
-
-					return true;
-				}
-			}
-		}
-
-		if(ev.getType() == GUIMouseEventType::MouseDown && mMouseOverHandle)
-		{
-			mState = State::Active;
-			markContentAsDirty();
-
-			if(mHorizontal)
-			{
-				INT32 left = (INT32)mOffset.x + Math::floorToInt(mHandlePos);
-				mDragStartPos = ev.getPosition().x - left;
-			}
-			else
-			{
-				INT32 top = (INT32)mOffset.y + Math::floorToInt(mHandlePos);
-				mDragStartPos = ev.getPosition().y - top;
-			}
-
-			mHandleDragged = true;
-			return true;
-		}
-
-		if(ev.getType() == GUIMouseEventType::MouseDrag && mHandleDragged)
-		{
-			if(mHorizontal)
-			{
-				mHandlePos = (float)(ev.getPosition().x - mDragStartPos - mOffset.x);
-			}
-			else
-			{
-				mHandlePos = float(ev.getPosition().y - mDragStartPos - mOffset.y);
-			}
-
-			float maxScrollAmount = (float)getMaxSize() - mHandleSize;
-			mHandlePos = Math::clamp(mHandlePos, 0.0f, maxScrollAmount);
-
-			if(!onHandleMoved.empty())
-			{
-				float pct = 0.0f;
-				if(maxScrollAmount > 0.0f)
-					pct = mHandlePos / maxScrollAmount;
-				
-				onHandleMoved(pct);
-			}
-
-			markContentAsDirty();
-			return true;
-		}
-
-		if(ev.getType() == GUIMouseEventType::MouseOut && !mHandleDragged)
-		{
-			mState = State::Normal;
-			mMouseOverHandle = false;
-			markContentAsDirty();
-
-			return true;
-		}
-
-		if(ev.getType() == GUIMouseEventType::MouseUp)
-		{
-			if(mMouseOverHandle)
-				mState = State::Hover;
-			else
-				mState = State::Normal;
-
-			// If we clicked above or below the scroll handle, scroll by one page
-			INT32 handleOffset = 0;
-			if(mHorizontal)
-			{
-				INT32 handleLeft = (INT32)mOffset.x + Math::floorToInt(mHandlePos);
-				INT32 handleRight = handleLeft + mHandleSize;
-
-				if(ev.getPosition().x < handleLeft)
-					handleOffset -= mHandleSize;
-				else if(ev.getPosition().x > handleRight)
-					handleOffset += mHandleSize;
-			}
-			else
-			{
-				INT32 handleTop = (INT32)mOffset.y + Math::floorToInt(mHandlePos);
-				INT32 handleBottom = handleTop + mHandleSize;
-
-				if(ev.getPosition().y < handleTop)
-					handleOffset -= mHandleSize;
-				else if(ev.getPosition().y > handleBottom)
-					handleOffset += mHandleSize;
-			}
-
-			mHandlePos += handleOffset;
-			float maxScrollAmount = (float)getMaxSize() - mHandleSize;
-			mHandlePos = Math::clamp(mHandlePos, 0.0f, maxScrollAmount);
-
-			if(!onHandleMoved.empty())
-			{
-				float pct = 0.0f;
-				
-				if(maxScrollAmount > 0.0f)
-					pct = (float)mHandlePos / maxScrollAmount;
-
-				onHandleMoved(pct);
-			}
-
-			markContentAsDirty();
-			return true;
-		}
-
-		if(ev.getType() == GUIMouseEventType::MouseDragEnd)
-		{
-			mHandleDragged = false;
-
-			if(mMouseOverHandle)
-				mState = State::Hover;
-			else
-				mState = State::Normal;
-
-			markContentAsDirty();
-			return true;
-		}
-		
-		return false;
-	}
-
-	bool GUIScrollBarHandle::isOnHandle(const Vector2I& pos) const
-	{
-		if(mHorizontal)
-		{
-			INT32 left = (INT32)mOffset.x + Math::floorToInt(mHandlePos);
-			INT32 right = left + mHandleSize;
-
-			if(pos.x >= left && pos.x < right)
-				return true;
-		}
-		else
-		{
-			INT32 top = (INT32)mOffset.y + Math::floorToInt(mHandlePos);
-			INT32 bottom = top + mHandleSize;
-
-			if(pos.y >= top && pos.y < bottom)
-				return true;
-		}
-		
-		return false;
-	}
-
-	UINT32 GUIScrollBarHandle::getMaxSize() const
-	{
-		UINT32 maxSize = mHeight;
-		if(mHorizontal)
-			maxSize = mWidth;
-
-		return maxSize;
-	}
-
-	const HSpriteTexture& GUIScrollBarHandle::getActiveTexture() const
-	{
-		switch(mState)
-		{
-		case State::Active:
-			return _getStyle()->active.texture;
-		case State::Hover:
-			return _getStyle()->hover.texture;
-		case State::Normal:
-			return _getStyle()->normal.texture;
-		}
-
-		return _getStyle()->normal.texture;
-	}
+#include "BsGUISliderHandle.h"
+#include "BsImageSprite.h"
+#include "BsGUIWidget.h"
+#include "BsGUISkin.h"
+#include "BsSpriteTexture.h"
+#include "BsTextSprite.h"
+#include "BsGUILayoutOptions.h"
+#include "BsGUIMouseEvent.h"
+#include "BsDebug.h"
+#include "BsTexture.h"
+
+namespace BansheeEngine
+{
+	const String& GUISliderHandle::getGUITypeName()
+	{
+		static String name = "SliderHandle";
+		return name;
+	}
+
+	GUISliderHandle::GUISliderHandle(bool horizontal, const String& styleName, const GUILayoutOptions& layoutOptions)
+		:GUIElement(styleName, layoutOptions), mHorizontal(horizontal), mHandleSize(0), mMouseOverHandle(false), mHandlePos(0), mDragStartPos(0),
+		mHandleDragged(false), mState(State::Normal)
+	{
+		mImageSprite = bs_new<ImageSprite, PoolAlloc>();
+	}
+
+	GUISliderHandle::~GUISliderHandle()
+	{
+		bs_delete<PoolAlloc>(mImageSprite);
+	}
+
+	GUISliderHandle* GUISliderHandle::create(bool horizontal, const String& styleName)
+	{
+		return new (bs_alloc<GUISliderHandle, PoolAlloc>()) GUISliderHandle(horizontal, getStyleName<GUISliderHandle>(styleName), GUILayoutOptions::create());
+	}
+
+	GUISliderHandle* GUISliderHandle::create(bool horizontal, const GUIOptions& layoutOptions, const String& styleName)
+	{
+		return new (bs_alloc<GUISliderHandle, PoolAlloc>()) GUISliderHandle(horizontal, getStyleName<GUISliderHandle>(styleName), GUILayoutOptions::create(layoutOptions));
+	}
+
+	void GUISliderHandle::setHandleSize(UINT32 size)
+	{
+		mHandleSize = std::min(getMaxSize(), size);
+		markContentAsDirty();
+	}
+
+	void GUISliderHandle::setHandlePos(float pct)
+	{
+		pct = Math::clamp01(pct);
+
+		UINT32 maxScrollAmount = getMaxSize() - mHandleSize;
+		mHandlePos = pct * maxScrollAmount;
+
+		markContentAsDirty();
+	}
+
+	float GUISliderHandle::getHandlePos() const
+	{
+		UINT32 maxScrollAmount = getMaxSize() - mHandleSize;
+
+		if(maxScrollAmount > 0.0f)
+			return mHandlePos / maxScrollAmount;
+		else
+			return 0.0f;
+	}
+
+	UINT32 GUISliderHandle::getScrollableSize() const
+	{
+		return getMaxSize() - mHandleSize;
+	}
+
+	UINT32 GUISliderHandle::getNumRenderElements() const
+	{
+		return mImageSprite->getNumRenderElements();
+	}
+
+	const GUIMaterialInfo& GUISliderHandle::getMaterial(UINT32 renderElementIdx) const
+	{
+		return mImageSprite->getMaterial(renderElementIdx);
+	}
+
+	UINT32 GUISliderHandle::getNumQuads(UINT32 renderElementIdx) const
+	{
+		return mImageSprite->getNumQuads(renderElementIdx);
+	}
+
+	void GUISliderHandle::updateRenderElementsInternal()
+	{		
+		IMAGE_SPRITE_DESC desc;
+
+		HSpriteTexture activeTex = getActiveTexture();
+		if(SpriteTexture::checkIsLoaded(activeTex))
+			desc.texture = activeTex.getInternalPtr();
+
+		if (mHorizontal)
+		{
+			if (mHandleSize == 0 && desc.texture != nullptr)
+				mHandleSize = desc.texture->getWidth();
+
+			desc.width = mHandleSize;
+			desc.height = mHeight;
+		}
+		else
+		{
+			if (mHandleSize == 0 && desc.texture != nullptr)
+				mHandleSize = desc.texture->getHeight();
+
+			desc.width = mWidth;
+			desc.height = mHandleSize;
+		}
+
+		mImageSprite->update(desc, (UINT64)_getParentWidget());
+		
+		GUIElement::updateRenderElementsInternal();
+	}
+
+	void GUISliderHandle::updateClippedBounds()
+	{
+		mClippedBounds = Rect2I(mOffset.x, mOffset.y, mWidth, mHeight);
+
+		Rect2I localClipRect(mClipRect.x + mOffset.x, mClipRect.y + mOffset.y, mClipRect.width, mClipRect.height);
+		mClippedBounds.clip(localClipRect);
+	}
+
+	Vector2I GUISliderHandle::_getOptimalSize() const
+	{
+		HSpriteTexture activeTex = getActiveTexture();
+
+		if(SpriteTexture::checkIsLoaded(activeTex))
+			return Vector2I(activeTex->getWidth(), activeTex->getHeight());
+
+		return Vector2I();
+	}
+
+	void GUISliderHandle::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
+		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
+	{
+		Vector2I offset = mOffset;
+		if(mHorizontal)
+			offset.x += Math::floorToInt(mHandlePos);
+		else
+			offset.y += Math::floorToInt(mHandlePos);
+
+		Rect2I clipRect = mClipRect;
+		if(mHorizontal)
+			clipRect.x -= Math::floorToInt(mHandlePos);
+		else
+			clipRect.y -= Math::floorToInt(mHandlePos);
+
+		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, 
+			vertexStride, indexStride, renderElementIdx, offset, clipRect);
+	}
+
+	bool GUISliderHandle::mouseEvent(const GUIMouseEvent& ev)
+	{
+		if(ev.getType() == GUIMouseEventType::MouseMove)
+		{
+			if(mMouseOverHandle)
+			{
+				if(!isOnHandle(ev.getPosition()))
+				{
+					mMouseOverHandle = false;
+
+					mState = State::Normal;
+					markContentAsDirty();
+
+					return true;
+				}
+			}
+			else
+			{
+				if(isOnHandle(ev.getPosition()))
+				{
+					mMouseOverHandle = true;
+
+					mState = State::Hover;
+					markContentAsDirty();
+
+					return true;
+				}
+			}
+		}
+
+		if(ev.getType() == GUIMouseEventType::MouseDown && mMouseOverHandle)
+		{
+			mState = State::Active;
+			markContentAsDirty();
+
+			if(mHorizontal)
+			{
+				INT32 left = (INT32)mOffset.x + Math::floorToInt(mHandlePos);
+				mDragStartPos = ev.getPosition().x - left;
+			}
+			else
+			{
+				INT32 top = (INT32)mOffset.y + Math::floorToInt(mHandlePos);
+				mDragStartPos = ev.getPosition().y - top;
+			}
+
+			mHandleDragged = true;
+			return true;
+		}
+
+		if(ev.getType() == GUIMouseEventType::MouseDrag && mHandleDragged)
+		{
+			if(mHorizontal)
+			{
+				mHandlePos = (float)(ev.getPosition().x - mDragStartPos - mOffset.x);
+			}
+			else
+			{
+				mHandlePos = float(ev.getPosition().y - mDragStartPos - mOffset.y);
+			}
+
+			float maxScrollAmount = (float)getMaxSize() - mHandleSize;
+			mHandlePos = Math::clamp(mHandlePos, 0.0f, maxScrollAmount);
+
+			if(!onHandleMoved.empty())
+			{
+				float pct = 0.0f;
+				if(maxScrollAmount > 0.0f)
+					pct = mHandlePos / maxScrollAmount;
+				
+				onHandleMoved(pct);
+			}
+
+			markContentAsDirty();
+			return true;
+		}
+
+		if(ev.getType() == GUIMouseEventType::MouseOut && !mHandleDragged)
+		{
+			mState = State::Normal;
+			mMouseOverHandle = false;
+			markContentAsDirty();
+
+			return true;
+		}
+
+		if(ev.getType() == GUIMouseEventType::MouseUp)
+		{
+			if(mMouseOverHandle)
+				mState = State::Hover;
+			else
+				mState = State::Normal;
+
+			// If we clicked above or below the scroll handle, scroll by one page
+			INT32 handleOffset = 0;
+			if(mHorizontal)
+			{
+				INT32 handleLeft = (INT32)mOffset.x + Math::floorToInt(mHandlePos);
+				INT32 handleRight = handleLeft + mHandleSize;
+
+				if(ev.getPosition().x < handleLeft)
+					handleOffset -= mHandleSize;
+				else if(ev.getPosition().x > handleRight)
+					handleOffset += mHandleSize;
+			}
+			else
+			{
+				INT32 handleTop = (INT32)mOffset.y + Math::floorToInt(mHandlePos);
+				INT32 handleBottom = handleTop + mHandleSize;
+
+				if(ev.getPosition().y < handleTop)
+					handleOffset -= mHandleSize;
+				else if(ev.getPosition().y > handleBottom)
+					handleOffset += mHandleSize;
+			}
+
+			mHandlePos += handleOffset;
+			float maxScrollAmount = (float)getMaxSize() - mHandleSize;
+			mHandlePos = Math::clamp(mHandlePos, 0.0f, maxScrollAmount);
+
+			if(!onHandleMoved.empty())
+			{
+				float pct = 0.0f;
+				
+				if(maxScrollAmount > 0.0f)
+					pct = (float)mHandlePos / maxScrollAmount;
+
+				onHandleMoved(pct);
+			}
+
+			markContentAsDirty();
+			return true;
+		}
+
+		if(ev.getType() == GUIMouseEventType::MouseDragEnd)
+		{
+			mHandleDragged = false;
+
+			if(mMouseOverHandle)
+				mState = State::Hover;
+			else
+				mState = State::Normal;
+
+			markContentAsDirty();
+			return true;
+		}
+		
+		return false;
+	}
+
+	bool GUISliderHandle::isOnHandle(const Vector2I& pos) const
+	{
+		if(mHorizontal)
+		{
+			INT32 left = (INT32)mOffset.x + Math::floorToInt(mHandlePos);
+			INT32 right = left + mHandleSize;
+
+			if(pos.x >= left && pos.x < right)
+				return true;
+		}
+		else
+		{
+			INT32 top = (INT32)mOffset.y + Math::floorToInt(mHandlePos);
+			INT32 bottom = top + mHandleSize;
+
+			if(pos.y >= top && pos.y < bottom)
+				return true;
+		}
+		
+		return false;
+	}
+
+	UINT32 GUISliderHandle::getMaxSize() const
+	{
+		UINT32 maxSize = mHeight;
+		if(mHorizontal)
+			maxSize = mWidth;
+
+		return maxSize;
+	}
+
+	const HSpriteTexture& GUISliderHandle::getActiveTexture() const
+	{
+		switch(mState)
+		{
+		case State::Active:
+			return _getStyle()->active.texture;
+		case State::Hover:
+			return _getStyle()->hover.texture;
+		case State::Normal:
+			return _getStyle()->normal.texture;
+		}
+
+		return _getStyle()->normal.texture;
+	}
 }

+ 19 - 0
TODO.txt

@@ -5,6 +5,23 @@
 When serializing Camera I cannot save the reference to RenderTexture. Make it a Resource?
 Possibly set up automatic refresh in debug mode after initialization? As an ad-hoc unit test
 
+<<<<<Simple stuff>>>>>>
+
+ColorPicker
+ - Add slider GUI control if I don't have it already. It should be separate from the background image control.
+ - Make sure I can set GUI area depth from C# (and think about how to do it neatly - probably just limit to to -128 - 127)
+
+Test file/folder open/save dialog
+
+Make sure that GUIArea depth works in C#
+
+Add a simple way to create modal dialogs (ModalDialog in C#, similar to EditorWindow)
+
+TODO: Progress bar/slider:
+ - Add proper GUI styles for them
+ - Test them
+ - Add C# wrappers for them
+
 <<<<<<Handles>>>>>>>>
 
 When scaling using center make sure to offset the object before scale
@@ -46,6 +63,8 @@ Add ProjectWindow and HierarchyWindow to C#
 Set up a default layout and save it
 
 Need a way to drag and drop items from Scene tree view to Scene view
+ - When dragging a mesh it should by default create a SceneObject with a renderable
+ - I might want a C# DragAndDrop class? It can contain Resource or SceneObject only for now, similar to Selection
 
 AFTER I have scene widget in C#:
  - Test custom handles from C#