Преглед изворни кода

Selectable/Movable scrollbar

Marko Pintera пре 12 година
родитељ
комит
55e2f25e2f

+ 13 - 3
BansheeEngine/Include/BsGUIScrollBarHandle.h

@@ -11,8 +11,12 @@ namespace BansheeEngine
 	public:
 		static const CM::String& getGUITypeName();
 
-		static GUIScrollBarHandle* create(GUIWidget& parent, const GUIElementStyle* style = nullptr);
-		static GUIScrollBarHandle* create(GUIWidget& parent, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style = nullptr);
+		static GUIScrollBarHandle* create(GUIWidget& parent, bool horizontal, const GUIElementStyle* style = nullptr);
+		static GUIScrollBarHandle* create(GUIWidget& parent, bool horizontal, const GUILayoutOptions& layoutOptions, 
+			const GUIElementStyle* style = nullptr);
+
+		void setHandleSize(CM::UINT32 size);
+		void setHandlePos(float pct);
 	protected:
 		~GUIScrollBarHandle();
 
@@ -49,9 +53,15 @@ namespace BansheeEngine
 		CM::UINT32 mHandleSize;
 		SpriteTexturePtr mCurTexture;
 		bool mHorizontal; // Otherwise its vertical
+		CM::INT32 mHandlePos;
+		CM::INT32 mDragStartPos;
+		bool mMouseOverHandle;
+		bool mHandleDragged;
 
-		GUIScrollBarHandle(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions);
+		GUIScrollBarHandle(GUIWidget& parent, bool horizontal, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions);
 
 		virtual bool mouseEvent(const GUIMouseEvent& ev);
+		bool isOnHandle(const CM::Int2& pos) const;
+		CM::UINT32 getMaxSize() const;
 	};
 }

+ 146 - 17
BansheeEngine/Source/BsGUIScrollBarHandle.cpp

@@ -18,8 +18,9 @@ namespace BansheeEngine
 		return name;
 	}
 
-	GUIScrollBarHandle::GUIScrollBarHandle(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions)
-		:GUIElement(parent, style, layoutOptions), mHorizontal(false), mHandleSize(2)
+	GUIScrollBarHandle::GUIScrollBarHandle(GUIWidget& parent, bool horizontal, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions)
+		:GUIElement(parent, style, layoutOptions), mHorizontal(horizontal), mHandleSize(2), mMouseOverHandle(false), mHandlePos(0), mDragStartPos(0),
+		mHandleDragged(false)
 	{
 		mImageSprite = cm_new<ImageSprite, PoolAlloc>();
 		mCurTexture = style->normal.texture;
@@ -30,7 +31,7 @@ namespace BansheeEngine
 		cm_delete<PoolAlloc>(mImageSprite);
 	}
 
-	GUIScrollBarHandle* GUIScrollBarHandle::create(GUIWidget& parent, const GUIElementStyle* style)
+	GUIScrollBarHandle* GUIScrollBarHandle::create(GUIWidget& parent, bool horizontal, const GUIElementStyle* style)
 	{
 		if(style == nullptr)
 		{
@@ -38,10 +39,10 @@ namespace BansheeEngine
 			style = skin->getStyle(getGUITypeName());
 		}
 
-		return new (cm_alloc<GUIScrollBarHandle, PoolAlloc>()) GUIScrollBarHandle(parent, style, getDefaultLayoutOptions(style));
+		return new (cm_alloc<GUIScrollBarHandle, PoolAlloc>()) GUIScrollBarHandle(parent, horizontal, style, getDefaultLayoutOptions(style));
 	}
 
-	GUIScrollBarHandle* GUIScrollBarHandle::create(GUIWidget& parent, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style)
+	GUIScrollBarHandle* GUIScrollBarHandle::create(GUIWidget& parent, bool horizontal, const GUILayoutOptions& layoutOptions, const GUIElementStyle* style)
 	{
 		if(style == nullptr)
 		{
@@ -49,7 +50,21 @@ namespace BansheeEngine
 			style = skin->getStyle(getGUITypeName());
 		}
 
-		return new (cm_alloc<GUIScrollBarHandle, PoolAlloc>()) GUIScrollBarHandle(parent, style, layoutOptions);
+		return new (cm_alloc<GUIScrollBarHandle, PoolAlloc>()) GUIScrollBarHandle(parent, horizontal, style, layoutOptions);
+	}
+
+	void GUIScrollBarHandle::setHandleSize(CM::UINT32 size)
+	{
+		mHandleSize = std::min(getMaxSize(), size);
+		markContentAsDirty();
+	}
+
+	void GUIScrollBarHandle::setHandlePos(float pct)
+	{
+		UINT32 maxScrollAmount = getMaxSize() - mHandleSize;
+		mHandlePos = Math::FloorToInt(pct * maxScrollAmount);
+
+		markContentAsDirty();
 	}
 
 	UINT32 GUIScrollBarHandle::getNumRenderElements() const
@@ -85,7 +100,9 @@ namespace BansheeEngine
 
 		mImageSprite->update(desc);
 		mBounds = Rect(mOffset.x, mOffset.y, mWidth, mHeight);
-		mBounds.clip(mClipRect);
+
+		Rect localClipRect(mClipRect.x + mOffset.x, mClipRect.y + mOffset.y, mClipRect.width, mClipRect.height);
+		mBounds.clip(localClipRect);
 	}
 
 	UINT32 GUIScrollBarHandle::_getOptimalWidth() const
@@ -111,41 +128,153 @@ namespace BansheeEngine
 	void GUIScrollBarHandle::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 	{
+		Int2 offset = mOffset;
+		if(mHorizontal)
+			offset.x += mHandlePos;
+		else
+			offset.y += mHandlePos;
+
+		Rect clipRect = mClipRect;
+		if(mHorizontal)
+			clipRect.x -= mHandlePos;
+		else
+			clipRect.y -= mHandlePos;
+
 		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, 
-			vertexStride, indexStride, renderElementIdx, mOffset, mClipRect);
+			vertexStride, indexStride, renderElementIdx, offset, clipRect);
 	}
 
 	bool GUIScrollBarHandle::mouseEvent(const GUIMouseEvent& ev)
 	{
-		if(ev.getType() == GUIMouseEventType::MouseOver)
+		if(ev.getType() == GUIMouseEventType::MouseMove)
 		{
-			mCurTexture = mStyle->hover.texture;
+			if(mMouseOverHandle)
+			{
+				if(!isOnHandle(ev.getPosition()))
+				{
+					mMouseOverHandle = false;
+
+					mCurTexture = mStyle->normal.texture;
+					markContentAsDirty();
+
+					return true;
+				}
+			}
+			else
+			{
+				if(isOnHandle(ev.getPosition()))
+				{
+					mMouseOverHandle = true;
+
+					mCurTexture = mStyle->hover.texture;
+					markContentAsDirty();
+
+					return true;
+				}
+			}
+		}
+
+		if(ev.getType() == GUIMouseEventType::MouseDown && mMouseOverHandle)
+		{
+			mCurTexture = mStyle->active.texture;
 			markContentAsDirty();
 
+			if(mHorizontal)
+			{
+				INT32 left = (INT32)mOffset.x + mHandlePos;
+				mDragStartPos = ev.getPosition().x - left;
+			}
+			else
+			{
+				INT32 top = (INT32)mOffset.y + mHandlePos;
+				mDragStartPos = ev.getPosition().y - top;
+			}
+
+			mHandleDragged = true;
 			return true;
 		}
-		else if(ev.getType() == GUIMouseEventType::MouseOut)
+
+		if(ev.getType() == GUIMouseEventType::MouseDrag && mHandleDragged)
 		{
-			mCurTexture = mStyle->normal.texture;
-			markContentAsDirty();
+			if(mHorizontal)
+			{
+				mHandlePos = ev.getPosition().x - mDragStartPos - mOffset.x;
+			}
+			else
+			{
+				mHandlePos = ev.getPosition().y - mDragStartPos - mOffset.y;
+			}
 
+			UINT32 maxScrollAmount = getMaxSize() - mHandleSize;
+			mHandlePos = Math::Clamp(mHandlePos, 0, (INT32)maxScrollAmount);
+
+			markContentAsDirty();
 			return true;
 		}
-		else if(ev.getType() == GUIMouseEventType::MouseDown)
+
+		if(ev.getType() == GUIMouseEventType::MouseOut && !mHandleDragged)
 		{
-			mCurTexture = mStyle->active.texture;
+			mCurTexture = mStyle->normal.texture;
 			markContentAsDirty();
 
 			return true;
 		}
-		else if(ev.getType() == GUIMouseEventType::MouseUp)
+
+		if(ev.getType() == GUIMouseEventType::MouseUp)
 		{
-			mCurTexture = mStyle->hover.texture;
+			if(mMouseOverHandle)
+				mCurTexture = mStyle->hover.texture;
+			else
+				mCurTexture = mStyle->normal.texture;
+
 			markContentAsDirty();
+			return true;
+		}
+
+		if(ev.getType() == GUIMouseEventType::MouseDragEnd)
+		{
+			mHandleDragged = false;
+
+			if(mMouseOverHandle)
+				mCurTexture = mStyle->hover.texture;
+			else
+				mCurTexture = mStyle->normal.texture;
 
+			markContentAsDirty();
 			return true;
 		}
 		
 		return false;
 	}
+
+	bool GUIScrollBarHandle::isOnHandle(const CM::Int2& pos) const
+	{
+		if(mHorizontal)
+		{
+			INT32 left = (INT32)mOffset.x + mHandlePos;
+			INT32 right = left + mHandleSize;
+
+			if(pos.x >= left && pos.x < right)
+				return true;
+		}
+		else
+		{
+			INT32 top = (INT32)mOffset.y + 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;
+	}
 }

+ 2 - 1
BansheeEngine/Source/BsGUIScrollBarVert.cpp

@@ -6,6 +6,7 @@
 #include "BsGUILayout.h"
 #include "BsGUISkin.h"
 #include "BsGUIButton.h"
+#include "BsGUIScrollBarHandle.h"
 #include "BsGUISpace.h"
 #include "CmException.h"
 
@@ -22,7 +23,7 @@ namespace BansheeEngine
 
 		GUIButton* upBtn = GUIButton::create(parent, L"", parent.getSkin()->getStyle("ScrollUpBtn"));
 		GUIButton* downBtn = GUIButton::create(parent, L"", parent.getSkin()->getStyle("ScrollDownBtn"));
-		GUIButton* handleBtn = GUIButton::create(parent, L"", GUILayoutOptions::expandableY(6), parent.getSkin()->getStyle("ScrollBarVertBtn"));
+		GUIScrollBarHandle* handleBtn = GUIScrollBarHandle::create(parent, false, GUILayoutOptions::expandableY(6), parent.getSkin()->getStyle("ScrollBarVertBtn"));
 
 		mLayout->addSpace(2);
 		mLayout->addElement(upBtn);