Explorar o código

More work on the ScrollArea

Marko Pintera %!s(int64=12) %!d(string=hai) anos
pai
achega
20020bd8ea

+ 2 - 0
BansheeEngine/BansheeEngine.vcxproj

@@ -181,6 +181,7 @@
     <ClInclude Include="Include\BsGUIWidget.h" />
     <ClInclude Include="Include\BsImageSprite.h" />
     <ClInclude Include="Include\BsSceneManager.h" />
+    <ClInclude Include="Include\BsGUIScrollArea.h" />
     <ClInclude Include="Include\BsSprite.h" />
     <ClInclude Include="Include\BsSpriteTexture.h" />
     <ClInclude Include="Include\BsTextSprite.h" />
@@ -226,6 +227,7 @@
     <ClCompile Include="Source\BsGUIWindowMover.cpp" />
     <ClCompile Include="Source\BsImageSprite.cpp" />
     <ClCompile Include="Source\BsSceneManager.cpp" />
+    <ClCompile Include="Source\BsGUIScrollArea.cpp" />
     <ClCompile Include="Source\BsSprite.cpp" />
     <ClCompile Include="Source\BsSpriteTexture.cpp" />
     <ClCompile Include="Source\BsTextSprite.cpp" />

+ 6 - 0
BansheeEngine/BansheeEngine.vcxproj.filters

@@ -183,6 +183,9 @@
     <ClInclude Include="Include\BsGUIScrollBarHandle.h">
       <Filter>Header Files\GUI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsGUIScrollArea.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsGUIElement.cpp">
@@ -311,5 +314,8 @@
     <ClCompile Include="Source\BsGUIScrollBarHandle.cpp">
       <Filter>Source Files\GUI</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsGUIScrollArea.cpp">
+      <Filter>Source Files\GUI</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 0 - 3
BansheeEngine/Include/BsGUIElement.h

@@ -107,9 +107,6 @@ namespace BansheeEngine
 		bool _acceptsKeyboardFocus() const { return mAcceptsKeyboardFocus; }
 
 		const GUILayoutOptions& _getLayoutOptions() const { return mLayoutOptions; }
-
-		static void _destroyInternal(GUIElement* element);
-
 	protected:
 		virtual void updateRenderElementsInternal() = 0;
 

+ 1 - 1
BansheeEngine/Include/BsGUIElementBase.h

@@ -20,7 +20,7 @@ namespace BansheeEngine
 
 	public:
 		GUIElementBase();
-		virtual ~GUIElementBase() {}
+		virtual ~GUIElementBase();
 
 		/************************************************************************/
 		/* 							INTERNAL METHODS                      		*/

+ 22 - 5
BansheeEngine/Include/BsGUILayout.h

@@ -30,18 +30,35 @@ namespace BansheeEngine
 		void removeFlexibleSpace(GUIFlexibleSpace& space);
 		GUIFlexibleSpace& insertFlexibleSpace(CM::UINT32 idx);
 
-		/**
-		 * @brief	Returns a number of all child elements
-		 */
-		CM::UINT32 getNumChildren() const;
-
 		CM::UINT32 _getOptimalWidth() const { return mOptimalWidth; }
 		CM::UINT32 _getOptimalHeight() const { return mOptimalHeight; }
 		Type _getType() const { return GUIElementBase::Type::Layout; }
 
+		/**
+		 * @brief	Gets an actual width of all the child elements in the layout.
+		 *
+		 * @note	updateLayoutInternal must be called whenever layout or its children change,
+		 * 			otherwise this method will return an incorrect value.
+		 * 			
+		 *			Returned value is based on non-clipped element bounds.
+		 */
+		CM::UINT32 _getActualWidth() const { return mActualWidth; }
+
+		/**
+		 * @brief	Gets an actual height of all the child elements in the layout.
+		 *
+		 * @note	updateLayoutInternal must be called whenever layout or its children change,
+		 * 			otherwise this method will return an incorrect value.
+		 * 			
+		 *			Returned value is based on non-clipped element bounds.
+		 */
+		CM::UINT32 _getActualHeight() const { return mActualHeight; }
 	protected:
 		CM::Vector<CM::Int2>::type mOptimalSizes;
 		CM::UINT32 mOptimalWidth;
 		CM::UINT32 mOptimalHeight;
+
+		CM::UINT32 mActualWidth;
+		CM::UINT32 mActualHeight;
 	};
 }

+ 68 - 0
BansheeEngine/Include/BsGUIScrollArea.h

@@ -0,0 +1,68 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsGUIElement.h"
+
+namespace BansheeEngine
+{
+	class BS_EXPORT GUIScrollArea : public GUIElement
+	{
+	public:
+		static const CM::String& getGUITypeName();
+
+		static GUIScrollArea* create(GUIWidget& parent, const GUIElementStyle* style = nullptr);
+		static GUIScrollArea* create(GUIWidget& parent, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style = nullptr);
+
+		GUILayout& getLayout() const { return *mContentLayout; }
+
+	protected:
+		~GUIScrollArea();
+
+		/**
+		 * @copydoc GUIElement::getNumRenderElements()
+		 */
+		virtual CM::UINT32 getNumRenderElements() const;
+
+		/**
+		 * @copydoc GUIElement::getMaterial()
+		 */
+		virtual const CM::HMaterial& getMaterial(CM::UINT32 renderElementIdx) const;
+
+		/**
+		 * @copydoc GUIElement::getNumQuads()
+		 */
+		virtual CM::UINT32 getNumQuads(CM::UINT32 renderElementIdx) const;
+
+		/**
+		 * @copydoc GUIElement::fillBuffer()
+		 */
+		virtual void fillBuffer(CM::UINT8* vertices, CM::UINT8* uv, CM::UINT32* indices, CM::UINT32 startingQuad, 
+			CM::UINT32 maxNumQuads, CM::UINT32 vertexStride, CM::UINT32 indexStride, CM::UINT32 renderElementIdx) const;
+
+		/**
+		 * @copydoc GUIElement::updateRenderElementsInternal()
+		 */
+		virtual void updateRenderElementsInternal();
+
+		virtual CM::UINT32 _getOptimalWidth() const;
+		virtual CM::UINT32 _getOptimalHeight() const;
+	private:
+		GUIScrollArea(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions);
+
+		GUILayout* mContentLayout;
+		GUIScrollBarVert* mVertScroll;
+		GUIScrollBarHorz* mHorzScroll;
+
+		CM::INT32 mVertOffset;
+		CM::INT32 mHorzOffset;
+
+		CM::UINT32 mContentWidth, mContentHeight;
+
+		static const CM::UINT32 ScrollBarWidth;
+
+		void vertScrollUpdate(float pct);
+		void horzScrollUpdate(float pct);
+		void _updateLayoutInternal(CM::UINT32 x, CM::UINT32 y, CM::UINT32 width, CM::UINT32 height,
+			CM::Rect clipRect, CM::UINT8 widgetDepth, CM::UINT16 areaDepth);
+	};
+}

+ 3 - 0
BansheeEngine/Include/BsGUIScrollBarHandle.h

@@ -3,6 +3,7 @@
 #include "BsPrerequisites.h"
 #include "BsGUIElement.h"
 #include "BsImageSprite.h"
+#include "boost/signal.hpp"
 
 namespace BansheeEngine
 {
@@ -17,6 +18,8 @@ namespace BansheeEngine
 
 		void setHandleSize(CM::UINT32 size);
 		void setHandlePos(float pct);
+
+		boost::signal<void(float newPosition)> handleMoved;
 	protected:
 		~GUIScrollBarHandle();
 

+ 12 - 0
BansheeEngine/Include/BsGUIScrollBarVert.h

@@ -3,6 +3,8 @@
 #include "BsPrerequisites.h"
 #include "BsGUIElement.h"
 
+#include "boost/signal.hpp"
+
 namespace BansheeEngine
 {
 	class BS_EXPORT GUIScrollBarVert : public GUIElement
@@ -13,6 +15,10 @@ namespace BansheeEngine
 		static GUIScrollBarVert* create(GUIWidget& parent, const GUIElementStyle* style = nullptr);
 		static GUIScrollBarVert* create(GUIWidget& parent, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style = nullptr);
 
+		boost::signal<void(float newPosition)> scrollPositionChanged;
+
+		void setHandleSize(CM::UINT32 size);
+		void setScrollPos(float pct);
 	protected:
 		~GUIScrollBarVert();
 
@@ -51,5 +57,11 @@ namespace BansheeEngine
 
 		GUILayout* mLayout;
 		ImageSprite* mImageSprite;
+
+		GUIButton* mUpBtn;
+		GUIButton* mDownBtn;
+		GUIScrollBarHandle* mHandleBtn;
+
+		void handleMoved(float handlePct);
 	};
 }

+ 3 - 0
BansheeEngine/Include/BsPrerequisites.h

@@ -36,6 +36,9 @@ namespace BansheeEngine
 	class GUIWindowFrame;
 	class GUIWindowMover;
 	class GUIInputBox;
+	class GUIScrollBarHandle;
+	class GUIScrollBarVert;
+	class GUIScrollBarHorz;
 	class GUISkin;
 	struct GUIElementStyle;
 	class GUIMouseEvent;

+ 0 - 5
BansheeEngine/Source/BsGUIElement.cpp

@@ -153,11 +153,6 @@ namespace BansheeEngine
 		return layoutOptions;
 	}
 
-	void GUIElement::_destroyInternal(GUIElement* element)
-	{
-		cm_delete<PoolAlloc>(element);
-	}
-
 	void GUIElement::destroy(GUIElement* element)
 	{
 		element->mParent.unregisterElement(element);

+ 16 - 0
BansheeEngine/Source/BsGUIElementBase.cpp

@@ -2,6 +2,7 @@
 #include "BsGUILayout.h"
 #include "BsGUILayoutX.h"
 #include "BsGUILayoutY.h"
+#include "BsGUIElement.h"
 #include "CmException.h"
 
 using namespace CamelotFramework;
@@ -14,6 +15,21 @@ namespace BansheeEngine
 
 	}
 
+	GUIElementBase::~GUIElementBase()
+	{
+		for(auto& child : mChildren)
+		{
+			// Non-GUIElement are owned by us
+			if(child->_getType() != GUIElementBase::Type::Element)
+				cm_delete<PoolAlloc>(child);
+			else
+			{
+				GUIElement* element = static_cast<GUIElement*>(child);
+				element->_setParentLayout(nullptr);
+			}
+		}
+	}
+
 	bool GUIElementBase::_isContentDirty() const
 	{
 		if((mIsDirty & 0x01) != 0)

+ 2 - 17
BansheeEngine/Source/BsGUILayout.cpp

@@ -10,24 +10,14 @@ using namespace CamelotFramework;
 namespace BansheeEngine
 {
 	GUILayout::GUILayout()
-		:mOptimalWidth(0), mOptimalHeight(0)
+		:mOptimalWidth(0), mOptimalHeight(0), mActualWidth(0), mActualHeight(0)
 	{
 
 	}
 
 	GUILayout::~GUILayout() 
 	{
-		for(auto& child : mChildren)
-		{
-			// Non-GUIElement are owned by us
-			if(child->_getType() != GUIElementBase::Type::Element)
-				cm_delete<PoolAlloc>(child);
-			else
-			{
-				GUIElement* element = static_cast<GUIElement*>(child);
-				element->_setParentLayout(nullptr);
-			}
-		}
+
 	}
 
 	void GUILayout::addElement(GUIElement* element)
@@ -165,9 +155,4 @@ namespace BansheeEngine
 
 		return *entry;
 	}
-
-	UINT32 GUILayout::getNumChildren() const
-	{
-		return (UINT32)mChildren.size();
-	}
 }

+ 9 - 0
BansheeEngine/Source/BsGUILayoutX.cpp

@@ -327,9 +327,13 @@ namespace BansheeEngine
 		// Also assign offsets, clip rectangles and depth
 		UINT32 xOffset = 0;
 		childIdx = 0;
+
+		mActualWidth = 0;
+		mActualHeight = 0;
 		for(auto& child : mChildren)
 		{
 			UINT32 elemWidth = elementSizes[childIdx];
+			mActualWidth += elemWidth;
 
 			if(child->_getType() == GUIElementBase::Type::Element)
 			{
@@ -362,6 +366,8 @@ namespace BansheeEngine
 
 				Rect newClipRect(offset.x, offset.y, elemWidth, elemHeight);
 				element->_updateLayoutInternal(offset.x, offset.y, elemWidth, elemHeight, newClipRect, widgetDepth, areaDepth);
+
+				mActualHeight = std::max(mActualHeight, elemHeight);
 			}
 			else if(child->_getType() == GUIElementBase::Type::Layout)
 			{
@@ -369,6 +375,9 @@ namespace BansheeEngine
 
 				Rect newClipRect(x + xOffset, y, elemWidth, height);
 				layout->_updateLayoutInternal(x + xOffset, y, elemWidth, height, newClipRect, widgetDepth, areaDepth);
+
+				UINT32 childHeight = layout->_getActualHeight();
+				mActualHeight = std::max(mActualHeight, childHeight);
 			}
 
 			xOffset += elemWidth;

+ 9 - 0
BansheeEngine/Source/BsGUILayoutY.cpp

@@ -328,9 +328,13 @@ namespace BansheeEngine
 		// Also assign offsets, clip rectangles and depth
 		UINT32 yOffset = 0;
 		childIdx = 0;
+
+		mActualWidth = 0;
+		mActualHeight = 0;
 		for(auto& child : mChildren)
 		{
 			UINT32 elemHeight = elementSizes[childIdx];
+			mActualHeight += elemHeight;
 
 			if(child->_getType() == GUIElementBase::Type::Element)
 			{
@@ -362,6 +366,8 @@ namespace BansheeEngine
 
 				Rect newClipRect(offset.x, offset.y, elemWidth, elemHeight);
 				element->_updateLayoutInternal(offset.x, offset.y, elemWidth, elemHeight, newClipRect, widgetDepth, areaDepth);
+
+				mActualWidth = std::max(mActualWidth, elemWidth);
 			}
 			else if(child->_getType() == GUIElementBase::Type::Layout)
 			{
@@ -369,6 +375,9 @@ namespace BansheeEngine
 
 				Rect newClipRect(x, y + yOffset, width, elemHeight);
 				layout->_updateLayoutInternal(x, y + yOffset, width, elemHeight, newClipRect, widgetDepth, areaDepth);
+
+				UINT32 childWidth = layout->_getActualWidth();
+				mActualWidth = std::max(mActualWidth, childWidth);
 			}
 
 			yOffset += elemHeight;

+ 152 - 0
BansheeEngine/Source/BsGUIScrollArea.cpp

@@ -0,0 +1,152 @@
+#include "BsGUIScrollArea.h"
+#include "BsGUIElementStyle.h"
+#include "BsGUISkin.h"
+#include "BsGUIWidget.h"
+#include "BsGUILayoutOptions.h"
+#include "BsGUILayout.h"
+#include "BsGUISkin.h"
+#include "BsGUIScrollBarVert.h"
+#include "BsGUIScrollBarHorz.h"
+#include "CmException.h"
+
+using namespace CamelotFramework;
+
+namespace BansheeEngine
+{
+	const UINT32 GUIScrollArea::ScrollBarWidth = 6;
+
+	GUIScrollArea::GUIScrollArea(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions)
+		:GUIElement(parent, style, layoutOptions), mVertScroll(nullptr), mHorzScroll(nullptr), mVertOffset(0), mHorzOffset(0),
+		mContentWidth(0), mContentHeight(0)
+	{
+		mContentLayout = &addLayoutYInternal();
+		mVertScroll = GUIScrollBarVert::create(parent);
+		
+		mVertScroll->scrollPositionChanged.connect(boost::bind(&GUIScrollArea::vertScrollUpdate, this, _1));
+
+		mHorzScroll = GUIScrollBarHorz::create(parent);
+		// mHorzScroll->scrollPositionChanged.connect(boost::bind(&GUIScrollArea::horzScrollUpdate, this, _1)); // TODO - Enable
+	}
+
+	GUIScrollArea::~GUIScrollArea()
+	{
+
+	}
+
+	UINT32 GUIScrollArea::getNumRenderElements() const
+	{
+		return 0;
+	}
+
+	const HMaterial& GUIScrollArea::getMaterial(UINT32 renderElementIdx) const
+	{
+		CM_EXCEPT(InternalErrorException, "Trying to retrieve a material from an element with no render elements.");
+	}
+
+	UINT32 GUIScrollArea::getNumQuads(UINT32 renderElementIdx) const
+	{
+		return 0;
+	}
+
+	void GUIScrollArea::updateRenderElementsInternal()
+	{ }
+
+	UINT32 GUIScrollArea::_getOptimalWidth() const
+	{
+		return mContentLayout->_getOptimalWidth();
+	}
+
+	UINT32 GUIScrollArea::_getOptimalHeight() const
+	{
+		return mContentLayout->_getOptimalHeight();
+	}
+
+	void GUIScrollArea::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
+		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
+	{ }
+
+	void GUIScrollArea::_updateLayoutInternal(UINT32 x, UINT32 y, UINT32 width, UINT32 height,
+		Rect clipRect, UINT8 widgetDepth, UINT16 areaDepth)
+	{
+		mContentLayout->_updateLayoutInternal(x, y, width, height, clipRect, widgetDepth, areaDepth);
+		UINT32 contentWidth = mContentLayout->_getActualWidth();
+		UINT32 contentHeight = mContentLayout->_getActualHeight();
+
+		if(contentHeight > mHeight)
+		{
+			// Make room for scrollbar
+			UINT32 contentWidth = (UINT32)std::max(0, (INT32)width - (INT32)ScrollBarWidth);
+
+			Rect layoutClipRect(clipRect.x, clipRect.y, contentWidth, clipRect.height);
+			mContentLayout->_updateLayoutInternal(x, y - mVertOffset, contentWidth, height, layoutClipRect, widgetDepth, areaDepth);
+			contentWidth = mContentLayout->_getActualWidth();
+			contentHeight = mContentLayout->_getActualHeight();
+
+			mVertScroll = GUIScrollBarVert::create(_getParentWidget());
+			mVertScroll->scrollPositionChanged.connect(boost::bind(&GUIScrollArea::vertScrollUpdate, this, _1));
+
+			Int2 offset(x + contentWidth, y);
+			mVertScroll->_setOffset(offset);
+			mVertScroll->_setWidth(ScrollBarWidth);
+			mVertScroll->_setHeight(height);
+			mVertScroll->_setAreaDepth(areaDepth);
+			mVertScroll->_setWidgetDepth(widgetDepth);
+
+			Rect elemClipRect(clipRect.x - offset.x, clipRect.y - offset.y, clipRect.width, clipRect.height);
+			mVertScroll->_setClipRect(elemClipRect);
+
+			// TODO - Update scroll handle size and update position to match
+		}
+		else
+		{
+			if(mVertScroll != nullptr)
+			{
+				GUIElement::destroy(mVertScroll);
+				mVertScroll = nullptr;
+			}
+		}
+
+		// TODO - Add horizontal scroll bar
+		
+		mContentWidth = contentWidth;
+		mContentHeight = contentHeight;
+	}
+
+	void GUIScrollArea::vertScrollUpdate(float scrollPos)
+	{
+		mVertOffset = Math::FloorToInt(mContentHeight * scrollPos);
+	}
+
+	void GUIScrollArea::horzScrollUpdate(float scrollPos)
+	{
+		mHorzOffset = Math::FloorToInt(mContentWidth * scrollPos);
+	}
+
+	GUIScrollArea* GUIScrollArea::create(GUIWidget& parent, const GUIElementStyle* style)
+	{
+		if(style == nullptr)
+		{
+			const GUISkin* skin = parent.getSkin();
+			style = skin->getStyle(getGUITypeName());
+		}
+
+		return new (cm_alloc<GUIScrollArea, PoolAlloc>()) GUIScrollArea(parent, style, getDefaultLayoutOptions(style));
+	}
+
+	GUIScrollArea* GUIScrollArea::create(GUIWidget& parent, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style)
+	{
+		if(style == nullptr)
+		{
+			const GUISkin* skin = parent.getSkin();
+			style = skin->getStyle(getGUITypeName());
+		}
+
+		return new (cm_alloc<GUIScrollArea, PoolAlloc>()) GUIScrollArea(parent, style, layoutOptions);
+	}
+
+	const String& GUIScrollArea::getGUITypeName()
+	{
+		static String typeName = "ScrollArea";
+		return typeName;
+	}
+}

+ 6 - 0
BansheeEngine/Source/BsGUIScrollBarHandle.cpp

@@ -208,6 +208,12 @@ namespace BansheeEngine
 			UINT32 maxScrollAmount = getMaxSize() - mHandleSize;
 			mHandlePos = Math::Clamp(mHandlePos, 0, (INT32)maxScrollAmount);
 
+			if(!handleMoved.empty())
+			{
+				float pct = maxScrollAmount / (float)mHandlePos;
+				handleMoved(pct);
+			}
+
 			markContentAsDirty();
 			return true;
 		}

+ 29 - 7
BansheeEngine/Source/BsGUIScrollBarVert.cpp

@@ -15,28 +15,34 @@ using namespace CamelotFramework;
 namespace BansheeEngine
 {
 	GUIScrollBarVert::GUIScrollBarVert(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions)
-		:GUIElement(parent, style, layoutOptions), mLayout(nullptr)
+		:GUIElement(parent, style, layoutOptions)
 	{
 		mImageSprite = cm_new<ImageSprite, PoolAlloc>();
 
 		mLayout = &addLayoutYInternal();
 
-		GUIButton* upBtn = GUIButton::create(parent, L"", parent.getSkin()->getStyle("ScrollUpBtn"));
-		GUIButton* downBtn = GUIButton::create(parent, L"", parent.getSkin()->getStyle("ScrollDownBtn"));
-		GUIScrollBarHandle* handleBtn = GUIScrollBarHandle::create(parent, false, GUILayoutOptions::expandableY(6), parent.getSkin()->getStyle("ScrollBarVertBtn"));
+		mUpBtn = GUIButton::create(parent, L"", parent.getSkin()->getStyle("ScrollUpBtn"));
+		mDownBtn = GUIButton::create(parent, L"", parent.getSkin()->getStyle("ScrollDownBtn"));
+		mHandleBtn = GUIScrollBarHandle::create(parent, false, GUILayoutOptions::expandableY(6), parent.getSkin()->getStyle("ScrollBarVertBtn"));
 
 		mLayout->addSpace(2);
-		mLayout->addElement(upBtn);
+		mLayout->addElement(mUpBtn);
 		mLayout->addSpace(2);
-		mLayout->addElement(handleBtn); // We might want a special element for this?
+		mLayout->addElement(mHandleBtn);
 		mLayout->addSpace(2);
-		mLayout->addElement(downBtn);
+		mLayout->addElement(mDownBtn);
 		mLayout->addSpace(2);
+
+		mHandleBtn->handleMoved.connect(boost::bind(&GUIScrollBarVert::handleMoved, this, _1));
 	}
 
 	GUIScrollBarVert::~GUIScrollBarVert()
 	{
 		cm_delete<PoolAlloc>(mImageSprite);
+
+		GUIElement::destroy(mUpBtn);
+		GUIElement::destroy(mDownBtn);
+		GUIElement::destroy(mHandleBtn);
 	}
 
 	UINT32 GUIScrollBarVert::getNumRenderElements() const
@@ -85,6 +91,22 @@ namespace BansheeEngine
 		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx, mOffset, mClipRect);
 	}
 
+	void GUIScrollBarVert::handleMoved(float handlePct)
+	{
+		if(!scrollPositionChanged.empty())
+			scrollPositionChanged(handlePct);
+	}
+
+	void GUIScrollBarVert::setHandleSize(UINT32 size)
+	{
+		mHandleBtn->setHandleSize(size);
+	}
+
+	void GUIScrollBarVert::setScrollPos(float pct)
+	{
+		mHandleBtn->setHandlePos(pct);
+	}
+
 	GUIScrollBarVert* GUIScrollBarVert::create(GUIWidget& parent, const GUIElementStyle* style)
 	{
 		if(style == nullptr)

+ 5 - 2
BansheeEngine/Source/BsGUIWidget.cpp

@@ -35,9 +35,12 @@ namespace BansheeEngine
 		if(mTarget != nullptr)
 			GUIManager::instance().unregisterWidget(this);
 
-		for(auto& elem : mElements)
+		// Iterate over all elements in this way because each
+		// GUIElement::destroy call internally unregisters the element
+		// from the widget, and modifies the mElements array
+		for(UINT32 i = 0; i < (UINT32)mElements.size(); i++)
 		{
-			GUIElement::_destroyInternal(elem);
+			GUIElement::destroy(mElements[0]);
 		}
 
 		for(auto& area : mAreas)

+ 7 - 3
TODO.txt

@@ -26,10 +26,14 @@ IMMEDIATE:
 	- SpriteTexture keeps a static reference to DUmmyTexture which I need to release before shutdown
 
 - Hover colors of the scroll bar are wrong
-- Scroll bar background
 - Add horizontal scrollbar
-- Resizable scroll handle (Special element)
-  - Maybe a slider element I can re-use?
+
+For tomorrow:
+Add another "content" layout to GUIScrollBarVert
+OVerride updateLayoutElements
+ - apply scroll offset(s) (both horz and vertical)
+ - remember last update layout width/height and adjust scroll handle size/position if it changed
+Ensure clip rects work as intended.
 
 TextBox needed elements:
  - Key-repeat? Pressing left/right/up/down arrows doesn't repeat the keys (also delete/backspace)