Prechádzať zdrojové kódy

Added support for scrollbars with resize handles

BearishSun 9 rokov pred
rodič
commit
c21864b903

+ 11 - 12
Source/BansheeEngine/Include/BsGUIScrollBar.h

@@ -25,9 +25,6 @@ namespace BansheeEngine
 		 */
 		 */
 		void scroll(float amount);
 		void scroll(float amount);
 
 
-		/**	Returns the maximum size of the scroll handle, in pixels. */
-		UINT32 getMaxHandleSize() const;
-
 		/**	Returns the maximum scrollable size the handle can move within (for example scroll bar length). */
 		/**	Returns the maximum scrollable size the handle can move within (for example scroll bar length). */
 		UINT32 getScrollableSize() const;
 		UINT32 getScrollableSize() const;
 
 
@@ -35,10 +32,10 @@ namespace BansheeEngine
 		void setTint(const Color& color) override;
 		void setTint(const Color& color) override;
 
 
 		/**
 		/**
-		 * Triggered whenever the scrollbar handle is moved. Value provided is the handle position in percent 
-		 * (ranging [0, 1]).
+		 * Triggered whenever the scrollbar handle is moved or resized. Values provided are the handle position and size 
+		 * in percent (ranging [0, 1]).
 		 */
 		 */
-		Event<void(float newPosition)> onScrollPositionChanged;
+		Event<void(float posPct, float sizePct)> onScrollOrResize;
 
 
 	public: // ***** INTERNAL ******
 	public: // ***** INTERNAL ******
 		/** @name Internal
 		/** @name Internal
@@ -46,11 +43,11 @@ namespace BansheeEngine
 		 */
 		 */
 
 
 		/**
 		/**
-		 * Sets the size of the handle in pixels.
+		 * Sets the size of the handle in percent (ranging [0, 1]) of the total scroll bar area.
 		 *
 		 *
 		 * @note	Does not trigger layout update.
 		 * @note	Does not trigger layout update.
 		 */
 		 */
-		void _setHandleSize(UINT32 size);
+		void _setHandleSize(float pct);
 
 
 		/**
 		/**
 		 * Sets the position of the scroll handle in percent (ranging [0, 1]).
 		 * Sets the position of the scroll handle in percent (ranging [0, 1]).
@@ -69,11 +66,13 @@ namespace BansheeEngine
 		 *
 		 *
 		 * @param[in]	horizontal	If true the scroll bar will have a horizontal moving handle, otherwise it will be a
 		 * @param[in]	horizontal	If true the scroll bar will have a horizontal moving handle, otherwise it will be a
 		 *							vertical one.
 		 *							vertical one.
+		 * @param[in]	resizable	If true the scrollbar will have additional handles that allow the scroll handle to be
+		 *							resized. This allows you to adjust the size of the visible scroll area.
 		 * @param[in]	styleName	Optional style to use for the element. Style will be retrieved from GUISkin of the
 		 * @param[in]	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.
 		 *							GUIWidget the element is used on. If not specified default style is used.
 		 * @param[in]	dimensions	Determines valid dimensions (size) of the element.
 		 * @param[in]	dimensions	Determines valid dimensions (size) of the element.
 		 */
 		 */
-		GUIScrollBar(bool horizontal, const String& styleName, const GUIDimensions& dimensions);
+		GUIScrollBar(bool horizontal, bool resizable, const String& styleName, const GUIDimensions& dimensions);
 		virtual ~GUIScrollBar();
 		virtual ~GUIScrollBar();
 
 
 		/** @copydoc GUIElement::_getNumRenderElements */
 		/** @copydoc GUIElement::_getNumRenderElements */
@@ -102,10 +101,10 @@ namespace BansheeEngine
 		UINT32 _getRenderElementDepthRange() const override;
 		UINT32 _getRenderElementDepthRange() const override;
 	private:
 	private:
 		/**
 		/**
-		 * Triggered whenever the scroll handle moves. Provided value represents the new position of the handle in percent
-		 * (ranging [0, 1]).
+		 * Triggered whenever the scroll handle moves. Provided value represents the new position and size of the handle 
+		 * in percent (ranging [0, 1]).
 		 */
 		 */
-		void handleMoved(float handlePct);
+		void handleMoved(float handlePct, float sizePct);
 
 
 		/**	Triggered when scroll up button is clicked. */
 		/**	Triggered when scroll up button is clicked. */
 		void upButtonClicked();
 		void upButtonClicked();

+ 24 - 1
Source/BansheeEngine/Include/BsGUIScrollBarHorz.h

@@ -26,6 +26,16 @@ namespace BansheeEngine
 		 */
 		 */
 		static GUIScrollBarHorz* create(const String& styleName = StringUtil::BLANK);
 		static GUIScrollBarHorz* create(const String& styleName = StringUtil::BLANK);
 
 
+		/**
+		 * Creates a new horizontal scroll bar.
+		 *
+		 * @param[in]	resizeable		If true the scrollbar will have additional handles that allow the scroll handle to
+		 *								be resized. This allows you to adjust the size of the visible scroll area.
+		 * @param[in]	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 GUIScrollBarHorz* create(bool resizeable, const String& styleName = StringUtil::BLANK);
+
 		/**
 		/**
 		 * Creates a new horizontal scroll bar.
 		 * Creates a new horizontal scroll bar.
 		 *
 		 *
@@ -35,8 +45,21 @@ namespace BansheeEngine
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 */
 		 */
 		static GUIScrollBarHorz* create(const GUIOptions& options, const String& styleName = StringUtil::BLANK);
 		static GUIScrollBarHorz* create(const GUIOptions& options, const String& styleName = StringUtil::BLANK);
+
+		/**
+		 * Creates a new horizontal scroll bar.
+		 *
+		 * @param[in]	resizeable		If true the scrollbar will have additional handles that allow the scroll handle to
+		 *								be resized. This allows you to adjust the size of the visible scroll area.
+		 * @param[in]	options			Options that allow you to control how is the element positioned and sized.
+		 *								This will override any similar options set by style.
+		 * @param[in]	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 GUIScrollBarHorz* create(bool resizeable, const GUIOptions& options, 
+			const String& styleName = StringUtil::BLANK);
 	protected:
 	protected:
-		GUIScrollBarHorz(const String& styleName, const GUIDimensions& dimensions);
+		GUIScrollBarHorz(bool resizeable, const String& styleName, const GUIDimensions& dimensions);
 		~GUIScrollBarHorz();
 		~GUIScrollBarHorz();
 	};
 	};
 
 

+ 23 - 2
Source/BansheeEngine/Include/BsGUIScrollBarVert.h

@@ -4,7 +4,6 @@
 
 
 #include "BsPrerequisites.h"
 #include "BsPrerequisites.h"
 #include "BsGUIScrollBar.h"
 #include "BsGUIScrollBar.h"
-#include "BsEvent.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
@@ -27,6 +26,16 @@ namespace BansheeEngine
 		 */
 		 */
 		static GUIScrollBarVert* create(const String& styleName = StringUtil::BLANK);
 		static GUIScrollBarVert* create(const String& styleName = StringUtil::BLANK);
 
 
+		/**
+		 * Creates a new vertical scroll bar.
+		 *
+		 * @param[in]	resizeable		If true the scrollbar will have additional handles that allow the scroll handle to
+		 *								be resized. This allows you to adjust the size of the visible scroll area.
+		 * @param[in]	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 GUIScrollBarVert* create(bool resizable, const String& styleName = StringUtil::BLANK);
+
 		/**
 		/**
 		 * Creates a new vertical scroll bar.
 		 * Creates a new vertical scroll bar.
 		 *
 		 *
@@ -36,8 +45,20 @@ namespace BansheeEngine
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 */
 		 */
 		static GUIScrollBarVert* create(const GUIOptions& options, const String& styleName = StringUtil::BLANK);
 		static GUIScrollBarVert* create(const GUIOptions& options, const String& styleName = StringUtil::BLANK);
+
+		/**
+		 * Creates a new vertical scroll bar.
+		 *
+		 * @param[in]	resizeable		If true the scrollbar will have additional handles that allow the scroll handle to
+		 *								be resized. This allows you to adjust the size of the visible scroll area.
+		 * @param[in]	options			Options that allow you to control how is the element positioned and sized.
+		 *								This will override any similar options set by style.
+		 * @param[in]	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 GUIScrollBarVert* create(bool resizable, const GUIOptions& options, const String& styleName = StringUtil::BLANK);
 	protected:
 	protected:
-		GUIScrollBarVert(const String& styleName, const GUIDimensions& dimensions);
+		GUIScrollBarVert(bool resizable, const String& styleName, const GUIDimensions& dimensions);
 		~GUIScrollBarVert();
 		~GUIScrollBarVert();
 	};
 	};
 
 

+ 1 - 1
Source/BansheeEngine/Include/BsGUISlider.h

@@ -91,7 +91,7 @@ namespace BansheeEngine
 		void styleUpdated() override;
 		void styleUpdated() override;
 
 
 		/**	Triggered when the slider handles moves. */
 		/**	Triggered when the slider handles moves. */
-		void onHandleMoved(float newPosition);
+		void onHandleMoved(float newPosition, float newSize);
 
 
 	private:
 	private:
 		GUISliderHandle* mSliderHandle;
 		GUISliderHandle* mSliderHandle;

+ 43 - 18
Source/BansheeEngine/Include/BsGUISliderHandle.h

@@ -13,6 +13,25 @@ namespace BansheeEngine
 	 *  @{
 	 *  @{
 	 */
 	 */
 
 
+	/** Flags that control how does a slider handle behave. */
+	enum class GUISliderHandleFlag
+	{
+		/** Slider handle will move horizontally. Cannot be used with the Vertical option. */
+		Horizontal = 1 << 0,
+		/** Slider handle will move vertically. Cannot be used with the Horizontal option. */
+		Vertical = 1 << 1,
+		/** 
+		 * If enabled, clicking on a specific slider position will cause the handle to jump to that position. If false the
+		 * handle will only slightly move in that direction.
+		 */
+		JumpOnClick = 1 << 2,
+		/** Determines should the slider handle provide additional side-handles that allow it to be resized. */
+		Resizeable = 1 << 3
+	};
+
+	typedef Flags<GUISliderHandleFlag> GUISliderHandleFlags;
+	BS_FLAGS_OPERATORS(GUISliderHandleFlag);
+
 	/** A handle that can be dragged from its predefined minimum and maximum position, either horizontally or vertically. */
 	/** A handle that can be dragged from its predefined minimum and maximum position, either horizontally or vertically. */
 	class BS_EXPORT GUISliderHandle : public GUIElement
 	class BS_EXPORT GUISliderHandle : public GUIElement
 	{
 	{
@@ -22,6 +41,12 @@ namespace BansheeEngine
 			Normal, Hover, Active
 			Normal, Hover, Active
 		};
 		};
 
 
+		/** State the handle can be in while user is dragging it. */
+		enum class DragState
+		{
+			Normal, LeftResize, RightResize
+		};
+
 	public:
 	public:
 		/** Returns type name of the GUI element used for finding GUI element styles.  */
 		/** Returns type name of the GUI element used for finding GUI element styles.  */
 		static const String& getGUITypeName();
 		static const String& getGUITypeName();
@@ -29,28 +54,22 @@ namespace BansheeEngine
 		/**
 		/**
 		 * Creates a new handle.
 		 * Creates a new handle.
 		 *
 		 *
-		 * @param[in]	horizontal		Should the handle be movable vertically or horizontally.
-		 * @param[in]	jumpOnClick		If true clicking on a specific position on the slider will cause the slider handle
-		 *								to jump to that position. Otherwise the slider will just slightly move towards that
-		 *								direction.
+		 * @param[in]	flags			Flags that control how does the handle behave.
 		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the
 		 * @param[in]	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.
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 */
 		 */
-		static GUISliderHandle* create(bool horizontal, bool jumpOnClick, const String& styleName = StringUtil::BLANK);
+		static GUISliderHandle* create(GUISliderHandleFlags flags, const String& styleName = StringUtil::BLANK);
 
 
 		/**
 		/**
 		 * Creates a new handle.
 		 * Creates a new handle.
 		 *
 		 *
-		 * @param[in]	horizontal		Should the handle be movable vertically or horizontally.
-		 * @param[in]	jumpOnClick		If true clicking on a specific position on the slider will cause the slider handle
-		 *								to jump to that position. Otherwise the slider will just slightly move towards that
-		 *								direction.
+		 * @param[in]	flags			Flags that control how does the handle behave.
 		 * @param[in]	options			Options that allow you to control how is the element positioned and sized.
 		 * @param[in]	options			Options that allow you to control how is the element positioned and sized.
 		 *								This will override any similar options set by style.
 		 *								This will override any similar options set by style.
 		 * @param[in]	styleName		Optional style to use for the element. Style will be retrieved from GUISkin of the
 		 * @param[in]	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.
 		 *								GUIWidget the element is used on. If not specified default style is used.
 		 */
 		 */
-		static GUISliderHandle* create(bool horizontal, bool jumpOnClick, const GUIOptions& options,
+		static GUISliderHandle* create(GUISliderHandleFlags flags, const GUIOptions& options,
 			const String& styleName = StringUtil::BLANK);
 			const String& styleName = StringUtil::BLANK);
 
 
 		/**	Gets the current position of the handle, in percent ranging [0.0f, 1.0f]. */
 		/**	Gets the current position of the handle, in percent ranging [0.0f, 1.0f]. */
@@ -69,13 +88,13 @@ namespace BansheeEngine
 		UINT32 getMaxSize() const;
 		UINT32 getMaxSize() const;
 
 
 		/**	
 		/**	
-		 * Sets a step that defines the minimal increment the value can be increased/decreased by. Set to zero	to have no
+		 * Sets a step that defines the minimal increment the value can be increased/decreased by. Set to zero to have no
 		 * step.
 		 * step.
 		 */
 		 */
 		void setStep(float step);
 		void setStep(float step);
 
 
 		/** Triggered when the user drags the handle. */
 		/** Triggered when the user drags the handle. */
-		Event<void(float newPosition)> onHandleMoved;
+		Event<void(float pos, float size)> onHandleMovedOrResized;
 
 
 	public: // ***** INTERNAL ******
 	public: // ***** INTERNAL ******
 		/** @name Internal
 		/** @name Internal
@@ -83,11 +102,11 @@ namespace BansheeEngine
 		 */
 		 */
 
 
 		/**
 		/**
-		 * Size of the handle in pixels, along the handle drag direction.
+		 * Size of the handle in percent of the total draggable area, along the handle drag direction.
 		 *
 		 *
 		 * @note	 Does not trigger layout update.
 		 * @note	 Does not trigger layout update.
 		 */
 		 */
-		void _setHandleSize(UINT32 size);
+		void _setHandleSize(float pct);
 
 
 		/**
 		/**
 		 * Moves the handle the the specified position in the handle area.
 		 * Moves the handle the the specified position in the handle area.
@@ -98,6 +117,9 @@ namespace BansheeEngine
 		 */
 		 */
 		void _setHandlePos(float pct);
 		void _setHandlePos(float pct);
 
 
+		/** Returns the size of the slider handle, in percent of the total area. */
+		float _getHandleSizePct() const;
+
 		/** @copydoc GUIElement::_getOptimalSize */
 		/** @copydoc GUIElement::_getOptimalSize */
 		Vector2I _getOptimalSize() const override;
 		Vector2I _getOptimalSize() const override;
 
 
@@ -124,7 +146,7 @@ namespace BansheeEngine
 		/** @copydoc GUIElement::updateClippedBounds() */
 		/** @copydoc GUIElement::updateClippedBounds() */
 		void updateClippedBounds() override;
 		void updateClippedBounds() override;
 	private:
 	private:
-		GUISliderHandle(bool horizontal, bool jumpOnClick, const String& styleName, const GUIDimensions& dimensions);
+		GUISliderHandle(GUISliderHandleFlags flags, const String& styleName, const GUIDimensions& dimensions);
 
 
 		/** @copydoc GUIElement::_mouseEvent */
 		/** @copydoc GUIElement::_mouseEvent */
 		bool _mouseEvent(const GUIMouseEvent& ev) override;
 		bool _mouseEvent(const GUIMouseEvent& ev) override;
@@ -132,20 +154,23 @@ namespace BansheeEngine
 		/** Checks are the specified over the scroll handle. Coordinates are relative to the parent widget. */
 		/** Checks are the specified over the scroll handle. Coordinates are relative to the parent widget. */
 		bool isOnHandle(const Vector2I& pos) const;
 		bool isOnHandle(const Vector2I& pos) const;
 
 
-		/**	Sets the position of the slider handle, in pixels. Relative to this object. For internal use only. */
+		/**	Sets the position of the slider handle, in pixels. Relative to this object. */
 		void setHandlePosPx(INT32 pos);
 		void setHandlePosPx(INT32 pos);
 
 
 		/**	Gets the currently active texture, depending on handle state. */
 		/**	Gets the currently active texture, depending on handle state. */
 		const HSpriteTexture& getActiveTexture() const;
 		const HSpriteTexture& getActiveTexture() const;
 
 
+		static const UINT32 MIN_HANDLE_SIZE;
+		static const UINT32 RESIZE_HANDLE_SIZE;
+
 		ImageSprite* mImageSprite;
 		ImageSprite* mImageSprite;
 		UINT32 mHandleSize;
 		UINT32 mHandleSize;
 
 
-		bool mHorizontal; // Otherwise its vertical
-		bool mJumpOnClick;
+		GUISliderHandleFlags mFlags;
 		float mPctHandlePos;
 		float mPctHandlePos;
 		float mStep;
 		float mStep;
 		INT32 mDragStartPos;
 		INT32 mDragStartPos;
+		DragState mDragState;
 		bool mMouseOverHandle;
 		bool mMouseOverHandle;
 		bool mHandleDragged;
 		bool mHandleDragged;
 		State mState;
 		State mState;

+ 4 - 11
Source/BansheeEngine/Source/BsGUIScrollArea.cpp

@@ -14,7 +14,6 @@ using namespace std::placeholders;
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	const UINT32 GUIScrollArea::ScrollBarWidth = 16;
 	const UINT32 GUIScrollArea::ScrollBarWidth = 16;
-	const UINT32 GUIScrollArea::MinHandleSize = 4;
 	const UINT32 GUIScrollArea::WheelScrollAmount = 50;
 	const UINT32 GUIScrollArea::WheelScrollAmount = 50;
 
 
 	GUIScrollArea::GUIScrollArea(ScrollBarType vertBarType, ScrollBarType horzBarType, 
 	GUIScrollArea::GUIScrollArea(ScrollBarType vertBarType, ScrollBarType horzBarType, 
@@ -32,8 +31,8 @@ namespace BansheeEngine
 		_registerChildElement(mHorzScroll);
 		_registerChildElement(mHorzScroll);
 		_registerChildElement(mVertScroll);
 		_registerChildElement(mVertScroll);
 
 
-		mHorzScroll->onScrollPositionChanged.connect(std::bind(&GUIScrollArea::horzScrollUpdate, this, _1));
-		mVertScroll->onScrollPositionChanged.connect(std::bind(&GUIScrollArea::vertScrollUpdate, this, _1));
+		mHorzScroll->onScrollOrResize.connect(std::bind(&GUIScrollArea::horzScrollUpdate, this, _1));
+		mVertScroll->onScrollOrResize.connect(std::bind(&GUIScrollArea::vertScrollUpdate, this, _1));
 	}
 	}
 
 
 	GUIScrollArea::~GUIScrollArea()
 	GUIScrollArea::~GUIScrollArea()
@@ -321,16 +320,13 @@ namespace BansheeEngine
 			mVertScroll->_updateLayoutInternal(vertScrollData);
 			mVertScroll->_updateLayoutInternal(vertScrollData);
 
 
 			// Set new handle size and update position to match the new size
 			// Set new handle size and update position to match the new size
-			UINT32 newHandleSize = (UINT32)Math::floorToInt(mVertScroll->getMaxHandleSize() * (vertScrollBounds.height / (float)mContentSize.y));
-			newHandleSize = std::max(newHandleSize, MinHandleSize);
-
 			UINT32 scrollableHeight = (UINT32)std::max(0, INT32(mContentSize.y) - INT32(vertScrollBounds.height));
 			UINT32 scrollableHeight = (UINT32)std::max(0, INT32(mContentSize.y) - INT32(vertScrollBounds.height));
 			float newScrollPct = 0.0f;
 			float newScrollPct = 0.0f;
 
 
 			if (scrollableHeight > 0)
 			if (scrollableHeight > 0)
 				newScrollPct = mVertOffset / scrollableHeight;	
 				newScrollPct = mVertOffset / scrollableHeight;	
 
 
-			mVertScroll->_setHandleSize(newHandleSize);
+			mVertScroll->_setHandleSize(vertScrollBounds.height / (float)mContentSize.y);
 			mVertScroll->_setScrollPos(newScrollPct);
 			mVertScroll->_setScrollPos(newScrollPct);
 		}
 		}
 
 
@@ -346,16 +342,13 @@ namespace BansheeEngine
 			mHorzScroll->_updateLayoutInternal(horzScrollData);
 			mHorzScroll->_updateLayoutInternal(horzScrollData);
 
 
 			// Set new handle size and update position to match the new size
 			// Set new handle size and update position to match the new size
-			UINT32 newHandleSize = (UINT32)Math::floorToInt(mHorzScroll->getMaxHandleSize() * (horzScrollBounds.width / (float)mContentSize.x));
-			newHandleSize = std::max(newHandleSize, MinHandleSize);
-
 			UINT32 scrollableWidth = (UINT32)std::max(0, INT32(mContentSize.x) - INT32(horzScrollBounds.width));
 			UINT32 scrollableWidth = (UINT32)std::max(0, INT32(mContentSize.x) - INT32(horzScrollBounds.width));
 			float newScrollPct = 0.0f;
 			float newScrollPct = 0.0f;
 
 
 			if (scrollableWidth > 0)
 			if (scrollableWidth > 0)
 				newScrollPct = mHorzOffset / scrollableWidth;
 				newScrollPct = mHorzOffset / scrollableWidth;
 
 
-			mHorzScroll->_setHandleSize(newHandleSize);
+			mHorzScroll->_setHandleSize(horzScrollBounds.width / (float)mContentSize.x);
 			mHorzScroll->_setScrollPos(newScrollPct);
 			mHorzScroll->_setScrollPos(newScrollPct);
 		}
 		}
 
 

+ 15 - 16
Source/BansheeEngine/Source/BsGUIScrollBar.cpp

@@ -16,11 +16,15 @@ namespace BansheeEngine
 {
 {
 	const UINT32 GUIScrollBar::ButtonScrollAmount = 10;
 	const UINT32 GUIScrollBar::ButtonScrollAmount = 10;
 
 
-	GUIScrollBar::GUIScrollBar(bool horizontal, const String& styleName, const GUIDimensions& dimensions)
+	GUIScrollBar::GUIScrollBar(bool horizontal, bool resizable, const String& styleName, const GUIDimensions& dimensions)
 		:GUIElement(styleName, dimensions), mHorizontal(horizontal)
 		:GUIElement(styleName, dimensions), mHorizontal(horizontal)
 	{
 	{
 		mImageSprite = bs_new<ImageSprite>();
 		mImageSprite = bs_new<ImageSprite>();
 
 
+		GUISliderHandleFlags flags;
+		if (resizable)
+			flags |= GUISliderHandleFlag::Resizeable;
+
 		if(mHorizontal)
 		if(mHorizontal)
 		{
 		{
 			mLayout = GUILayoutX::create();
 			mLayout = GUILayoutX::create();
@@ -29,7 +33,7 @@ namespace BansheeEngine
 			mUpBtn = GUIButton::create(HString(L""), "ScrollLeftBtn");
 			mUpBtn = GUIButton::create(HString(L""), "ScrollLeftBtn");
 			mDownBtn = GUIButton::create(HString(L""), "ScrollRightBtn");
 			mDownBtn = GUIButton::create(HString(L""), "ScrollRightBtn");
 
 
-			mHandleBtn = GUISliderHandle::create(mHorizontal, false, "ScrollBarHorzBtn");
+			mHandleBtn = GUISliderHandle::create(flags | GUISliderHandleFlag::Horizontal, "ScrollBarHorzBtn");
 		}
 		}
 		else
 		else
 		{
 		{
@@ -39,7 +43,7 @@ namespace BansheeEngine
 			mUpBtn = GUIButton::create(HString(L""), "ScrollUpBtn");
 			mUpBtn = GUIButton::create(HString(L""), "ScrollUpBtn");
 			mDownBtn = GUIButton::create(HString(L""), "ScrollDownBtn");
 			mDownBtn = GUIButton::create(HString(L""), "ScrollDownBtn");
 
 
-			mHandleBtn = GUISliderHandle::create(mHorizontal, false, "ScrollBarVertBtn");
+			mHandleBtn = GUISliderHandle::create(flags | GUISliderHandleFlag::Vertical, "ScrollBarVertBtn");
 		}
 		}
 
 
 		mLayout->addNewElement<GUIFixedSpace>(2);
 		mLayout->addNewElement<GUIFixedSpace>(2);
@@ -48,7 +52,7 @@ namespace BansheeEngine
 		mLayout->addElement(mDownBtn);
 		mLayout->addElement(mDownBtn);
 		mLayout->addNewElement<GUIFixedSpace>(2);
 		mLayout->addNewElement<GUIFixedSpace>(2);
 
 
-		mHandleBtn->onHandleMoved.connect(std::bind(&GUIScrollBar::handleMoved, this, _1));
+		mHandleBtn->onHandleMovedOrResized.connect(std::bind(&GUIScrollBar::handleMoved, this, _1, _2));
 
 
 		mUpBtn->onClick.connect(std::bind(&GUIScrollBar::upButtonClicked, this));
 		mUpBtn->onClick.connect(std::bind(&GUIScrollBar::upButtonClicked, this));
 		mDownBtn->onClick.connect(std::bind(&GUIScrollBar::downButtonClicked, this));
 		mDownBtn->onClick.connect(std::bind(&GUIScrollBar::downButtonClicked, this));
@@ -131,10 +135,10 @@ namespace BansheeEngine
 			vertexStride, indexStride, renderElementIdx, offset, mLayoutData.getLocalClipRect());
 			vertexStride, indexStride, renderElementIdx, offset, mLayoutData.getLocalClipRect());
 	}
 	}
 
 
-	void GUIScrollBar::handleMoved(float handlePct)
+	void GUIScrollBar::handleMoved(float handlePct, float sizePct)
 	{
 	{
-		if(!onScrollPositionChanged.empty())
-			onScrollPositionChanged(handlePct);
+		if(!onScrollOrResize.empty())
+			onScrollOrResize(handlePct, sizePct);
 	}
 	}
 
 
 	void GUIScrollBar::upButtonClicked()
 	void GUIScrollBar::upButtonClicked()
@@ -170,14 +174,14 @@ namespace BansheeEngine
 		{
 		{
 			mHandleBtn->_markLayoutAsDirty();
 			mHandleBtn->_markLayoutAsDirty();
 
 
-			if (!onScrollPositionChanged.empty())
-				onScrollPositionChanged(newHandlePos);
+			if (!onScrollOrResize.empty())
+				onScrollOrResize(newHandlePos, mHandleBtn->_getHandleSizePct());
 		}
 		}
 	}
 	}
 
 
-	void GUIScrollBar::_setHandleSize(UINT32 size)
+	void GUIScrollBar::_setHandleSize(float pct)
 	{
 	{
-		mHandleBtn->_setHandleSize(size);
+		mHandleBtn->_setHandleSize(pct);
 	}
 	}
 
 
 	void GUIScrollBar::_setScrollPos(float pct)
 	void GUIScrollBar::_setScrollPos(float pct)
@@ -190,11 +194,6 @@ namespace BansheeEngine
 		return mHandleBtn->getHandlePos();
 		return mHandleBtn->getHandlePos();
 	}
 	}
 
 
-	UINT32 GUIScrollBar::getMaxHandleSize() const
-	{
-		return mHandleBtn->getMaxSize();
-	}
-
 	UINT32 GUIScrollBar::getScrollableSize() const
 	UINT32 GUIScrollBar::getScrollableSize() const
 	{
 	{
 		return mHandleBtn->getScrollableSize();
 		return mHandleBtn->getScrollableSize();

+ 18 - 4
Source/BansheeEngine/Source/BsGUIScrollBarHorz.cpp

@@ -5,8 +5,8 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	GUIScrollBarHorz::GUIScrollBarHorz(const String& styleName, const GUIDimensions& dimensions)
-		:GUIScrollBar(true, styleName, dimensions)
+	GUIScrollBarHorz::GUIScrollBarHorz(bool resizeable, const String& styleName, const GUIDimensions& dimensions)
+		:GUIScrollBar(true, resizeable, styleName, dimensions)
 	{
 	{
 
 
 	}
 	}
@@ -18,12 +18,26 @@ namespace BansheeEngine
 
 
 	GUIScrollBarHorz* GUIScrollBarHorz::create(const String& styleName)
 	GUIScrollBarHorz* GUIScrollBarHorz::create(const String& styleName)
 	{
 	{
-		return new (bs_alloc<GUIScrollBarHorz>()) GUIScrollBarHorz(getStyleName<GUIScrollBarHorz>(styleName), GUIDimensions::create());
+		return new (bs_alloc<GUIScrollBarHorz>()) GUIScrollBarHorz(false, getStyleName<GUIScrollBarHorz>(styleName), 
+			GUIDimensions::create());
+	}
+
+	GUIScrollBarHorz* GUIScrollBarHorz::create(bool resizeable, const String& styleName)
+	{
+		return new (bs_alloc<GUIScrollBarHorz>()) GUIScrollBarHorz(resizeable, getStyleName<GUIScrollBarHorz>(styleName), 
+			GUIDimensions::create());
 	}
 	}
 
 
 	GUIScrollBarHorz* GUIScrollBarHorz::create(const GUIOptions& options, const String& styleName)
 	GUIScrollBarHorz* GUIScrollBarHorz::create(const GUIOptions& options, const String& styleName)
 	{
 	{
-		return new (bs_alloc<GUIScrollBarHorz>()) GUIScrollBarHorz(getStyleName<GUIScrollBarHorz>(styleName), GUIDimensions::create(options));
+		return new (bs_alloc<GUIScrollBarHorz>()) GUIScrollBarHorz(false, getStyleName<GUIScrollBarHorz>(styleName), 
+			GUIDimensions::create(options));
+	}
+
+	GUIScrollBarHorz* GUIScrollBarHorz::create(bool resizeable, const GUIOptions& options, const String& styleName)
+	{
+		return new (bs_alloc<GUIScrollBarHorz>()) GUIScrollBarHorz(resizeable, getStyleName<GUIScrollBarHorz>(styleName), 
+			GUIDimensions::create(options));
 	}
 	}
 
 
 	const String& GUIScrollBarHorz::getGUITypeName()
 	const String& GUIScrollBarHorz::getGUITypeName()

+ 18 - 4
Source/BansheeEngine/Source/BsGUIScrollBarVert.cpp

@@ -5,8 +5,8 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	GUIScrollBarVert::GUIScrollBarVert(const String& styleName, const GUIDimensions& dimensions)
-		:GUIScrollBar(false, styleName, dimensions)
+	GUIScrollBarVert::GUIScrollBarVert(bool resizeable, const String& styleName, const GUIDimensions& dimensions)
+		:GUIScrollBar(false, resizeable, styleName, dimensions)
 	{
 	{
 
 
 	}
 	}
@@ -18,12 +18,26 @@ namespace BansheeEngine
 
 
 	GUIScrollBarVert* GUIScrollBarVert::create(const String& styleName)
 	GUIScrollBarVert* GUIScrollBarVert::create(const String& styleName)
 	{
 	{
-		return new (bs_alloc<GUIScrollBarVert>()) GUIScrollBarVert(getStyleName<GUIScrollBarVert>(styleName), GUIDimensions::create());
+		return new (bs_alloc<GUIScrollBarVert>()) GUIScrollBarVert(false, getStyleName<GUIScrollBarVert>(styleName), 
+			GUIDimensions::create());
+	}
+
+	GUIScrollBarVert* GUIScrollBarVert::create(bool resizeable, const String& styleName)
+	{
+		return new (bs_alloc<GUIScrollBarVert>()) GUIScrollBarVert(resizeable, getStyleName<GUIScrollBarVert>(styleName), 
+			GUIDimensions::create());
 	}
 	}
 
 
 	GUIScrollBarVert* GUIScrollBarVert::create(const GUIOptions& options, const String& styleName)
 	GUIScrollBarVert* GUIScrollBarVert::create(const GUIOptions& options, const String& styleName)
 	{
 	{
-		return new (bs_alloc<GUIScrollBarVert>()) GUIScrollBarVert(getStyleName<GUIScrollBarVert>(styleName), GUIDimensions::create(options));
+		return new (bs_alloc<GUIScrollBarVert>()) GUIScrollBarVert(false, getStyleName<GUIScrollBarVert>(styleName), 
+			GUIDimensions::create(options));
+	}
+
+	GUIScrollBarVert* GUIScrollBarVert::create(bool resizeable, const GUIOptions& options, const String& styleName)
+	{
+		return new (bs_alloc<GUIScrollBarVert>()) GUIScrollBarVert(resizeable, getStyleName<GUIScrollBarVert>(styleName), 
+			GUIDimensions::create(options));
 	}
 	}
 
 
 	const String& GUIScrollBarVert::getGUITypeName()
 	const String& GUIScrollBarVert::getGUITypeName()

+ 6 - 3
Source/BansheeEngine/Source/BsGUISlider.cpp

@@ -12,7 +12,10 @@ namespace BansheeEngine
 	GUISlider::GUISlider(bool horizontal, const String& styleName, const GUIDimensions& dimensions)
 	GUISlider::GUISlider(bool horizontal, const String& styleName, const GUIDimensions& dimensions)
 		:GUIElementContainer(dimensions, styleName), mHorizontal(horizontal), mMinRange(0.0f), mMaxRange(1.0f)
 		:GUIElementContainer(dimensions, styleName), mHorizontal(horizontal), mMinRange(0.0f), mMaxRange(1.0f)
 	{
 	{
-		mSliderHandle = GUISliderHandle::create(horizontal, true, getSubStyleName(getHandleStyleType()));
+		GUISliderHandleFlags flags = horizontal ? GUISliderHandleFlag::Horizontal : GUISliderHandleFlag::Vertical;
+		flags |= GUISliderHandleFlag::JumpOnClick;
+
+		mSliderHandle = GUISliderHandle::create(flags, getSubStyleName(getHandleStyleType()));
 		mBackground = GUITexture::create(getSubStyleName(getBackgroundStyleType()));
 		mBackground = GUITexture::create(getSubStyleName(getBackgroundStyleType()));
 		mFillBackground = GUITexture::create(getSubStyleName(getFillStyleType()));
 		mFillBackground = GUITexture::create(getSubStyleName(getFillStyleType()));
 
 
@@ -23,7 +26,7 @@ namespace BansheeEngine
 		_registerChildElement(mBackground);
 		_registerChildElement(mBackground);
 		_registerChildElement(mFillBackground);
 		_registerChildElement(mFillBackground);
 
 
-		mHandleMovedConn = mSliderHandle->onHandleMoved.connect(std::bind(&GUISlider::onHandleMoved, this, _1));
+		mHandleMovedConn = mSliderHandle->onHandleMovedOrResized.connect(std::bind(&GUISlider::onHandleMoved, this, _1, _2));
 	}
 	}
 
 
 	GUISlider::~GUISlider()
 	GUISlider::~GUISlider()
@@ -195,7 +198,7 @@ namespace BansheeEngine
 		mSliderHandle->setTint(color);
 		mSliderHandle->setTint(color);
 	}
 	}
 
 
-	void GUISlider::onHandleMoved(float newPosition)
+	void GUISlider::onHandleMoved(float newPosition, float newSize)
 	{
 	{
 		onChanged(getValue());
 		onChanged(getValue());
 	}
 	}

+ 99 - 34
Source/BansheeEngine/Source/BsGUISliderHandle.cpp

@@ -10,15 +10,18 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	const UINT32 GUISliderHandle::MIN_HANDLE_SIZE = 16;
+	const UINT32 GUISliderHandle::RESIZE_HANDLE_SIZE = 8;
+
 	const String& GUISliderHandle::getGUITypeName()
 	const String& GUISliderHandle::getGUITypeName()
 	{
 	{
 		static String name = "SliderHandle";
 		static String name = "SliderHandle";
 		return name;
 		return name;
 	}
 	}
 
 
-	GUISliderHandle::GUISliderHandle(bool horizontal, bool jumpOnClick, const String& styleName, const GUIDimensions& dimensions)
-		: GUIElement(styleName, dimensions), mHandleSize(0), mHorizontal(horizontal), mJumpOnClick(jumpOnClick)
-		, mPctHandlePos(0.0f), mStep(0.0f), mDragStartPos(0), mMouseOverHandle(false), mHandleDragged(false)
+	GUISliderHandle::GUISliderHandle(GUISliderHandleFlags flags, const String& styleName, const GUIDimensions& dimensions)
+		: GUIElement(styleName, dimensions), mHandleSize(0), mFlags(flags), mPctHandlePos(0.0f), mStep(0.0f)
+		, mDragStartPos(0), mDragState(DragState::Normal), mMouseOverHandle(false), mHandleDragged(false)
 		, mState(State::Normal)
 		, mState(State::Normal)
 	{
 	{
 		mImageSprite = bs_new<ImageSprite>();
 		mImageSprite = bs_new<ImageSprite>();
@@ -29,21 +32,23 @@ namespace BansheeEngine
 		bs_delete(mImageSprite);
 		bs_delete(mImageSprite);
 	}
 	}
 
 
-	GUISliderHandle* GUISliderHandle::create(bool horizontal, bool jumpOnClick, const String& styleName)
+	GUISliderHandle* GUISliderHandle::create(GUISliderHandleFlags flags, const String& styleName)
 	{
 	{
-		return new (bs_alloc<GUISliderHandle>()) GUISliderHandle(horizontal, jumpOnClick, 
+		return new (bs_alloc<GUISliderHandle>()) GUISliderHandle(flags, 
 			getStyleName<GUISliderHandle>(styleName), GUIDimensions::create());
 			getStyleName<GUISliderHandle>(styleName), GUIDimensions::create());
 	}
 	}
 
 
-	GUISliderHandle* GUISliderHandle::create(bool horizontal, bool jumpOnClick, const GUIOptions& options, const String& styleName)
+	GUISliderHandle* GUISliderHandle::create(GUISliderHandleFlags flags, const GUIOptions& options, const String& styleName)
 	{
 	{
-		return new (bs_alloc<GUISliderHandle>()) GUISliderHandle(horizontal, jumpOnClick, 
+		return new (bs_alloc<GUISliderHandle>()) GUISliderHandle(flags, 
 			getStyleName<GUISliderHandle>(styleName), GUIDimensions::create(options));
 			getStyleName<GUISliderHandle>(styleName), GUIDimensions::create(options));
 	}
 	}
 
 
-	void GUISliderHandle::_setHandleSize(UINT32 size)
+	void GUISliderHandle::_setHandleSize(float pct)
 	{
 	{
-		mHandleSize = std::min(getMaxSize(), size);
+		pct = Math::clamp01(pct);
+
+		mHandleSize = std::max(MIN_HANDLE_SIZE, (UINT32)(getMaxSize() * pct));
 	}
 	}
 
 
 	void GUISliderHandle::_setHandlePos(float pct)
 	void GUISliderHandle::_setHandlePos(float pct)
@@ -105,7 +110,7 @@ namespace BansheeEngine
 		if(SpriteTexture::checkIsLoaded(activeTex))
 		if(SpriteTexture::checkIsLoaded(activeTex))
 			desc.texture = activeTex.getInternalPtr();
 			desc.texture = activeTex.getInternalPtr();
 
 
-		if (mHorizontal)
+		if (mFlags.isSet(GUISliderHandleFlag::Horizontal))
 		{
 		{
 			if (mHandleSize == 0 && desc.texture != nullptr)
 			if (mHandleSize == 0 && desc.texture != nullptr)
 				mHandleSize = desc.texture->getWidth();
 				mHandleSize = desc.texture->getWidth();
@@ -156,16 +161,18 @@ namespace BansheeEngine
 		UINT32 indexStride = sizeof(UINT32);
 		UINT32 indexStride = sizeof(UINT32);
 
 
 		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
 		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
-		if(mHorizontal)
-			offset.x += getHandlePosPx();
-		else
-			offset.y += getHandlePosPx();
-
 		Rect2I clipRect = mLayoutData.getLocalClipRect();
 		Rect2I clipRect = mLayoutData.getLocalClipRect();
-		if(mHorizontal)
+
+		if (mFlags.isSet(GUISliderHandleFlag::Horizontal))
+		{
+			offset.x += getHandlePosPx();
 			clipRect.x -= getHandlePosPx();
 			clipRect.x -= getHandlePosPx();
+		}
 		else
 		else
+		{
+			offset.y += getHandlePosPx();
 			clipRect.y -= getHandlePosPx();
 			clipRect.y -= getHandlePosPx();
+		}
 
 
 		mImageSprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
 		mImageSprite->fillBuffer(vertices, uvs, indices, vertexOffset, indexOffset, maxNumVerts, maxNumIndices,
 			vertexStride, indexStride, renderElementIdx, offset, clipRect);
 			vertexStride, indexStride, renderElementIdx, offset, clipRect);
@@ -204,34 +211,68 @@ namespace BansheeEngine
 			}
 			}
 		}
 		}
 
 
-		if(ev.getType() == GUIMouseEventType::MouseDown && (mMouseOverHandle || mJumpOnClick))
+		bool jumpOnClick = mFlags.isSet(GUISliderHandleFlag::JumpOnClick);
+		if(ev.getType() == GUIMouseEventType::MouseDown && (mMouseOverHandle || jumpOnClick))
 		{
 		{
 			if (!_isDisabled())
 			if (!_isDisabled())
 			{
 			{
 				mState = State::Active;
 				mState = State::Active;
 				_markLayoutAsDirty();
 				_markLayoutAsDirty();
 
 
-				if (mJumpOnClick)
+				if (jumpOnClick)
 				{
 				{
 					float handlePosPx = 0.0f;
 					float handlePosPx = 0.0f;
 
 
-					if (mHorizontal)
+					if (mFlags.isSet(GUISliderHandleFlag::Horizontal))
 						handlePosPx = (float)(ev.getPosition().x - (INT32)mLayoutData.area.x - mHandleSize * 0.5f);
 						handlePosPx = (float)(ev.getPosition().x - (INT32)mLayoutData.area.x - mHandleSize * 0.5f);
 					else
 					else
 						handlePosPx = (float)(ev.getPosition().y - (INT32)mLayoutData.area.y - mHandleSize * 0.5f);
 						handlePosPx = (float)(ev.getPosition().y - (INT32)mLayoutData.area.y - mHandleSize * 0.5f);
 
 
 					setHandlePosPx((INT32)handlePosPx);
 					setHandlePosPx((INT32)handlePosPx);
-					onHandleMoved(mPctHandlePos);
+					onHandleMovedOrResized(mPctHandlePos, _getHandleSizePct());
 				}
 				}
 
 
-				if (mHorizontal)
+				bool isResizeable = mFlags.isSet(GUISliderHandleFlag::Resizeable);
+				if (mFlags.isSet(GUISliderHandleFlag::Horizontal))
 				{
 				{
 					INT32 left = (INT32)mLayoutData.area.x + getHandlePosPx();
 					INT32 left = (INT32)mLayoutData.area.x + getHandlePosPx();
+
+					if(isResizeable)
+					{
+						INT32 right = left + mHandleSize;
+
+						INT32 clickPos = ev.getPosition().x;
+						if(clickPos >= left && clickPos < (left + (INT32)RESIZE_HANDLE_SIZE))
+							mDragState = DragState::LeftResize;
+						else if(clickPos >= (right - (INT32)RESIZE_HANDLE_SIZE) && clickPos < right)
+							mDragState = DragState::RightResize;
+						else
+							mDragState = DragState::Normal;
+					}
+					else
+						mDragState = DragState::Normal;
+
 					mDragStartPos = ev.getPosition().x - left;
 					mDragStartPos = ev.getPosition().x - left;
 				}
 				}
 				else
 				else
 				{
 				{
 					INT32 top = (INT32)mLayoutData.area.y + getHandlePosPx();
 					INT32 top = (INT32)mLayoutData.area.y + getHandlePosPx();
+
+					if(isResizeable)
+					{
+						INT32 bottom = top + mHandleSize;
+
+						INT32 clickPos = ev.getPosition().y;
+						if (clickPos >= top && clickPos < (top + (INT32)RESIZE_HANDLE_SIZE))
+							mDragState = DragState::LeftResize;
+						else if (clickPos >= (bottom - (INT32)RESIZE_HANDLE_SIZE) && clickPos < bottom)
+							mDragState = DragState::RightResize;
+						else
+							mDragState = DragState::Normal;
+					}
+					else
+						mDragState = DragState::Normal;
+
 					mDragStartPos = ev.getPosition().y - top;
 					mDragStartPos = ev.getPosition().y - top;
 				}
 				}
 				
 				
@@ -245,18 +286,37 @@ namespace BansheeEngine
 		{
 		{
 			if (!_isDisabled())
 			if (!_isDisabled())
 			{
 			{
-				float handlePosPx = 0.0f;
-				if (mHorizontal)
-				{
-					handlePosPx = (float)(ev.getPosition().x - mDragStartPos - mLayoutData.area.x);
-				}
+				INT32 handlePosPx;
+				if (mFlags.isSet(GUISliderHandleFlag::Horizontal))
+					handlePosPx = ev.getPosition().x - mDragStartPos - mLayoutData.area.x;
 				else
 				else
+					handlePosPx = ev.getPosition().y - mDragStartPos - mLayoutData.area.y;
+
+				if (mDragState == DragState::Normal)
 				{
 				{
-					handlePosPx = (float)(ev.getPosition().y - mDragStartPos - mLayoutData.area.y);
+					setHandlePosPx(handlePosPx);
+					onHandleMovedOrResized(mPctHandlePos, _getHandleSizePct());
 				}
 				}
+				else // Resizing
+				{
+					if(mDragState == DragState::LeftResize)
+					{
+						INT32 right = getHandlePosPx() + mHandleSize;
+						INT32 newHandleSize = right - handlePosPx;
+
+						_setHandleSize(newHandleSize / (float)getMaxSize());
+						setHandlePosPx(handlePosPx);
+						onHandleMovedOrResized(mPctHandlePos, _getHandleSizePct());
+					}
+					else if(mDragState == DragState::RightResize)
+					{
+						INT32 left = getHandlePosPx();
+						INT32 newHandleSize = handlePosPx - left;
 
 
-				setHandlePosPx((INT32)handlePosPx);
-				onHandleMoved(mPctHandlePos);
+						_setHandleSize(newHandleSize / (float)getMaxSize());
+						onHandleMovedOrResized(mPctHandlePos, _getHandleSizePct());
+					}
+				}
 
 
 				_markLayoutAsDirty();
 				_markLayoutAsDirty();
 			}
 			}
@@ -293,7 +353,7 @@ namespace BansheeEngine
 				{
 				{
 					// If we clicked above or below the scroll handle, scroll by one page
 					// If we clicked above or below the scroll handle, scroll by one page
 					INT32 handlePosPx = getHandlePosPx();
 					INT32 handlePosPx = getHandlePosPx();
-					if (!mJumpOnClick)
+					if (!mFlags.isSet(GUISliderHandleFlag::JumpOnClick))
 					{
 					{
 						UINT32 stepSizePx = 0;
 						UINT32 stepSizePx = 0;
 						if (mStep > 0.0f)
 						if (mStep > 0.0f)
@@ -302,7 +362,7 @@ namespace BansheeEngine
 							stepSizePx = mHandleSize;
 							stepSizePx = mHandleSize;
 
 
 						INT32 handleOffset = 0;
 						INT32 handleOffset = 0;
-						if (mHorizontal)
+						if (mFlags.isSet(GUISliderHandleFlag::Horizontal))
 						{
 						{
 							INT32 handleLeft = (INT32)mLayoutData.area.x + handlePosPx;
 							INT32 handleLeft = (INT32)mLayoutData.area.x + handlePosPx;
 							INT32 handleRight = handleLeft + mHandleSize;
 							INT32 handleRight = handleLeft + mHandleSize;
@@ -327,7 +387,7 @@ namespace BansheeEngine
 					}
 					}
 
 
 					setHandlePosPx(handlePosPx);
 					setHandlePosPx(handlePosPx);
-					onHandleMoved(mPctHandlePos);
+					onHandleMovedOrResized(mPctHandlePos, _getHandleSizePct());
 				}
 				}
 				mHandleDragged = false;
 				mHandleDragged = false;
 				_markLayoutAsDirty();
 				_markLayoutAsDirty();
@@ -357,7 +417,7 @@ namespace BansheeEngine
 
 
 	bool GUISliderHandle::isOnHandle(const Vector2I& pos) const
 	bool GUISliderHandle::isOnHandle(const Vector2I& pos) const
 	{
 	{
-		if(mHorizontal)
+		if(mFlags.isSet(GUISliderHandleFlag::Horizontal))
 		{
 		{
 			INT32 left = (INT32)mLayoutData.area.x + getHandlePosPx();
 			INT32 left = (INT32)mLayoutData.area.x + getHandlePosPx();
 			INT32 right = left + mHandleSize;
 			INT32 right = left + mHandleSize;
@@ -383,6 +443,11 @@ namespace BansheeEngine
 		return Math::floorToInt(mPctHandlePos * maxScrollAmount);
 		return Math::floorToInt(mPctHandlePos * maxScrollAmount);
 	}
 	}
 
 
+	float GUISliderHandle::_getHandleSizePct() const
+	{
+		return Math::clamp01(mHandleSize / (float)getMaxSize());
+	}
+
 	void GUISliderHandle::setHandlePosPx(INT32 pos)
 	void GUISliderHandle::setHandlePosPx(INT32 pos)
 	{
 	{
 		float maxScrollAmount = (float)getMaxSize() - mHandleSize;
 		float maxScrollAmount = (float)getMaxSize() - mHandleSize;
@@ -392,7 +457,7 @@ namespace BansheeEngine
 	UINT32 GUISliderHandle::getMaxSize() const
 	UINT32 GUISliderHandle::getMaxSize() const
 	{
 	{
 		UINT32 maxSize = mLayoutData.area.height;
 		UINT32 maxSize = mLayoutData.area.height;
-		if(mHorizontal)
+		if(mFlags.isSet(GUISliderHandleFlag::Horizontal))
 			maxSize = mLayoutData.area.width;
 			maxSize = mLayoutData.area.width;
 
 
 		return maxSize;
 		return maxSize;