2
0
Эх сурвалжийг харах

Int and float fields are now draggable

Marko Pintera 11 жил өмнө
parent
commit
58b8c0e393

+ 6 - 0
BansheeEditor/Include/BsGUIFloatField.h

@@ -42,13 +42,19 @@ namespace BansheeEditor
 	protected:
 		virtual ~GUIFloatField();
 
+		void updateClippedBounds();
+
 		void _updateLayoutInternal(CM::INT32 x, CM::INT32 y, CM::UINT32 width, CM::UINT32 height,
 			CM::RectI clipRect, CM::UINT8 widgetDepth, CM::UINT16 areaDepth);
 	protected:
 		static const float SPLIT_POSITION;
+		static const float DRAG_SPEED;
 
 		BS::GUILabel* mLabel;
 		BS::GUIInputBox* mInputBox;
+		CM::INT32 mLastDragPos;
+		bool mIsDragging;
+		bool mIsDragCursorSet;
 
 		virtual bool mouseEvent(const BS::GUIMouseEvent& ev);
 

+ 6 - 0
BansheeEditor/Include/BsGUIIntField.h

@@ -42,13 +42,19 @@ namespace BansheeEditor
 	protected:
 		virtual ~GUIIntField();
 
+		void updateClippedBounds();
+
 		void _updateLayoutInternal(CM::INT32 x, CM::INT32 y, CM::UINT32 width, CM::UINT32 height,
 			CM::RectI clipRect, CM::UINT8 widgetDepth, CM::UINT16 areaDepth);
 	protected:
 		static const float SPLIT_POSITION;
+		static const CM::INT32 DRAG_SPEED;
 
 		BS::GUILabel* mLabel;
 		BS::GUIInputBox* mInputBox;
+		CM::INT32 mLastDragPos;
+		bool mIsDragging;
+		bool mIsDragCursorSet;
 
 		virtual bool mouseEvent(const BS::GUIMouseEvent& ev);
 

+ 0 - 17
BansheeEditor/Include/CmTestTextSprite.h

@@ -17,24 +17,7 @@ namespace BansheeEditor
 		void init(const BS::HCamera& camera, const CM::String& text, CM::RenderTexturePtr sceneView);
 
 	private:
-		BS::GUILabel* mLabel;
-		BS::GUIListBox* mListBox;
 		GUISceneTreeView* mSceneTreeView;
 		GUIResourceTreeView* mResourceTreeView;
-		CM::HString labelString;
-
-		CM::HSceneObject mDbgMainA;
-		CM::HSceneObject mDbgMainB;
-
-		CM::HSceneObject mDbgChildA;
-		CM::HSceneObject mDbgChildB;
-		CM::HSceneObject mDbgChildC;
-
-		void dbgBtn();
-
-		void dbgAdd();
-		void dbgRename();
-		void dbgRemoveChildren();
-		void dbgRemoveParents();
 	};
 }

+ 96 - 9
BansheeEditor/Source/BsGUIFloatField.cpp

@@ -7,6 +7,9 @@
 #include "BsBuiltinResources.h"
 #include "BsGUIWidget.h"
 #include "BsGUIMouseEvent.h"
+#include "BsCursor.h"
+#include "BsGUIWidget.h"
+#include "CmViewport.h"
 #include <regex>
 
 using namespace CamelotFramework;
@@ -15,10 +18,12 @@ using namespace BansheeEngine;
 namespace BansheeEditor
 {
 	const float GUIFloatField::SPLIT_POSITION = 0.5f;
+	const float GUIFloatField::DRAG_SPEED = 0.05f;
 
 	GUIFloatField::GUIFloatField(const PrivatelyConstruct& dummy, GUIWidget& parent, const GUIContent& labelContent, 
 		GUIElementStyle* labelStyle, GUIElementStyle* inputBoxStyle, const GUILayoutOptions& layoutOptions)
-		:GUIElementContainer(parent, layoutOptions), mLabel(nullptr), mInputBox(nullptr)
+		:GUIElementContainer(parent, layoutOptions), mLabel(nullptr), mInputBox(nullptr), mIsDragging(false),
+		mLastDragPos(0), mIsDragCursorSet(false)
 	{
 		const GUIElementStyle* curLabelStyle = labelStyle;
 		const GUIElementStyle* curInputBoxStyle = inputBoxStyle;
@@ -35,11 +40,14 @@ namespace BansheeEditor
 
 		_registerChildElement(mLabel);
 		_registerChildElement(mInputBox);
+
+		setValue(0);
 	}
 
 	GUIFloatField::GUIFloatField(const PrivatelyConstruct& dummy, GUIWidget& parent, 
 		GUIElementStyle* labelStyle, GUIElementStyle* inputBoxStyle, const GUILayoutOptions& layoutOptions)
-		:GUIElementContainer(parent, layoutOptions), mLabel(nullptr), mInputBox(nullptr)
+		:GUIElementContainer(parent, layoutOptions), mLabel(nullptr), mInputBox(nullptr), mIsDragging(false),
+		mLastDragPos(0)
 	{
 		const GUIElementStyle* curInputBoxStyle = inputBoxStyle;
 
@@ -50,6 +58,8 @@ namespace BansheeEditor
 		mInputBox->setFilter(&GUIFloatField::floatFilter);
 
 		_registerChildElement(mInputBox);
+
+		setValue(0);
 	}
 
 	GUIFloatField::~GUIFloatField()
@@ -102,29 +112,100 @@ namespace BansheeEditor
 	{
 		GUIElementContainer::mouseEvent(event);
 
+		RectI draggableArea;
+
+		if(mLabel != nullptr)
+			draggableArea = mLabel->getBounds();
+
 		if(event.getType() == GUIMouseEventType::MouseDragStart)
 		{
-			// TODO -If over draggable area start drag
+			if(draggableArea.contains(event.getPosition()))
+			{
+				mLastDragPos = event.getPosition().x;
+				mIsDragging = true;
+
+				Cursor::instance().setCursor(CursorType::ArrowLeftRight);
+				mIsDragCursorSet = true;
+			}
 
 			return true;
 		}
 		else if(event.getType() == GUIMouseEventType::MouseDrag)
 		{
-			// TODO - If drag is started increase/lower the value
+			if(mIsDragging)
+			{
+				INT32 xDiff = event.getPosition().x - mLastDragPos;
+
+				INT32 jumpAmount = 0;
+				if(event.getPosition().x < 0)
+				{
+					Vector2I cursorScreenPos = Cursor::instance().getScreenPosition();
+					cursorScreenPos.x += _getParentWidget().getTarget()->getWidth();
+					jumpAmount = _getParentWidget().getTarget()->getWidth();
+
+					Cursor::instance().setScreenPosition(cursorScreenPos);
+				}
+				else if(event.getPosition().x >= _getParentWidget().getTarget()->getWidth())
+				{
+					Vector2I cursorScreenPos = Cursor::instance().getScreenPosition();
+					cursorScreenPos.x -= _getParentWidget().getTarget()->getWidth();
+					jumpAmount = -_getParentWidget().getTarget()->getWidth();
+
+					Cursor::instance().setScreenPosition(cursorScreenPos);
+				}
+
+				float oldValue = getValue();
+				float newValue = oldValue + xDiff * DRAG_SPEED;
+
+				mLastDragPos = event.getPosition().x + jumpAmount;
+
+				if(oldValue != newValue)
+					setValue(newValue);
+			}
 
 			return true;
 		}
-		else if(event.getType() == GUIMouseEventType::MouseOut)
+		else if(event.getType() == GUIMouseEventType::MouseDragEnd)
 		{
-			// TODO - Ensure cursor is set back to arrow
+			mIsDragging = false;
+
+			if(mIsDragCursorSet)
+			{
+				Cursor::instance().setCursor(CursorType::Arrow);
+				mIsDragCursorSet = false;
+			}
 
 			return true;
 		}
+		else if(event.getType() == GUIMouseEventType::MouseOut)
+		{
+			if(!mIsDragging)
+			{
+				if(mIsDragCursorSet)
+				{
+					Cursor::instance().setCursor(CursorType::Arrow);
+					mIsDragCursorSet = false;
+				}
+			}
+		}
 		else if(event.getType() == GUIMouseEventType::MouseMove)
 		{
-			// TODO - If mouse is over drag area change cursor to Arrow Left/Right
-
-			return true;
+			if(draggableArea.contains(event.getPosition()))
+			{
+				Cursor::instance().setCursor(CursorType::ArrowLeftRight);
+				mIsDragCursorSet = true;
+			}
+			else
+			{
+				if(!mIsDragging)
+				{
+					if(mIsDragCursorSet)
+					{
+						Cursor::instance().setCursor(CursorType::Arrow);
+						mIsDragCursorSet = false;
+					}
+				}
+			}
 		}
 
 		return false;
@@ -140,6 +221,12 @@ namespace BansheeEditor
 		mInputBox->setText(toWString(value));
 	}
 
+	void GUIFloatField::updateClippedBounds()
+	{
+		Vector2I offset = _getOffset();
+		mClippedBounds = RectI(offset.x, offset.y, _getWidth(), _getHeight());
+	}
+
 	void GUIFloatField::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
 		RectI clipRect, UINT8 widgetDepth, UINT16 areaDepth)
 	{

+ 114 - 10
BansheeEditor/Source/BsGUIIntField.cpp

@@ -7,6 +7,9 @@
 #include "BsBuiltinResources.h"
 #include "BsGUIWidget.h"
 #include "BsGUIMouseEvent.h"
+#include "BsGUIWidget.h"
+#include "BsCursor.h"
+#include "CmViewport.h"
 #include <regex>
 
 using namespace CamelotFramework;
@@ -15,10 +18,12 @@ using namespace BansheeEngine;
 namespace BansheeEditor
 {
 	const float GUIIntField::SPLIT_POSITION = 0.5f;
+	const INT32 GUIIntField::DRAG_SPEED = 5;
 
 	GUIIntField::GUIIntField(const PrivatelyConstruct& dummy, GUIWidget& parent, const GUIContent& labelContent, 
 		GUIElementStyle* labelStyle, GUIElementStyle* inputBoxStyle, const GUILayoutOptions& layoutOptions)
-		:GUIElementContainer(parent, layoutOptions), mLabel(nullptr), mInputBox(nullptr)
+		:GUIElementContainer(parent, layoutOptions), mLabel(nullptr), mInputBox(nullptr), mIsDragging(false),
+		mLastDragPos(0), mIsDragCursorSet(false)
 	{
 		const GUIElementStyle* curLabelStyle = labelStyle;
 		const GUIElementStyle* curInputBoxStyle = inputBoxStyle;
@@ -35,11 +40,14 @@ namespace BansheeEditor
 
 		_registerChildElement(mLabel);
 		_registerChildElement(mInputBox);
+
+		setValue(0);
 	}
 
 	GUIIntField::GUIIntField(const PrivatelyConstruct& dummy, GUIWidget& parent, 
 		GUIElementStyle* labelStyle, GUIElementStyle* inputBoxStyle, const GUILayoutOptions& layoutOptions)
-		:GUIElementContainer(parent, layoutOptions), mLabel(nullptr), mInputBox(nullptr)
+		:GUIElementContainer(parent, layoutOptions), mLabel(nullptr), mInputBox(nullptr), mIsDragging(false),
+		mLastDragPos(0)
 	{
 		const GUIElementStyle* curInputBoxStyle = inputBoxStyle;
 
@@ -50,6 +58,8 @@ namespace BansheeEditor
 		mInputBox->setFilter(&GUIIntField::intFilter);
 
 		_registerChildElement(mInputBox);
+
+		setValue(0);
 	}
 
 	GUIIntField::~GUIIntField()
@@ -102,29 +112,117 @@ namespace BansheeEditor
 	{
 		GUIElementContainer::mouseEvent(event);
 
+		RectI draggableArea;
+
+		if(mLabel != nullptr)
+			draggableArea = mLabel->getBounds();
+
 		if(event.getType() == GUIMouseEventType::MouseDragStart)
 		{
-			// TODO -If over draggable area start drag
+			if(draggableArea.contains(event.getPosition()))
+			{
+				mLastDragPos = event.getPosition().x;
+				mIsDragging = true;
+
+				Cursor::instance().setCursor(CursorType::ArrowLeftRight);
+				mIsDragCursorSet = true;
+			}
 
 			return true;
 		}
 		else if(event.getType() == GUIMouseEventType::MouseDrag)
 		{
-			// TODO - If drag is started increase/lower the value
+			if(mIsDragging)
+			{
+				INT32 xDiff = event.getPosition().x - mLastDragPos;
+
+				INT32 jumpAmount = 0;
+				if(event.getPosition().x < 0)
+				{
+					Vector2I cursorScreenPos = Cursor::instance().getScreenPosition();
+					cursorScreenPos.x += _getParentWidget().getTarget()->getWidth();
+					jumpAmount = _getParentWidget().getTarget()->getWidth();
+
+					Cursor::instance().setScreenPosition(cursorScreenPos);
+				}
+				else if(event.getPosition().x >= _getParentWidget().getTarget()->getWidth())
+				{
+					Vector2I cursorScreenPos = Cursor::instance().getScreenPosition();
+					cursorScreenPos.x -= _getParentWidget().getTarget()->getWidth();
+					jumpAmount = -_getParentWidget().getTarget()->getWidth();
+
+					Cursor::instance().setScreenPosition(cursorScreenPos);
+				}
+
+				INT32 oldValue = getValue();
+				INT32 newValue = oldValue;
+
+				if(xDiff >= DRAG_SPEED)
+				{
+					while(xDiff >= DRAG_SPEED)
+					{
+						newValue++;
+						xDiff -= DRAG_SPEED;
+					}
+				}
+				else if(xDiff <= -DRAG_SPEED)
+				{
+					while(xDiff <= -DRAG_SPEED)
+					{
+						newValue--;
+						xDiff += DRAG_SPEED;
+					}
+				}
+				
+				mLastDragPos += (newValue - oldValue) * DRAG_SPEED + jumpAmount;
+
+				if(oldValue != newValue)
+					setValue(newValue);
+			}
 
 			return true;
 		}
-		else if(event.getType() == GUIMouseEventType::MouseOut)
+		else if(event.getType() == GUIMouseEventType::MouseDragEnd)
 		{
-			// TODO - Ensure cursor is set back to arrow
-			
+			mIsDragging = false;
+
+			if(mIsDragCursorSet)
+			{
+				Cursor::instance().setCursor(CursorType::Arrow);
+				mIsDragCursorSet = false;
+			}
+
 			return true;
 		}
+		else if(event.getType() == GUIMouseEventType::MouseOut)
+		{
+			if(!mIsDragging)
+			{
+				if(mIsDragCursorSet)
+				{
+					Cursor::instance().setCursor(CursorType::Arrow);
+					mIsDragCursorSet = false;
+				}
+			}
+		}
 		else if(event.getType() == GUIMouseEventType::MouseMove)
 		{
-			// TODO - If mouse is over drag area change cursor to Arrow Left/Right
-
-			return true;
+			if(draggableArea.contains(event.getPosition()))
+			{
+				Cursor::instance().setCursor(CursorType::ArrowLeftRight);
+				mIsDragCursorSet = true;
+			}
+			else
+			{
+				if(!mIsDragging)
+				{
+					if(mIsDragCursorSet)
+					{
+						Cursor::instance().setCursor(CursorType::Arrow);
+						mIsDragCursorSet = false;
+					}
+				}
+			}
 		}
 
 		return false;
@@ -140,6 +238,12 @@ namespace BansheeEditor
 		mInputBox->setText(toWString(value));
 	}
 
+	void GUIIntField::updateClippedBounds()
+	{
+		Vector2I offset = _getOffset();
+		mClippedBounds = RectI(offset.x, offset.y, _getWidth(), _getHeight());
+	}
+
 	void GUIIntField::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height,
 		RectI clipRect, UINT8 widgetDepth, UINT16 areaDepth)
 	{

+ 20 - 111
BansheeEditor/Source/CmTestTextSprite.cpp

@@ -36,7 +36,7 @@ using namespace BansheeEngine;
 namespace BansheeEditor
 {
 	TestTextSprite::TestTextSprite(const HSceneObject& parent, CM::Viewport* target)
-		:GUIWidget(parent, target), mListBox(nullptr)
+		:GUIWidget(parent, target)
 	{
 	}
 
@@ -49,15 +49,6 @@ namespace BansheeEditor
 		setSkin(BansheeEditor::EditorGUI::instance().getSkin());
 		setDepth(128);
 
-		GUIArea* area = GUIArea::createStretchedXY(*this, 0, 0, 0, 0);
-
-		mSceneTreeView = GUISceneTreeView::create(*this, GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()));
-		mResourceTreeView = GUIResourceTreeView::create(*this, GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()));
-		GUILayout& sceneTreeViewLayout = area->getLayout().addLayoutY();
-		
-		//sceneTreeViewLayout.addElement(mSceneTreeView);
-		
-
 		SceneObject::create("FILLER_A");
 		SceneObject::create("FILLER_B");
 		SceneObject::create("FILLER_C");
@@ -71,116 +62,34 @@ namespace BansheeEditor
 		SceneObject::create("FILLER_K");
 		SceneObject::create("FILLER_L");
 
-		area->getLayout().addElement(GUIRenderTexture::create(*this, sceneView, GUIOptions(GUIOption::fixedWidth(800), GUIOption::fixedHeight(600))));
-		//mLabel = GUILabel::create(*this, HString(L""));
-		//area->getLayout().addElement(mLabel);
-
-		//Vector<HString>::type dropDownElements;
-		//dropDownElements.push_back(HString(L"Ejlement #1"));
-		//dropDownElements.push_back(HString(L"Element #2"));
-		//dropDownElements.push_back(HString(L"Element #3"));
-		//mListBox = GUIListBox::create(*this, dropDownElements, GUIOptions(GUIOption::fixedWidth(50), GUIOption::fixedHeight(13)));
-		//area->getLayout().addElement(mListBox);
-
-		GUIScrollArea* scrollArea = GUIScrollArea::create(*this, GUIOptions(GUIOption::fixedWidth(100), GUIOption::fixedHeight(100)));
-		sceneTreeViewLayout.addFlexibleSpace();
-		area->getLayout().addElement(scrollArea);
-		sceneTreeViewLayout.addFlexibleSpace();
+		//GUIArea* area = GUIArea::createStretchedXY(*this, 0, 0, 0, 0);
+		//area->getLayout().addElement(GUIRenderTexture::create(*this, sceneView, GUIOptions(GUIOption::fixedWidth(800), GUIOption::fixedHeight(600))));
 
-		scrollArea->getLayout().addElement(mSceneTreeView);
-		area->getLayout().addElement(mResourceTreeView);
+		//GUIArea* area = GUIArea::createStretchedXY(*this, 0, 0, 0, 0);
 
-		GUIIntField* intField = GUIIntField::create(*this, HString(L"Int Field"), GUIOptions(GUIOption::fixedWidth(200)));
-		GUIFloatField* floatField = GUIFloatField::create(*this, HString(L"Float Field"), GUIOptions(GUIOption::fixedWidth(200)));
-		area->getLayout().addElement(intField);
-		area->getLayout().addElement(floatField);
-		//GUIButton* button = GUIButton::create(*this, HString(L"dbgBtn"));
-		//button->onClick.connect(boost::bind(&TestTextSprite::dbgBtn, this));
-		//area->getLayout().addElement(button);
+		//mSceneTreeView = GUISceneTreeView::create(*this, GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()));
+		//mResourceTreeView = GUIResourceTreeView::create(*this, GUIOptions(GUIOption::flexibleWidth(), GUIOption::flexibleHeight()));
+		//GUILayout& sceneTreeViewLayout = area->getLayout().addLayoutY();
 
-		//button = GUIButton::create(*this, HString(L"Add GameObjects"));
-		//button->onClick.connect(boost::bind(&TestTextSprite::dbgAdd, this));
-		//area->getLayout().addElement(button);
+		//GUIScrollArea* scrollArea = GUIScrollArea::create(*this, GUIOptions(GUIOption::fixedWidth(100), GUIOption::fixedHeight(100)));
+		//sceneTreeViewLayout.addFlexibleSpace();
+		//area->getLayout().addElement(scrollArea);
+		//sceneTreeViewLayout.addFlexibleSpace();
 
-		//button = GUIButton::create(*this, HString(L"Rename GameObject"));
-		//button->onClick.connect(boost::bind(&TestTextSprite::dbgRename, this));
-		//area->getLayout().addElement(button);
+		//scrollArea->getLayout().addElement(mSceneTreeView);
+		//area->getLayout().addElement(mResourceTreeView);
 
-		//button = GUIButton::create(*this, HString(L"Remove child GameObjects"));
-		//button->onClick.connect(boost::bind(&TestTextSprite::dbgRemoveChildren, this));
-		//area->getLayout().addElement(button);
+		//GUIIntField* intField = GUIIntField::create(*this, HString(L"Int Field"), GUIOptions(GUIOption::fixedWidth(200)));
+		//GUIFloatField* floatField = GUIFloatField::create(*this, HString(L"Float Field"), GUIOptions(GUIOption::fixedWidth(200)));
+		//area->getLayout().addElement(intField);
+		//area->getLayout().addElement(floatField);
 
-		//button = GUIButton::create(*this, HString(L"Remove parent GameObjects"));
-		//button->onClick.connect(boost::bind(&TestTextSprite::dbgRemoveParents, this));
-		//area->getLayout().addElement(button);
-
-		area->getLayout().addFlexibleSpace();
-
-		labelString = HString(L"\\{0}, {1}");
-		//mLabel->setContent(GUIContent(labelString));
+		//area->getLayout().addFlexibleSpace();
 	}
 
 	void TestTextSprite::update()
 	{
-		labelString.setParameter(0, toWString(Input::instance().getCursorPosition().x));
-		mSceneTreeView->update();
-		mResourceTreeView->update();
-		//labelString.setParameter(1, toWString(Input::instance().getCursorPosition().y));
-	}
-
-	void TestTextSprite::dbgBtn()
-	{
-		static int dbg = 0;
-
-		if(dbg == 0)
-		{
-			//Vector<HString>::type dropDownElements;
-			//dropDownElements.push_back(HString(L"Element #4"));
-			//dropDownElements.push_back(HString(L"Element #5"));
-			//dropDownElements.push_back(HString(L"Element #6"));
-
-			//mListBox->setElements(dropDownElements);
-
-			//StringTable::instance().setString(L"dbgBtn", Language::Abkhazian, L"ALOALO");
-			//StringTable::instance().setActiveLanguage(Language::Abkhazian);
-		}
-		else if(dbg == 1)
-		{
-			//StringTable::instance().removeString(L"dbgBtn");
-		}
-
-		dbg++;
-	}
-
-	void TestTextSprite::dbgAdd()
-	{
-		mDbgMainA = SceneObject::create("DEBUG_A");
-		mDbgChildA = SceneObject::create("DEBUG_CHILD_0");
-		mDbgChildA->setParent(mDbgMainA);
-
-		mDbgChildB = SceneObject::create("DEBUG_CHILD_1");
-		mDbgChildB->setParent(mDbgMainA);
-
-		mDbgChildC = SceneObject::create("DEBUG_CHILD_2");
-		mDbgChildC->setParent(mDbgMainA);
-
-		mDbgMainB = SceneObject::create("DEBUG_B");
-	}
-
-	void TestTextSprite::dbgRename()
-	{
-		mDbgMainA->setName("Z_DEBUG_RENAMED_A");
-	}
-
-	void TestTextSprite::dbgRemoveChildren()
-	{
-		mDbgChildA->destroy();
-		mDbgChildB->destroy();
-	}
-
-	void TestTextSprite::dbgRemoveParents()
-	{
-		mDbgMainA->destroy();
-		mDbgMainB->destroy();
+		//mSceneTreeView->update();
+		//mResourceTreeView->update();
 	}
 }

+ 9 - 11
BansheeEditor/Source/DbgEditorWidget2.cpp

@@ -6,6 +6,10 @@
 #include "BsGUILayout.h"
 #include "BsGUIWidget.h"
 #include "BsGUISkin.h"
+#include "BsGUIIntField.h"
+#include "BsGUIFloatField.h"
+#include "BsGUISpace.h"
+#include "CmHString.h"
 
 using namespace CamelotFramework;
 using namespace BansheeEngine;
@@ -19,18 +23,12 @@ namespace BansheeEditor
 	{
 		GUILayout& layout = mContent->getLayout();
 
-		GUIScrollArea* scrollArea = GUIScrollArea::create(getParentWidget());
-		layout.addElement(scrollArea);
+		GUIIntField* intField = GUIIntField::create(getParentWidget(), HString(L"Int Field"), GUIOptions(GUIOption::fixedWidth(200)));
+		GUIFloatField* floatField = GUIFloatField::create(getParentWidget(), HString(L"Float Field"), GUIOptions(GUIOption::fixedWidth(200)));
+		layout.addElement(intField);
+		layout.addElement(floatField);
 
-		GUILayout& scrollLayout = scrollArea->getLayout().addLayoutY();
-
-		std::shared_ptr<GUIToggleGroup> toggleGroup = GUIToggle::createToggleGroup();
-
-		scrollLayout.addElement(GUIToggle::create(getParentWidget(), HString(L"Test A"), toggleGroup, getParentWidget().getSkin().getStyle("Button")));
-		scrollLayout.addElement(GUIToggle::create(getParentWidget(), HString(L"Test B"), toggleGroup, getParentWidget().getSkin().getStyle("Button")));
-		scrollLayout.addElement(GUIToggle::create(getParentWidget(), HString(L"Test C"), toggleGroup, getParentWidget().getSkin().getStyle("Button")));
-		scrollLayout.addElement(GUIToggle::create(getParentWidget(), HString(L"Test D"), toggleGroup, getParentWidget().getSkin().getStyle("Button")));
-		scrollLayout.addElement(GUIToggle::create(getParentWidget(), HString(L"Test E"), toggleGroup, getParentWidget().getSkin().getStyle("Button")));
+		layout.addFlexibleSpace();
 	}
 
 	DbgEditorWidget2::~DbgEditorWidget2()

+ 7 - 1
BansheeEngine/Include/BsCursor.h

@@ -48,7 +48,12 @@ namespace BansheeEngine
 		/**
 		 * @brief	Moves the cursor to the specified screen position.
 		 */
-		void move(const CM::Vector2I& screenPos);
+		void setScreenPosition(const CM::Vector2I& screenPos);
+
+		/**
+		 * @brief	Retrieves the cursor position in screen coordinates.
+		 */
+		CM::Vector2I getScreenPosition();
 
 		/**
 		 * @brief	Hides the cursor.
@@ -129,5 +134,6 @@ namespace BansheeEngine
 		CM::UINT32 mActiveCursorId;
 
 		void restoreCursorIcon(CursorType type);
+		void updateCursorImage();
 	};
 }

+ 26 - 13
BansheeEngine/Source/BsCursor.cpp

@@ -14,13 +14,19 @@ namespace BansheeEngine
 			restoreCursorIcon((CursorType)i);
 
 		setCursor(CursorType::Arrow);
+		updateCursorImage();
 	}
 
-	void Cursor::move(const Vector2I& screenPos)
+	void Cursor::setScreenPosition(const Vector2I& screenPos)
 	{
 		Platform::setCursorPosition(screenPos);
 	}
 
+	Vector2I Cursor::getScreenPosition()
+	{
+		return Platform::getCursorPosition();
+	}
+
 	void Cursor::hide()
 	{
 		Platform::hideCursor();
@@ -49,11 +55,11 @@ namespace BansheeEngine
 	void Cursor::setCursor(CursorType type)
 	{
 		UINT32 id = (UINT32)type;
-		CustomIcon& customIcon = mCustomIcons[id];
-
-		Platform::setCursor(customIcon.pixelData, customIcon.hotSpot);
-
-		mActiveCursorId = id;
+		if(mActiveCursorId != id)
+		{
+			mActiveCursorId = id;
+			updateCursorImage();
+		}
 	}
 
 	void Cursor::setCursor(const CM::String& name)
@@ -66,10 +72,11 @@ namespace BansheeEngine
 		}
 
 		UINT32 id = iterFind->second;
-		CustomIcon& customIcon = mCustomIcons[id];
-		Platform::setCursor(customIcon.pixelData, customIcon.hotSpot);
-
-		mActiveCursorId = id;
+		if(mActiveCursorId != id)
+		{
+			mActiveCursorId = id;
+			updateCursorImage();
+		}
 	}
 
 	void Cursor::setCursorIcon(const CM::String& name, const CM::PixelData& pixelData, const CM::Vector2I& hotSpot)
@@ -81,7 +88,7 @@ namespace BansheeEngine
 			mCustomIcons[id] = CustomIcon(pixelData, hotSpot);
 
 			if(mActiveCursorId == id)
-				setCursor(name); // Refresh active
+				updateCursorImage(); // Refresh active
 		}
 		else
 		{
@@ -99,7 +106,7 @@ namespace BansheeEngine
 		mCustomIcons[id].hotSpot = hotSpot;
 
 		if(mActiveCursorId == id)
-			setCursor(type); // Refresh active
+			updateCursorImage(); // Refresh active
 	}
 
 	void Cursor::clearCursorIcon(const CM::String& name)
@@ -117,7 +124,7 @@ namespace BansheeEngine
 		restoreCursorIcon(type);
 
 		if(mActiveCursorId == (UINT32)type)
-			setCursor(type); // Refresh active
+			updateCursorImage(); // Refresh active
 	}
 
 	void Cursor::restoreCursorIcon(CursorType type)
@@ -161,4 +168,10 @@ namespace BansheeEngine
 
 		CM_EXCEPT(InvalidParametersException, "Invalid cursor type: " + toString((UINT32)type));
 	}
+
+	void Cursor::updateCursorImage()
+	{
+		CustomIcon& customIcon = mCustomIcons[mActiveCursorId];
+		Platform::setCursor(customIcon.pixelData, customIcon.hotSpot);
+	}
 }

+ 9 - 5
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -400,11 +400,8 @@ namespace BansheeEngine
 				markContentAsDirty();
 			}
 
-			if(!mInputCursorSet)
-			{
-				Cursor::instance().setCursor(CursorType::IBeam);
-				mInputCursorSet = true;
-			}
+			Cursor::instance().setCursor(CursorType::IBeam);
+			mInputCursorSet = true;
 
 			mIsMouseOver = true;
 
@@ -428,6 +425,13 @@ namespace BansheeEngine
 
 			return true;
 		}
+		else if(ev.getType() == GUIMouseEventType::MouseMove)
+		{
+			Cursor::instance().setCursor(CursorType::IBeam);
+			mInputCursorSet = true;
+
+			return true;
+		}
 		else if(ev.getType() == GUIMouseEventType::MouseDoubleClick && ev.getButton() == GUIMouseButton::Left)
 		{
 			showSelection(0);

+ 9 - 6
BansheeEngine/Source/BsGUIManager.cpp

@@ -778,18 +778,21 @@ namespace BansheeEngine
 		}
 
 		// Send DragEnd event to whichever element is active
-		bool acceptEndDrag = mDragState == DragState::Dragging && mActiveMouseButton == guiButton && 
+		bool acceptEndDrag = (mDragState == DragState::Dragging || mDragState == DragState::HeldWithoutDrag) && mActiveMouseButton == guiButton && 
 			(guiButton == GUIMouseButton::Left);
 
 		if(acceptEndDrag)
 		{
-			for(auto& activeElement : mActiveElements)
+			if(mDragState == DragState::Dragging)
 			{
-				Vector2I localPos = getWidgetRelativePos(*activeElement.widget, event.screenPos);
+				for(auto& activeElement : mActiveElements)
+				{
+					Vector2I localPos = getWidgetRelativePos(*activeElement.widget, event.screenPos);
 
-				mMouseEvent.setMouseDragEndData(localPos);
-				if(sendMouseEvent(activeElement.widget, activeElement.element, mMouseEvent))
-					event.markAsUsed();
+					mMouseEvent.setMouseDragEndData(localPos);
+					if(sendMouseEvent(activeElement.widget, activeElement.element, mMouseEvent))
+						event.markAsUsed();
+				}
 			}
 
 			mDragState = DragState::NoDrag;

+ 7 - 0
CamelotCore/Include/Win32/CmPlatformImpl.h

@@ -52,6 +52,13 @@ namespace CamelotFramework
 		Platform() { }
 		virtual ~Platform() { }
 
+		/**
+		 * @brief	Retrieves the cursor position in screen coordinates.
+		 * 			
+		 * @note	Thread safe. 
+		 */
+		static Vector2I getCursorPosition();
+
 		/**
 		 * @brief	Moves the cursor to the specified screen position.
 		 * 			

+ 13 - 0
CamelotCore/Source/Win32/CmPlatformImpl.cpp

@@ -72,6 +72,19 @@ namespace CamelotFramework
 	NativeCursorData Platform::mCursor;
 	bool Platform::mUsingCustomCursor = false;
 
+	Vector2I Platform::getCursorPosition()
+	{
+		Vector2I screenPos;
+
+		POINT cursorPos;
+		GetCursorPos(&cursorPos);
+
+		screenPos.x = cursorPos.x;
+		screenPos.y = cursorPos.y;
+
+		return screenPos;
+	}
+
 	void Platform::setCursorPosition(const Vector2I& screenPos)
 	{
 		SetCursorPos(screenPos.x, screenPos.y);

+ 4 - 0
Inspector.txt

@@ -17,6 +17,10 @@ Text field
 Cursor
  - A way to save/load a set of cursors
 
+ IMMEDIATE:
+  - Deleting first entry in input field moves the cursor incorrectly
+  - Test if parsing int/float value from int/float field actually works
+
 Other:
  - Refactor BuiltinMaterialFactory to BuiltinEngineResources