Jelajahi Sumber

Merge pull request #35 from MarcoROG/master

Various GUI Improvements
Marko Pintera 9 tahun lalu
induk
melakukan
22ed7722ec
52 mengubah file dengan 1139 tambahan dan 145 penghapusan
  1. 5 20
      Source/BansheeCore/Source/Win32/BsWin32Platform.cpp
  2. 13 7
      Source/BansheeEditor/Include/BsGUIFloatField.h
  3. 9 2
      Source/BansheeEditor/Include/BsGUIIntField.h
  4. 17 4
      Source/BansheeEditor/Include/BsGUISliderField.h
  5. 25 10
      Source/BansheeEditor/Source/BsGUIFloatField.cpp
  6. 10 3
      Source/BansheeEditor/Source/BsGUIIntField.cpp
  7. 51 13
      Source/BansheeEditor/Source/BsGUISliderField.cpp
  8. 9 0
      Source/BansheeEngine/Include/BsGUISlider.h
  9. 3 0
      Source/BansheeEngine/Include/BsGUISliderHandle.h
  10. 15 0
      Source/BansheeEngine/Source/BsGUISlider.cpp
  11. 48 41
      Source/BansheeEngine/Source/BsGUISliderHandle.cpp
  12. 16 0
      Source/MBansheeEditor/GUI/GUIFloatField.cs
  13. 17 1
      Source/MBansheeEditor/GUI/GUIIntField.cs
  14. 31 10
      Source/MBansheeEditor/GUI/GUISliderField.cs
  15. 7 0
      Source/MBansheeEditor/MBansheeEditor.csproj
  16. 2 2
      Source/MBansheeEditor/Windows/Inspector/GenericInspector.cs
  17. 18 3
      Source/MBansheeEditor/Windows/Inspector/InspectableField.cs
  18. 11 2
      Source/MBansheeEditor/Windows/Inspector/InspectableFloat.cs
  19. 12 2
      Source/MBansheeEditor/Windows/Inspector/InspectableInt.cs
  20. 1 1
      Source/MBansheeEditor/Windows/Inspector/InspectableList.cs
  21. 1 1
      Source/MBansheeEditor/Windows/Inspector/InspectableObject.cs
  22. 37 0
      Source/MBansheeEditor/Windows/Inspector/InspectableRangedField.cs
  23. 86 0
      Source/MBansheeEditor/Windows/Inspector/InspectableRangedFloat.cs
  24. 86 0
      Source/MBansheeEditor/Windows/Inspector/InspectableRangedInt.cs
  25. 33 0
      Source/MBansheeEditor/Windows/Inspector/Style/InspectableFieldRangeStyle.cs
  26. 22 0
      Source/MBansheeEditor/Windows/Inspector/Style/InspectableFieldStepStyle.cs
  27. 27 0
      Source/MBansheeEditor/Windows/Inspector/Style/InspectableFieldStyle.cs
  28. 43 0
      Source/MBansheeEditor/Windows/Inspector/Style/InspectableFieldStyleInfo.cs
  29. 62 8
      Source/MBansheeEngine/GUI/GUISlider.cs
  30. 1 0
      Source/MBansheeEngine/MBansheeEngine.csproj
  31. 4 1
      Source/MBansheeEngine/Serialization/Range.cs
  32. 73 2
      Source/MBansheeEngine/Serialization/SerializableField.cs
  33. 28 0
      Source/MBansheeEngine/Serialization/Step.cs
  34. 3 1
      Source/SBansheeEditor/Include/BsScriptGUIFloatField.h
  35. 3 1
      Source/SBansheeEditor/Include/BsScriptGUIIntField.h
  36. 3 1
      Source/SBansheeEditor/Include/BsScriptGUISliderField.h
  37. 18 4
      Source/SBansheeEditor/Source/BsScriptGUIFloatField.cpp
  38. 15 1
      Source/SBansheeEditor/Source/BsScriptGUIIntField.cpp
  39. 15 1
      Source/SBansheeEditor/Source/BsScriptGUISliderField.cpp
  40. 4 0
      Source/SBansheeEngine/CMakeSources.cmake
  41. 15 1
      Source/SBansheeEngine/Include/BsManagedSerializableObjectInfo.h
  42. 8 0
      Source/SBansheeEngine/Include/BsScriptAssemblyManager.h
  43. 6 0
      Source/SBansheeEngine/Include/BsScriptGUISlider.h
  44. 27 0
      Source/SBansheeEngine/Include/BsScriptRange.h
  45. 4 1
      Source/SBansheeEngine/Include/BsScriptSerializableField.h
  46. 23 0
      Source/SBansheeEngine/Include/BsScriptStep.h
  47. 68 1
      Source/SBansheeEngine/Source/BsManagedSerializableObjectInfo.cpp
  48. 15 0
      Source/SBansheeEngine/Source/BsScriptAssemblyManager.cpp
  49. 42 0
      Source/SBansheeEngine/Source/BsScriptGUISlider.cpp
  50. 21 0
      Source/SBansheeEngine/Source/BsScriptRange.cpp
  51. 9 0
      Source/SBansheeEngine/Source/BsScriptSerializableField.cpp
  52. 17 0
      Source/SBansheeEngine/Source/BsScriptStep.cpp

+ 5 - 20
Source/BansheeCore/Source/Win32/BsWin32Platform.cpp

@@ -455,22 +455,22 @@ namespace BansheeEngine
 	 * @param[in]	ignoreMovement	If true, then movement keys (up/down/left/right) will be ignored and not considered
 	 *								as input commands (useful if you need to parse num keys as numbers and not movement).
 	 */
-	bool getCommand(unsigned int virtualKeyCode, InputCommandType& command, bool ignoreMovement = false)
+	bool getCommand(unsigned int virtualKeyCode, InputCommandType& command)
 	{
 		switch (virtualKeyCode) 
 		{ 
 		case VK_LEFT:
 			command = isShiftPressed ? InputCommandType::SelectLeft : InputCommandType::CursorMoveLeft;
-			return !ignoreMovement;
+			return true;
 		case VK_RIGHT:
 			command = isShiftPressed ? InputCommandType::SelectRight : InputCommandType::CursorMoveRight;
-			return !ignoreMovement;
+			return true;
 		case VK_UP:
 			command = isShiftPressed ? InputCommandType::SelectUp : InputCommandType::CursorMoveUp;
-			return !ignoreMovement;
+			return true;
 		case VK_DOWN:
 			command = isShiftPressed ? InputCommandType::SelectDown : InputCommandType::CursorMoveDown;
-			return !ignoreMovement;
+			return true;
 		case VK_ESCAPE:
 			command = InputCommandType::Escape;
 			return true;
@@ -855,21 +855,6 @@ namespace BansheeEngine
 					break; 
 				default:    // displayable character 
 					{
-						UINT8 scanCode = (lParam >> 16) & 0xFF;
-
-						BYTE keyState[256];
-						HKL layout = GetKeyboardLayout(0);
-						if(GetKeyboardState(keyState) == 0)
-							return 0;
-
-						unsigned int vk = MapVirtualKeyEx(scanCode, MAPVK_VSC_TO_VK_EX, layout);
-						if(vk == 0)
-							return 0;
-
-						InputCommandType command = InputCommandType::Backspace;
-						if(getCommand(vk, command, true)) // We ignore character combinations that are special commands
-							return 0;
-
 						UINT32 finalChar = (UINT32)wParam;
 
 						if(!onCharInput.empty())

+ 13 - 7
Source/BansheeEditor/Include/BsGUIFloatField.h

@@ -30,15 +30,21 @@ namespace BansheeEngine
 		/**	Returns the value of the input field. */
 		float getValue() const { return mValue; }
 
-		/**	Sets a new value in the input field. */
-		void setValue(float value);
+		/**	Sets a new value in the input field, it returns the clamped value according to range and step. */
+		float setValue(float value);
 
 		/**
-		 * Sets a minimum and maximum allow values in the input field. Set to large negative/positive values if you don't
+		 * Sets a minimum and maximum allowed values in the input field. Set to large negative/positive values if you don't
 		 * require clamping.
 		 */
 		void setRange(float min, float max);
 
+		/**	Sets the minimum change allowed for the input field. */
+		void setStep(float step);
+
+		/** Returns the minimum change allowed for the input field. */
+		float getStep() const{ return mStep; }
+
 		/**	Checks is the input field currently active. */
 		bool hasInputFocus() const { return mHasInputFocus; }
 
@@ -72,13 +78,12 @@ namespace BansheeEngine
 		void styleUpdated() override;
 
 		/**	Triggered when the input box value changes. */
-		void valueChanged(const WString& newValue);
+		void valueChanging(const WString& newValue);
 
 		/**
-		 * Triggered when the input box value changes, but unlike the previous overload the value is parsed into a floating
-		 * point value.
+		 * Triggered when the input box value changes and is confirmed.
 		 */
-		void valueChanged(float newValue);
+		void valueChanged(float newValue, bool confirmed = true);
 
 		/**	Triggers when the input box receives or loses keyboard focus. */
 		void focusChanged(bool focus);
@@ -96,6 +101,7 @@ namespace BansheeEngine
 		INT32 mLastDragPos;
 		float mMinValue;
 		float mMaxValue;
+		float mStep;
 		bool mIsDragging;
 		bool mHasInputFocus;
 	};

+ 9 - 2
Source/BansheeEditor/Include/BsGUIIntField.h

@@ -30,8 +30,8 @@ namespace BansheeEngine
 		/**	Returns the value of the input field. */
 		INT32 getValue() const { return mValue; }
 
-		/**	Sets a new value in the input field. */
-		void setValue(INT32 value);
+		/**	Sets a new value in the input field, it returns the clamped value according to range and step. */
+		INT32 setValue(INT32 value);
 
 		/**
 		 * Sets a minimum and maximum allow values in the input field. Set to large negative/positive values if you don't
@@ -39,6 +39,12 @@ namespace BansheeEngine
 		 */
 		void setRange(INT32 min, INT32 max);
 
+		/**	Sets the minimum change allowed for the input field. */
+		void setStep(INT32 step);
+
+		/** Returns the minimum change allowed for the input field. */
+		INT32 getStep() const { return mStep; }
+
 		/**	Checks is the input field currently active. */
 		bool hasInputFocus() const { return mHasInputFocus; }
 
@@ -96,6 +102,7 @@ namespace BansheeEngine
 		INT32 mLastDragPos;
 		INT32 mMinValue;
 		INT32 mMaxValue;
+		INT32 mStep;
 		bool mIsDragging;
 		bool mIsDragCursorSet;
 		bool mHasInputFocus;

+ 17 - 4
Source/BansheeEditor/Include/BsGUISliderField.h

@@ -33,8 +33,11 @@ namespace BansheeEngine
 		/**	Returns the value of the input field/slider. */
 		float getValue() const;
 
-		/**	Sets a new value in the input field/slider. */
-		void setValue(float value);
+		/** Gets the minimum percentual variation of the handle position */
+		float getStep() const;
+
+		/**	Sets a new value in the input field/slider, it returns the clamped value according to range and step. */
+		float setValue(float value);
 
 		/**
 		 * Sets a minimum and maximum allow values in the input field. Set to large negative/positive values if you don't
@@ -48,6 +51,9 @@ namespace BansheeEngine
 		 */
 		void setStep(float step);
 
+		/**	Checks is the input field currently active. */
+		bool hasInputFocus() const { return mHasInputFocus; }
+
 		/** @copydoc GUIElement::setTint */
 		void setTint(const Color& color) override;
 
@@ -70,17 +76,24 @@ namespace BansheeEngine
 		/** @copydoc GUIElementContainer::styleUpdated */
 		void styleUpdated() override;
 
-		/**	Triggered when the input box value changes. */
-		void valueChanged(const WString& newValue);
+		/**	Triggered when the input box value changes definitively. */
+		void inputBoxValueChanged(bool confirmed = true);
+
+		/**	Triggered when the input box value is changing. */
+		void inputBoxValueChanging(const WString& newValue);
 
 		/**	Triggered when the slider is moved. */
 		void sliderChanged(float newValue);
 
+		/**	Triggers when the input box receives or loses keyboard focus. */
+		void inputBoxFocusChanged(bool focus);
+
 		/**	Callback that checks can the provided string be	converted to a floating point value. */
 		static bool floatFilter(const WString& str);
 
 		GUIInputBox* mInputBox;
 		GUISliderHorz* mSlider;
+		bool mHasInputFocus;
 	};
 
 	/** @} */

+ 25 - 10
Source/BansheeEditor/Source/BsGUIFloatField.cpp

@@ -21,12 +21,12 @@ namespace BansheeEngine
 		const String& style, const GUIDimensions& dimensions, bool withLabel)
 		: TGUIField(dummy, labelContent, labelWidth, style, dimensions, withLabel), mInputBox(nullptr), mValue(0.0f)
 		, mLastDragPos(0), mMinValue(std::numeric_limits<float>::lowest()), mMaxValue(std::numeric_limits<float>::max())
-		, mIsDragging(false), mHasInputFocus(false)
+		, mIsDragging(false), mHasInputFocus(false), mStep(0.0f)
 	{
 		mInputBox = GUIInputBox::create(false, GUIOptions(GUIOption::flexibleWidth()), getSubStyleName(getInputStyleType()));
 		mInputBox->setFilter(&GUIFloatField::floatFilter);
 
-		mInputBox->onValueChanged.connect(std::bind((void(GUIFloatField::*)(const WString&))&GUIFloatField::valueChanged, this, _1));
+		mInputBox->onValueChanged.connect(std::bind((void(GUIFloatField::*)(const WString&))&GUIFloatField::valueChanging, this, _1));
 		mInputBox->onFocusChanged.connect(std::bind(&GUIFloatField::focusChanged, this, _1));
 		mInputBox->onConfirm.connect(std::bind(&GUIFloatField::inputConfirmed, this));
 
@@ -116,7 +116,7 @@ namespace BansheeEngine
 					if (oldValue != newValue)
 					{
 						setValue(newValue);
-						valueChanged(newValue);
+						valueChanged(newValue, true);
 					}
 				}
 			}
@@ -134,16 +134,18 @@ namespace BansheeEngine
 		return false;
 	}
 
-	void GUIFloatField::setValue(float value)
+	float GUIFloatField::setValue(float value)
 	{
+		if (mStep != 0.0f)
+			value = value - fmod(value, mStep);
 		mValue = Math::clamp(value, mMinValue, mMaxValue);
-
 		// Only update with new value if it actually changed, otherwise
 		// problems can occur when user types in "0." and the field
 		// updates back to "0" effectively making "." unusable
 		float curValue = parseFloat(mInputBox->getText());
 		if (mValue != curValue)
 			mInputBox->setText(toWString(mValue));
+		return mValue;
 	}
 
 	void GUIFloatField::setRange(float min, float max)
@@ -152,6 +154,11 @@ namespace BansheeEngine
 		mMaxValue = max;
 	}
 
+	void GUIFloatField::setStep(float step) 
+	{
+		mStep = step;
+	}
+
 	void GUIFloatField::setTint(const Color& color)
 	{
 		if (mLabel != nullptr)
@@ -188,14 +195,20 @@ namespace BansheeEngine
 		mInputBox->setStyle(getSubStyleName(getInputStyleType()));
 	}
 
-	void GUIFloatField::valueChanged(const WString& newValue)
+	void GUIFloatField::valueChanging(const WString& newValue)
 	{
-		valueChanged(parseFloat(newValue));
+		valueChanged(parseFloat(newValue), false);
 	}
 
-	void GUIFloatField::valueChanged(float newValue)
+	void GUIFloatField::valueChanged(float newValue, bool confirmed)
 	{
-		CmdInputFieldValueChange<GUIFloatField, float>::execute(this, newValue);
+		if (confirmed) {
+			CmdInputFieldValueChange<GUIFloatField, float>::execute(this, newValue);
+		}
+		else
+		{
+			onValueChanged(newValue);
+		}
 	}
 
 	void GUIFloatField::focusChanged(bool focus)
@@ -208,17 +221,19 @@ namespace BansheeEngine
 		else
 		{
 			UndoRedo::instance().popGroup("InputBox");
+			valueChanged(parseFloat(mInputBox->getText()));
 			mHasInputFocus = false;
 		}
 	}
 
 	void GUIFloatField::inputConfirmed()
 	{
+		valueChanged(parseFloat(mInputBox->getText()));
 		onConfirm();
 	}
 
 	bool GUIFloatField::floatFilter(const WString& str)
 	{
-		return std::regex_match(str, std::wregex(L"-?(\\d+(\\.\\d*)?)?"));
+		return std::regex_match(str, std::wregex(L"-?(\\d*(\\.\\d*)?)?"));
 	}
 }

+ 10 - 3
Source/BansheeEditor/Source/BsGUIIntField.cpp

@@ -22,7 +22,7 @@ namespace BansheeEngine
 		const String& style, const GUIDimensions& dimensions, bool withLabel)
 		: TGUIField(dummy, labelContent, labelWidth, style, dimensions, withLabel), mInputBox(nullptr), mValue(0)
 		, mLastDragPos(0), mMinValue(std::numeric_limits<INT32>::lowest())
-		, mMaxValue(std::numeric_limits<INT32>::max()), mIsDragging(false), mIsDragCursorSet(false), mHasInputFocus(false)
+		, mMaxValue(std::numeric_limits<INT32>::max()), mIsDragging(false), mIsDragCursorSet(false), mHasInputFocus(false), mStep(1)
 	{
 		mInputBox = GUIInputBox::create(false, GUIOptions(GUIOption::flexibleWidth()), getSubStyleName(getInputStyleType()));
 		mInputBox->setFilter(&GUIIntField::intFilter);
@@ -160,16 +160,18 @@ namespace BansheeEngine
 		mInputBox->setStyle(getSubStyleName(getInputStyleType()));
 	}
 
-	void GUIIntField::setValue(INT32 value)
+	INT32 GUIIntField::setValue(INT32 value)
 	{
+		if (mStep != 0)
+			mValue = mValue - fmod(mValue, mStep);
 		mValue = Math::clamp(value, mMinValue, mMaxValue);
-
 		// Only update with new value if it actually changed, otherwise
 		// problems can occur when user types in "0." and the field
 		// updates back to "0" effectively making "." unusable
 		float curValue = parseFloat(mInputBox->getText());
 		if (mValue != curValue)
 			mInputBox->setText(toWString(mValue));
+		return mValue;
 	}
 
 	void GUIIntField::setRange(INT32 min, INT32 max)
@@ -178,6 +180,11 @@ namespace BansheeEngine
 		mMaxValue = max;
 	}
 
+	void GUIIntField::setStep(INT32 step)
+	{
+		mStep = step;
+	}
+
 	void GUIIntField::setTint(const Color& color)
 	{
 		if (mLabel != nullptr)

+ 51 - 13
Source/BansheeEditor/Source/BsGUISliderField.cpp

@@ -15,7 +15,7 @@ namespace BansheeEngine
 {
 	GUISliderField::GUISliderField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
 		const String& style, const GUIDimensions& dimensions, bool withLabel)
-		:TGUIField(dummy, labelContent, labelWidth, style, dimensions, withLabel), mInputBox(nullptr), mSlider(nullptr)
+		:TGUIField(dummy, labelContent, labelWidth, style, dimensions, withLabel), mInputBox(nullptr), mSlider(nullptr), mHasInputFocus(false)
 	{
 		mSlider = GUISliderHorz::create(GUIOptions(GUIOption::flexibleWidth()), getSubStyleName(getSliderStyleType()));
 		mSlider->onChanged.connect(std::bind(&GUISliderField::sliderChanged, this, _1));
@@ -23,7 +23,9 @@ namespace BansheeEngine
 		mInputBox = GUIInputBox::create(false, GUIOptions(GUIOption::fixedWidth(75)), getSubStyleName(getInputStyleType()));
 		mInputBox->setFilter(&GUISliderField::floatFilter);
 
-		mInputBox->onValueChanged.connect(std::bind((void(GUISliderField::*)(const WString&))&GUISliderField::valueChanged, this, _1));
+		mInputBox->onValueChanged.connect(std::bind((void(GUISliderField::*)(const WString&))&GUISliderField::inputBoxValueChanging, this, _1));
+		mInputBox->onConfirm.connect(std::bind(&GUISliderField::inputBoxValueChanged, this, true));
+		mInputBox->onFocusChanged.connect(std::bind(&GUISliderField::inputBoxFocusChanged, this, _1));
 
 		mLayout->addElement(mSlider);
 		mLayout->addNewElement<GUIFixedSpace>(5);
@@ -43,7 +45,12 @@ namespace BansheeEngine
 		return mSlider->getValue();
 	}
 
-	void GUISliderField::setValue(float value)
+	float GUISliderField::getStep() const
+	{
+		return mSlider->getStep();
+	}
+
+	float GUISliderField::setValue(float value)
 	{
 		float origValue = mSlider->getValue();
 		if (origValue != value)
@@ -57,6 +64,7 @@ namespace BansheeEngine
 		float curValue = parseFloat(mInputBox->getText());
 		if (clampedValue != curValue)
 			mInputBox->setText(toWString(clampedValue));
+		return clampedValue;
 	}
 
 	void GUISliderField::setRange(float min, float max)
@@ -66,7 +74,7 @@ namespace BansheeEngine
 
 	void GUISliderField::setStep(float step)
 	{
-		mSlider->setStep(step);
+		mSlider->setStep(step / (mSlider->getRangeMaximum() - mSlider->getRangeMinimum()));
 	}
 
 	void GUISliderField::setTint(const Color& color)
@@ -79,10 +87,10 @@ namespace BansheeEngine
 
 	void GUISliderField::_setValue(float value, bool triggerEvent)
 	{
-		setValue(value);
+		float clamped = setValue(value);
 
 		if (triggerEvent)
-			onValueChanged(value);
+			onValueChanged(clamped);
 	}
 
 	const String& GUISliderField::getGUITypeName()
@@ -112,22 +120,52 @@ namespace BansheeEngine
 		mInputBox->setStyle(getSubStyleName(getInputStyleType()));
 	}
 
-	void GUISliderField::valueChanged(const WString& newValue)
+	void GUISliderField::inputBoxValueChanging(const WString& newValue) {
+		inputBoxValueChanged(false);
+	}
+
+	void GUISliderField::inputBoxValueChanged(bool confirmed)
 	{
-		float newFloatValue = parseFloat(newValue);
+		float newFloatValue = parseFloat(mInputBox->getText());
+		if (mSlider->getValue() != newFloatValue) {
+			if (confirmed) {
+				CmdInputFieldValueChange<GUISliderField, float>::execute(this, newFloatValue);
+			}
+			else
+			{
+				mSlider->setValue(newFloatValue);
+				onValueChanged(mSlider->getValue());
+			}
+		}
+		else if (mInputBox->getText() == L"" && confirmed) //Avoid leaving label blank
+		{
+			mInputBox->setText(L"0");
+		}
+	}
 
-		CmdInputFieldValueChange<GUISliderField, float>::execute(this, newFloatValue);
+	void GUISliderField::inputBoxFocusChanged(bool focus)
+	{
+		if (focus)
+		{
+			UndoRedo::instance().pushGroup("InputBox");
+			mHasInputFocus = true;
+		}
+		else
+		{
+			UndoRedo::instance().popGroup("InputBox");
+			inputBoxValueChanged();
+			mHasInputFocus = false;
+		}
 	}
 
 	void GUISliderField::sliderChanged(float newValue)
 	{
-		setValue(mSlider->getValue());
-
-		onValueChanged(newValue);
+		_setValue(newValue, true);
 	}
 
 	bool GUISliderField::floatFilter(const WString& str)
 	{
-		return std::regex_match(str, std::wregex(L"-?(\\d+(\\.\\d*)?)?"));
+		bool result = std::regex_match(str, std::wregex(L"-?(\\d*(\\.\\d*)?)?"));
+		return result;
 	}
 }

+ 9 - 0
Source/BansheeEngine/Include/BsGUISlider.h

@@ -50,12 +50,21 @@ namespace BansheeEngine
 		 */
 		void setRange(float min, float max);
 
+		/** Returns the minimum value of the slider */
+		float getRangeMinimum() const;
+
+		/** Returns the maximum value of the slider */
+		float getRangeMaximum() const;
+
 		/**
 		 * Sets a step that defines the minimal increment the value can be increased/decreased by. Set to zero to have no
 		 * step.
 		 */
 		void setStep(float step);
 
+		/** Gets the minimum percentual variation of the handle position */
+		float getStep() const;
+
 		/** @copydoc GUIElement::setTint */
 		virtual void setTint(const Color& color) override;
 

+ 3 - 0
Source/BansheeEngine/Include/BsGUISliderHandle.h

@@ -56,6 +56,9 @@ namespace BansheeEngine
 		/**	Gets the current position of the handle, in percent ranging [0.0f, 1.0f]. */
 		float getHandlePos() const;
 
+		/** Gets the minimum percentual variation of the handle position */
+		float getStep() const;
+
 		/**	Returns the position of the slider handle, in pixels. Relative to this object. */
 		INT32 getHandlePosPx() const;
 

+ 15 - 0
Source/BansheeEngine/Source/BsGUISlider.cpp

@@ -169,11 +169,26 @@ namespace BansheeEngine
 		mMaxRange = max;
 	}
 
+	float GUISlider::getRangeMaximum() const
+	{
+		return mMaxRange;
+	}
+
+	float GUISlider::getRangeMinimum() const
+	{
+		return mMinRange;
+	}
+
 	void GUISlider::setStep(float step)
 	{
 		mSliderHandle->setStep(step);
 	}
 
+	float GUISlider::getStep() const 
+	{
+		return mSliderHandle->getStep();
+	}
+
 	void GUISlider::setTint(const Color& color)
 	{
 		mBackground->setTint(color);

+ 48 - 41
Source/BansheeEngine/Source/BsGUISliderHandle.cpp

@@ -1,5 +1,6 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "math.h"
 #include "BsGUISliderHandle.h"
 #include "BsImageSprite.h"
 #include "BsGUISkin.h"
@@ -48,8 +49,11 @@ namespace BansheeEngine
 	void GUISliderHandle::_setHandlePos(float pct)
 	{
 		float maxPct = 1.0f;
-		if (mStep > 0.0f)
+		if (mStep > 0.0f && pct < maxPct)
+		{
+			pct = (pct + mStep * 0.5f) - fmod(pct + mStep * 0.5f, mStep);
 			maxPct = Math::floor(1.0f / mStep) * mStep;
+		}
 
 		mPctHandlePos = Math::clamp(pct, 0.0f, maxPct);
 	}
@@ -59,6 +63,11 @@ namespace BansheeEngine
 		return mPctHandlePos;;
 	}
 
+	float GUISliderHandle::getStep() const
+	{
+		return mStep;
+	}
+
 	void GUISliderHandle::setStep(float step)
 	{
 		mStep = Math::clamp01(step);
@@ -212,6 +221,7 @@ namespace BansheeEngine
 						handlePosPx = (float)(ev.getPosition().y - (INT32)mLayoutData.area.y - mHandleSize * 0.5f);
 
 					setHandlePosPx((INT32)handlePosPx);
+					onHandleMoved(mPctHandlePos);
 				}
 
 				if (mHorizontal)
@@ -224,7 +234,7 @@ namespace BansheeEngine
 					INT32 top = (INT32)mLayoutData.area.y + getHandlePosPx();
 					mDragStartPos = ev.getPosition().y - top;
 				}
-
+				
 				mHandleDragged = true;
 			}
 
@@ -279,44 +289,46 @@ namespace BansheeEngine
 				else
 					mState = State::Normal;
 
-				// If we clicked above or below the scroll handle, scroll by one page
-				INT32 handlePosPx = getHandlePosPx();
-				if (!mJumpOnClick)
+				if (!mHandleDragged) 
 				{
-					UINT32 stepSizePx = 0;
-					if (mStep > 0.0f)
-						stepSizePx = (UINT32)(mStep * getMaxSize());
-					else
-						stepSizePx = mHandleSize;
-
-					INT32 handleOffset = 0;
-					if (mHorizontal)
+					// If we clicked above or below the scroll handle, scroll by one page
+					INT32 handlePosPx = getHandlePosPx();
+					if (!mJumpOnClick)
 					{
-						INT32 handleLeft = (INT32)mLayoutData.area.x + handlePosPx;
-						INT32 handleRight = handleLeft + mHandleSize;
-
-						if (ev.getPosition().x < handleLeft)
-							handleOffset -= stepSizePx;
-						else if (ev.getPosition().x > handleRight)
-							handleOffset += stepSizePx;
-					}
-					else
-					{
-						INT32 handleTop = (INT32)mLayoutData.area.y + handlePosPx;
-						INT32 handleBottom = handleTop + mHandleSize;
-
-						if (ev.getPosition().y < handleTop)
-							handleOffset -= stepSizePx;
-						else if (ev.getPosition().y > handleBottom)
-							handleOffset += stepSizePx;
+						UINT32 stepSizePx = 0;
+						if (mStep > 0.0f)
+							stepSizePx = (UINT32)(mStep * getMaxSize());
+						else
+							stepSizePx = mHandleSize;
+
+						INT32 handleOffset = 0;
+						if (mHorizontal)
+						{
+							INT32 handleLeft = (INT32)mLayoutData.area.x + handlePosPx;
+							INT32 handleRight = handleLeft + mHandleSize;
+
+							if (ev.getPosition().x < handleLeft)
+								handleOffset -= stepSizePx;
+							else if (ev.getPosition().x > handleRight)
+								handleOffset += stepSizePx;
+						}
+						else
+						{
+							INT32 handleTop = (INT32)mLayoutData.area.y + handlePosPx;
+							INT32 handleBottom = handleTop + mHandleSize;
+
+							if (ev.getPosition().y < handleTop)
+								handleOffset -= stepSizePx;
+							else if (ev.getPosition().y > handleBottom)
+								handleOffset += stepSizePx;
+						}
+
+						handlePosPx += handleOffset;
 					}
 
-					handlePosPx += handleOffset;
+					setHandlePosPx(handlePosPx);
+					onHandleMoved(mPctHandlePos);
 				}
-
-				setHandlePosPx(handlePosPx);
-				onHandleMoved(mPctHandlePos);
-
 				mHandleDragged = false;
 				_markLayoutAsDirty();
 			}
@@ -329,7 +341,6 @@ namespace BansheeEngine
 			if (!_isDisabled())
 			{
 				mHandleDragged = false;
-
 				if (mMouseOverHandle)
 					mState = State::Hover;
 				else
@@ -375,11 +386,7 @@ namespace BansheeEngine
 	void GUISliderHandle::setHandlePosPx(INT32 pos)
 	{
 		float maxScrollAmount = (float)getMaxSize() - mHandleSize;
-		float maxPct = 1.0f;
-		if (mStep > 0.0f)
-			maxPct = Math::floor(1.0f / mStep) * mStep;
-
-		mPctHandlePos = Math::clamp(pos / maxScrollAmount, 0.0f, maxPct);
+		_setHandlePos(pos / maxScrollAmount);
 	}
 
 	UINT32 GUISliderHandle::getMaxSize() const

+ 16 - 0
Source/MBansheeEditor/GUI/GUIFloatField.cs

@@ -40,6 +40,16 @@ namespace BansheeEditor
             set { Internal_SetValue(mCachedPtr, value); }
         }
 
+        /// <summary>
+        /// Minimum change of the field.
+        /// </summary>
+        public float Step
+        {
+            get { return Internal_GetStep(mCachedPtr); }
+
+            set { Internal_SetStep(mCachedPtr, value); }
+        }
+
         /// <summary>
         /// Checks does the element currently has input focus. Input focus means the element has an input caret displayed
         /// and will accept input from the keyboard.
@@ -139,6 +149,12 @@ namespace BansheeEditor
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetRange(IntPtr nativeInstance, float min, float max);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetStep(IntPtr nativeInstance, float step);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetStep(IntPtr nativeInstance);
     }
 
     /** @} */

+ 17 - 1
Source/MBansheeEditor/GUI/GUIIntField.cs

@@ -40,6 +40,16 @@ namespace BansheeEditor
             set { Internal_SetValue(mCachedPtr, value); }
         }
 
+        /// <summary>
+        /// Minimum change of the field.
+        /// </summary>
+        public int Step
+        {
+            get { return Internal_GetStep(mCachedPtr); }
+
+            set { Internal_SetStep(mCachedPtr, value); }
+        }
+
         /// <summary>
         /// Checks does the element currently has input focus. Input focus means the element has an input caret displayed
         /// and will accept input from the keyboard.
@@ -129,7 +139,7 @@ namespace BansheeEditor
         private static extern void Internal_GetValue(IntPtr nativeInstance, out int value);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetValue(IntPtr nativeInstance, int value);
+        private static extern int Internal_SetValue(IntPtr nativeInstance, int value);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_HasInputFocus(IntPtr nativeInstance, out bool value);
@@ -139,6 +149,12 @@ namespace BansheeEditor
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetTint(IntPtr nativeInstance, ref Color color);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetStep(IntPtr nativeInstance, int step);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int Internal_GetStep(IntPtr nativeInstance);
     }
 
     /** @} */

+ 31 - 10
Source/MBansheeEditor/GUI/GUISliderField.cs

@@ -31,6 +31,16 @@ namespace BansheeEditor
             set { Internal_SetValue(mCachedPtr, value); }
         }
 
+        /// <summary>
+        /// A step value that determines the minimal increment the slider can be increased or decreased by.
+        /// </summary>
+        /// <param name="step">Step value in percent if range is not defined, otherwise in same units as the range.</param>
+        public float Step
+        {
+            get { return Internal_GetStep(mCachedPtr); }
+            set { Internal_SetStep(mCachedPtr, value); }
+        }
+
         /// <summary>
         /// Creates a new slider field element with a label.
         /// </summary>
@@ -64,6 +74,20 @@ namespace BansheeEditor
             Internal_CreateInstance(this, min, max, null, 0, style, options, false);
         }
 
+        /// <summary>
+        /// Checks does the element currently has input focus. Input focus means the element has an input caret displayed
+        /// and will accept input from the keyboard.
+        /// </summary>
+        public bool HasInputFocus
+        {
+            get
+            {
+                bool value;
+                Internal_HasInputFocus(mCachedPtr, out value);
+                return value;
+            }
+        }
+
         /// <summary>
         /// Colors the element with a specific tint.
         /// </summary>
@@ -84,15 +108,6 @@ namespace BansheeEditor
             Internal_SetRange(mCachedPtr, min, max);
         }
 
-        /// <summary>
-        /// Sets a step value that determines the minimal increment the slider can be increased or decreased by.
-        /// </summary>
-        /// <param name="step">Step value in percent if range is not defined, otherwise in same units as the range.</param>
-        public void SetStep(float step)
-        {
-            Internal_SetStep(mCachedPtr, step);
-        }
-
         /// <summary>
         /// Triggered by the runtime when the value of the float field changes.
         /// </summary>
@@ -111,7 +126,13 @@ namespace BansheeEditor
         private static extern float Internal_GetValue(IntPtr nativeInstance);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetValue(IntPtr nativeInstance, float value);
+        private static extern float Internal_GetStep(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_SetValue(IntPtr nativeInstance, float value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_HasInputFocus(IntPtr nativeInstance, out bool focus);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetTint(IntPtr nativeInstance, ref Color color);

+ 7 - 0
Source/MBansheeEditor/MBansheeEditor.csproj

@@ -80,6 +80,13 @@
     <Compile Include="Inspectors\SliderJointInspector.cs" />
     <Compile Include="Inspectors\SphereColliderInspector.cs" />
     <Compile Include="Inspectors\SphericalJointInspector.cs" />
+    <Compile Include="Windows\Inspector\Style\InspectableFieldRangeStyle.cs" />
+    <Compile Include="Windows\Inspector\Style\InspectableFieldStepStyle.cs" />
+    <Compile Include="Windows\Inspector\Style\InspectableFieldStyle.cs" />
+    <Compile Include="Windows\Inspector\InspectableRangedField.cs" />
+    <Compile Include="Windows\Inspector\InspectableRangedFloat.cs" />
+    <Compile Include="Windows\Inspector\InspectableRangedInt.cs" />
+    <Compile Include="Windows\Inspector\Style\InspectableFieldStyleInfo.cs" />
     <Compile Include="Windows\LogWindow.cs" />
     <Compile Include="Window\DefaultSize.cs" />
     <Compile Include="Windows\DialogBox.cs" />

+ 2 - 2
Source/MBansheeEditor/Windows/Inspector/GenericInspector.cs

@@ -29,10 +29,10 @@ namespace BansheeEditor
                 {
                     if (!field.Inspectable)
                         continue;
-
+                    
                     string path = field.Name;
                     InspectableField inspectableField = InspectableField.CreateInspectable(this, field.Name, path,
-                        currentIndex, 0, new InspectableFieldLayout(Layout), field.GetProperty());
+                        currentIndex, 0, new InspectableFieldLayout(Layout), field.GetProperty(), InspectableFieldStyle.Create(field));
 
                     inspectableFields.Add(inspectableField);
                     isEmpty = false;

+ 18 - 3
Source/MBansheeEditor/Windows/Inspector/InspectableField.cs

@@ -129,10 +129,11 @@ namespace BansheeEditor
         ///                     contain other fields, in which case you should increase this value by one.</param>
         /// <param name="layout">Parent layout that all the field elements will be added to.</param>
         /// <param name="property">Serializable property referencing the array whose contents to display.</param>
+        /// <param name="style">Information related the field style</param>
         /// <returns>Inspectable field implementation that can be used for displaying the GUI for a serializable property
         ///          of the provided type.</returns>
         public static InspectableField CreateInspectable(Inspector parent, string title, string path, int layoutIndex, 
-            int depth, InspectableFieldLayout layout, SerializableProperty property)
+            int depth, InspectableFieldLayout layout, SerializableProperty property, InspectableFieldStyleInfo style = null)
         {
             InspectableField field = null;
 
@@ -146,10 +147,24 @@ namespace BansheeEditor
                 switch (property.Type)
                 {
                     case SerializableProperty.FieldType.Int:
-                        field = new InspectableInt(parent, title, path, depth, layout, property);
+                        if (style?.RangeStyle == null || !style.RangeStyle.Slider)
+                        {
+                            field = new InspectableInt(parent, title, path, depth, layout, property, style);
+                        }
+                        else
+                        {
+                            field = new InspectableRangedInt(parent, title, path, depth, layout, property, style);
+                        }
                         break;
                     case SerializableProperty.FieldType.Float:
-                        field = new InspectableFloat(parent, title, path, depth, layout, property);
+                        if (style?.RangeStyle == null || !style.RangeStyle.Slider)
+                        {
+                            field = new InspectableFloat(parent, title, path, depth, layout, property, style);
+                        }
+                        else
+                        {
+                            field = new InspectableRangedFloat(parent, title, path, depth, layout, property, style);
+                        }
                         break;
                     case SerializableProperty.FieldType.Bool:
                         field = new InspectableBool(parent, title, path, depth, layout, property);

+ 11 - 2
Source/MBansheeEditor/Windows/Inspector/InspectableFloat.cs

@@ -15,6 +15,7 @@ namespace BansheeEditor
     {
         private GUIFloatField guiFloatField;
         private InspectableState state;
+        private InspectableFieldStyleInfo style;
 
         /// <summary>
         /// Creates a new inspectable float GUI for the specified property.
@@ -26,11 +27,12 @@ namespace BansheeEditor
         ///                     contain other fields, in which case you should increase this value by one.</param>
         /// <param name="layout">Parent layout that all the field elements will be added to.</param>
         /// <param name="property">Serializable property referencing the array whose contents to display.</param>
+        /// <param name="style">Contains information about the field style</param>
         public InspectableFloat(Inspector parent, string title, string path, int depth, InspectableFieldLayout layout, 
-            SerializableProperty property)
+            SerializableProperty property, InspectableFieldStyleInfo style)
             : base(parent, title, path, SerializableProperty.FieldType.Float, depth, layout, property)
         {
-
+            this.style = style;
         }
 
         /// <inheritoc/>
@@ -39,6 +41,13 @@ namespace BansheeEditor
             if (property != null)
             {
                 guiFloatField = new GUIFloatField(new GUIContent(title));
+                if (style != null)
+                {
+                    if (style.StepStyle != null && style.StepStyle.Step != 0)
+                        guiFloatField.Step = style.StepStyle.Step;
+                    if (style.RangeStyle != null)
+                        guiFloatField.SetRange(style.RangeStyle.Min, style.RangeStyle.Max);
+                }
                 guiFloatField.OnChanged += OnFieldValueChanged;
                 guiFloatField.OnConfirmed += OnFieldValueConfirm;
                 guiFloatField.OnFocusLost += OnFieldValueConfirm;

+ 12 - 2
Source/MBansheeEditor/Windows/Inspector/InspectableInt.cs

@@ -1,5 +1,6 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+
 using BansheeEngine;
 
 namespace BansheeEditor
@@ -15,6 +16,7 @@ namespace BansheeEditor
     {
         private GUIIntField guiIntField;
         private InspectableState state;
+        private InspectableFieldStyleInfo style;
 
         /// <summary>
         /// Creates a new inspectable integer GUI for the specified property.
@@ -26,11 +28,12 @@ namespace BansheeEditor
         ///                     contain other fields, in which case you should increase this value by one.</param>
         /// <param name="layout">Parent layout that all the field elements will be added to.</param>
         /// <param name="property">Serializable property referencing the array whose contents to display.</param>
+        /// <param name="style">Contains information about the field style</param>
         public InspectableInt(Inspector parent, string title, string path, int depth, InspectableFieldLayout layout, 
-            SerializableProperty property)
+            SerializableProperty property, InspectableFieldStyleInfo style)
             : base(parent, title, path, SerializableProperty.FieldType.Int, depth, layout, property)
         {
-
+            this.style = style;
         }
 
         /// <inheritdoc/>
@@ -39,6 +42,13 @@ namespace BansheeEditor
             if (property != null)
             {
                 guiIntField = new GUIIntField(new GUIContent(title));
+                if (style != null)
+                {
+                    if (style.StepStyle != null && style.StepStyle.Step != 0)
+                        guiIntField.Step = (int) style.StepStyle.Step;
+                    if (style.RangeStyle != null)
+                        guiIntField.SetRange((int) style.RangeStyle.Min, (int) style.RangeStyle.Max);
+                }
                 guiIntField.OnChanged += OnFieldValueChanged;
                 guiIntField.OnConfirmed += OnFieldValueConfirm;
                 guiIntField.OnFocusLost += OnFieldValueConfirm;

+ 1 - 1
Source/MBansheeEditor/Windows/Inspector/InspectableList.cs

@@ -291,7 +291,7 @@ namespace BansheeEditor
 
                 string entryPath = listParent.Path + "[" + SeqIndex + "]";
                 field = CreateInspectable(listParent.Inspector, SeqIndex + ".", entryPath, 0, Depth + 1,
-                    new InspectableFieldLayout(layout), property);
+                    new InspectableFieldLayout(layout), property, new InspectableFieldStyleInfo());
 
                 return field.GetTitleLayout();
             }

+ 1 - 1
Source/MBansheeEditor/Windows/Inspector/InspectableObject.cs

@@ -162,7 +162,7 @@ namespace BansheeEditor
                            string childPath = path + "/" + field.Name;
 
                            InspectableField inspectable = CreateInspectable(parent, field.Name, childPath,
-                               currentIndex, depth + 1, new InspectableFieldLayout(guiContentLayout), field.GetProperty());
+                               currentIndex, depth + 1, new InspectableFieldLayout(guiContentLayout), field.GetProperty(), InspectableFieldStyle.Create(field));
 
                            children.Add(inspectable);
                            currentIndex += inspectable.GetNumLayoutElements();

+ 37 - 0
Source/MBansheeEditor/Windows/Inspector/InspectableRangedField.cs

@@ -0,0 +1,37 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /** @addtogroup Inspector
+     *  @{
+     */
+
+    /// <summary>
+    /// IsnpectableRangedField is a <see cref="InspectableField"/> that has a Range attribute and must be rendered as a slider.
+    /// </summary>
+    public abstract class InspectableRangedField : InspectableField
+    {
+        protected InspectableFieldStyleInfo style;
+        /// <summary>
+        /// Creates a new inspectable ranged field GUI for the specified property.
+        /// </summary>
+        /// <param name="parent">Parent Inspector this field belongs to.</param>
+        /// <param name="title">Name of the property, or some other value to set as the title.</param>
+        /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param>
+        /// <param name="type">Type of property this field will be used for displaying.</param>
+        /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may
+        ///                     contain other fields, in which case you should increase this value by one.</param>
+        /// <param name="layout">Parent layout that all the field elements will be added to.</param>
+        /// <param name="property">Serializable property referencing the array whose contents to display.</param>
+        /// <param name="style">Contains information about the field style</param>
+        public InspectableRangedField(Inspector parent, string title, string path, SerializableProperty.FieldType type,
+            int depth, InspectableFieldLayout layout, SerializableProperty property, InspectableFieldStyleInfo style) : base(parent, title, path, type, depth, layout, property)
+        {
+            this.style = style;
+        }
+    }
+
+    /** @} */
+}

+ 86 - 0
Source/MBansheeEditor/Windows/Inspector/InspectableRangedFloat.cs

@@ -0,0 +1,86 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /** @addtogroup Inspector
+     *  @{
+     */
+
+    /// <summary>
+    /// Displays GUI for a serializable property containing a floating point value.
+    /// </summary>
+    public class InspectableRangedFloat : InspectableRangedField
+    {
+        private GUISliderField guiFloatField;
+        private InspectableState state;
+
+        /// <summary>
+        /// Creates a new inspectable float GUI for the specified property with a range.
+        /// </summary>
+        /// <param name="parent">Parent Inspector this field belongs to.</param>
+        /// <param name="title">Name of the property, or some other value to set as the title.</param>
+        /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param>
+        /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may
+        ///                     contain other fields, in which case you should increase this value by one.</param>
+        /// <param name="layout">Parent layout that all the field elements will be added to.</param>
+        /// <param name="property">Serializable property referencing the array whose contents to display.</param>
+        /// <param name="style">Contains information about the field style.</param>
+        public InspectableRangedFloat(Inspector parent, string title, string path, int depth, InspectableFieldLayout layout,
+            SerializableProperty property, InspectableFieldStyleInfo style)
+            : base(parent, title, path, SerializableProperty.FieldType.Float, depth, layout, property, style)
+        {
+
+        }
+
+        /// <inheritoc/>
+        protected internal override void Initialize(int layoutIndex)
+        {
+            if (property != null)
+            {
+                guiFloatField = new GUISliderField(style.RangeStyle.Min, style.RangeStyle.Max, new GUIContent(title));
+                if (style != null && style.StepStyle != null && style.StepStyle.Step != 0)
+                    guiFloatField.Step = style.StepStyle.Step;
+                guiFloatField.OnChanged += OnFieldValueChanged;
+                guiFloatField.OnFocusLost += OnFieldValueConfirm;
+
+                layout.AddElement(layoutIndex, guiFloatField);
+            }
+        }
+
+        /// <inheritdoc/>
+        public override InspectableState Refresh(int layoutIndex)
+        {
+            if (guiFloatField != null && !guiFloatField.HasInputFocus)
+                guiFloatField.Value = property.GetValue<float>();
+
+            InspectableState oldState = state;
+            if (state.HasFlag(InspectableState.Modified))
+                state = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Triggered when the user inputs a new floating point value.
+        /// </summary>
+        /// <param name="newValue">New value of the float field.</param>
+        private void OnFieldValueChanged(float newValue)
+        {
+            property.SetValue(newValue);
+            state |= InspectableState.ModifyInProgress;
+        }
+
+        /// <summary>
+        /// Triggered when the user confirms input in the float field.
+        /// </summary>
+        private void OnFieldValueConfirm()
+        {
+            if (state.HasFlag(InspectableState.ModifyInProgress))
+                state |= InspectableState.Modified;
+        }
+    }
+
+    /** @} */
+}

+ 86 - 0
Source/MBansheeEditor/Windows/Inspector/InspectableRangedInt.cs

@@ -0,0 +1,86 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /** @addtogroup Inspector
+     *  @{
+     */
+
+    /// <summary>
+    /// Displays GUI for a serializable property containing an integer value with a range.
+    /// </summary>
+    public class InspectableRangedInt : InspectableRangedField
+    {
+        private GUISliderField guiIntField;
+        private InspectableState state;
+
+        /// <summary>
+        /// Creates a new inspectable float GUI for the specified property with a range.
+        /// </summary>
+        /// <param name="parent">Parent Inspector this field belongs to.</param>
+        /// <param name="title">Name of the property, or some other value to set as the title.</param>
+        /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param>
+        /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may
+        ///                     contain other fields, in which case you should increase this value by one.</param>
+        /// <param name="layout">Parent layout that all the field elements will be added to.</param>
+        /// <param name="property">Serializable property referencing the array whose contents to display.</param>
+        /// <param name="style">Information about the range of the field.</param>
+        public InspectableRangedInt(Inspector parent, string title, string path, int depth, InspectableFieldLayout layout,
+            SerializableProperty property, InspectableFieldStyleInfo style)
+            : base(parent, title, path, SerializableProperty.FieldType.Float, depth, layout, property, style)
+        {
+
+        }
+
+        /// <inheritoc/>
+        protected internal override void Initialize(int layoutIndex)
+        {
+            if (property != null)
+            {
+                guiIntField = new GUISliderField(style.RangeStyle.Min, style.RangeStyle.Max, new GUIContent(title));
+                if (style != null && style.StepStyle != null && style.StepStyle.Step != 0)
+                    guiIntField.Step = style.StepStyle.Step;
+                guiIntField.OnChanged += OnFieldValueChanged;
+                guiIntField.OnFocusLost += OnFieldValueConfirm;
+
+                layout.AddElement(layoutIndex, guiIntField);
+            }
+        }
+
+        /// <inheritdoc/>
+        public override InspectableState Refresh(int layoutIndex)
+        {
+            if (guiIntField != null && !guiIntField.HasInputFocus)
+                guiIntField.Value = property.GetValue<float>();
+
+            InspectableState oldState = state;
+            if (state.HasFlag(InspectableState.Modified))
+                state = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Triggered when the user inputs a new integer value.
+        /// </summary>
+        /// <param name="newValue">New value of the float field.</param>
+        private void OnFieldValueChanged(float newValue)
+        {
+            property.SetValue(newValue);
+            state |= InspectableState.ModifyInProgress;
+        }
+
+        /// <summary>
+        /// Triggered when the user confirms input in the int field.
+        /// </summary>
+        private void OnFieldValueConfirm()
+        {
+            if (state.HasFlag(InspectableState.ModifyInProgress))
+                state |= InspectableState.Modified;
+        }
+    }
+
+    /** @} */
+}

+ 33 - 0
Source/MBansheeEditor/Windows/Inspector/Style/InspectableFieldRangeStyle.cs

@@ -0,0 +1,33 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Contains info about the range of values a field can store.
+    /// </summary>
+    public sealed class InspectableFieldRangeStyle : InspectableFieldStyle
+    {
+        public InspectableFieldRangeStyle(float min, float max, bool slider)
+        {
+            this.Max = max;
+            this.Min = min;
+            this.Slider = slider;
+        }
+
+        /// <summary>
+        /// The maximum value the field can be assigned.
+        /// </summary>
+        public float Max { get; set; }
+
+        /// <summary>
+        /// The minimum value the field can be assigned.
+        /// </summary>
+        public float Min { get; set; }
+
+        /// <summary>
+        /// Whether the field is rendered as a slider.
+        /// </summary>
+        public bool Slider { get; set; }
+    }
+}

+ 22 - 0
Source/MBansheeEditor/Windows/Inspector/Style/InspectableFieldStepStyle.cs

@@ -0,0 +1,22 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Contains information about the minimum change allowed to a field value.
+    /// </summary>
+    public sealed class InspectableFieldStepStyle : InspectableFieldStyle
+    {
+
+        public InspectableFieldStepStyle(float step)
+        {
+            this.Step = step;
+        }
+
+        /// <summary>
+        /// Minimum change of the field. Every change will be rounded to a multiple of this value.
+        /// </summary>
+        public float Step { get; set; }
+    }
+}

+ 27 - 0
Source/MBansheeEditor/Windows/Inspector/Style/InspectableFieldStyle.cs

@@ -0,0 +1,27 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Contains style information about inspectable items.
+    /// </summary>
+    public abstract class InspectableFieldStyle
+    {
+        /// <summary>
+        /// Creates all the relevant style information for a SerializableField.
+        /// </summary>
+        /// <param name="field">A SerializableField.</param>
+        /// <returns>Style information.</returns>
+        public static InspectableFieldStyleInfo Create(SerializableField field)
+        {
+            var styleInfo = new InspectableFieldStyleInfo();
+
+            styleInfo.RangeStyle = field.IsRanged? new InspectableFieldRangeStyle(field.RangeMinimum, field.RangeMaximum, field.IsSlider) : null;
+            styleInfo.StepStyle = field.IsStepped? new InspectableFieldStepStyle(field.Step) : null;
+            return styleInfo;
+        }
+    }
+}

+ 43 - 0
Source/MBansheeEditor/Windows/Inspector/Style/InspectableFieldStyleInfo.cs

@@ -0,0 +1,43 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Contains boolean information about a field style.
+    /// </summary>
+    public enum InstectableFieldStyleFlags
+    {
+        None = 0,
+        UseSlider = 1,
+    }
+
+    /// <summary>
+    /// Contains all the information about a field style.
+    /// </summary>
+    public class InspectableFieldStyleInfo
+    {
+        /// <summary>
+        /// Information about the field range.
+        /// </summary>
+        public InspectableFieldRangeStyle RangeStyle;
+
+        /// <summary>
+        /// Information about the field stepping.
+        /// </summary>
+        public InspectableFieldStepStyle StepStyle;
+
+        /// <summary>
+        /// Boolean information about the field.
+        /// </summary>
+        public InstectableFieldStyleFlags StyleFlags;
+
+        /// <summary>
+        /// Creates an empty set of information about a field style.
+        /// </summary>
+        public InspectableFieldStyleInfo()
+        {
+            
+        }
+    }
+}

+ 62 - 8
Source/MBansheeEngine/GUI/GUISlider.cs

@@ -77,12 +77,30 @@ namespace BansheeEngine
         }
 
         /// <summary>
-        /// Sets a step value that determines the minimal increment the slider can be increased or decreased by.
+        /// The upper bound of the slider range
         /// </summary>
-        /// <param name="step">Step value in percent if range is not defined, otherwise in same units as the range.</param>
-        public void SetStep(float step)
+        /// <returns>The upper bound of the slider range</returns>
+        public float GetRangeMaximum()
         {
-            Internal_SetStep(mCachedPtr, step);
+            return Internal_GetRangeMaximum(mCachedPtr);
+        }
+
+        /// <summary>
+        /// The lower bound of the slider range
+        /// </summary>
+        /// <returns>The lower bound of the slider range</returns>
+        public float GetRangeMinimum()
+        {
+            return Internal_GetRangeMinimum(mCachedPtr);
+        }
+
+        /// <summary>
+        /// A step value that determines the minimal increment the slider can be increased or decreased by.
+        /// </summary>
+        public float Step
+        {
+            get { return Internal_GetStep(mCachedPtr); }
+            set { Internal_SetStep(mCachedPtr, value); }
         }
 
         /// <summary>
@@ -122,9 +140,18 @@ namespace BansheeEngine
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetRange(IntPtr nativeInstance, float min, float max);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetRangeMaximum(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetRangeMinimum(IntPtr nativeInstance);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetStep(IntPtr nativeInstance, float step);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetStep(IntPtr nativeInstance);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetTint(IntPtr nativeInstance, ref Color color);
     }
@@ -197,12 +224,30 @@ namespace BansheeEngine
         }
 
         /// <summary>
-        /// Sets a step value that determines the minimal increment the slider can be increased or decreased by.
+        /// The upper bound of the slider range
         /// </summary>
-        /// <param name="step">Step value in percent if range is not defined, otherwise in same units as the range.</param>
-        public void SetStep(float step)
+        /// <returns>The upper bound of the slider range</returns>
+        public float GetRangeMaximum()
         {
-            Internal_SetStep(mCachedPtr, step);
+            return Internal_GetRangeMaximum(mCachedPtr);
+        }
+
+        /// <summary>
+        /// The lower bound of the slider range
+        /// </summary>
+        /// <returns>The lower bound of the slider range</returns>
+        public float GetRangeMinimum()
+        {
+            return Internal_GetRangeMinimum(mCachedPtr);
+        }
+
+        /// <summary>
+        /// A step value that determines the minimal increment the slider can be increased or decreased by.
+        /// </summary>
+        public float Step
+        {
+            get { return Internal_GetStep(mCachedPtr); }
+            set { Internal_SetStep(mCachedPtr, value); }
         }
 
         /// <summary>
@@ -242,9 +287,18 @@ namespace BansheeEngine
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetRange(IntPtr nativeInstance, float min, float max);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetRangeMaximum(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetRangeMinimum(IntPtr nativeInstance);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetStep(IntPtr nativeInstance, float step);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetStep(IntPtr nativeInstance);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetTint(IntPtr nativeInstance, ref Color color);
     }

+ 1 - 0
Source/MBansheeEngine/MBansheeEngine.csproj

@@ -55,6 +55,7 @@
     <Compile Include="Audio\Interop\NativeAudioSource.cs" />
     <Compile Include="GUI\GUICanvas.cs" />
     <Compile Include="Rendering\PostProcessSettings.cs" />
+    <Compile Include="Serialization\Step.cs" />
     <Compile Include="Utility\AsyncOp.cs" />
     <Compile Include="Math\Bounds.cs" />
     <Compile Include="Utility\Builtin.cs" />

+ 4 - 1
Source/MBansheeEngine/Serialization/Range.cs

@@ -19,14 +19,17 @@ namespace BansheeEngine
         /// </summary>
         /// <param name="min">Minimum boundary of the range to clamp the field value to.</param>
         /// <param name="max">Maximum boundary of the range to clamp the field value to.</param>
-        public Range(float min, float max)
+        /// <param name="slider">Whether the field should be rendered as a slider.</param>
+        public Range(float min, float max, bool slider = true)
         {
             this.min = min;
             this.max = max;
+            this.slider = slider;
         }
 
         private float min;
         private float max;
+        private bool slider;
     }
 
     /** @} */

+ 73 - 2
Source/MBansheeEngine/Serialization/SerializableField.cs

@@ -9,6 +9,17 @@ namespace BansheeEngine
      *  @{
      */
 
+    /// <summary>
+    /// Flags as defined in native code in BsManagedSerializableObjectInfo.h
+    /// </summary>
+    enum SerializableFieldAttributes : byte
+    {
+        Serializable = 0x01,
+        Inspectable = 0x02,
+        Ranged = 0x04,
+        Stepped = 0x08
+    }
+
     /// <summary>
     /// Allows you to access meta-data about field in an object. Similar to Reflection but simpler and faster.
     /// </summary>
@@ -60,12 +71,60 @@ namespace BansheeEngine
             get { return name; }
         }
 
+        /// <summary>
+        /// Returns true if the field accepts a defined range.
+        /// </summary>
+        public bool IsRanged
+        {
+            get { return (flags & (byte)SerializableFieldAttributes.Ranged) != 0; }
+        }
+
+        /// <summary>
+        /// Returns the upper bound of the range.
+        /// </summary>
+        public float RangeMaximum
+        {
+            get { return IsRanged? Internal_GetRangeMaximum(mCachedPtr) : 0; }
+        }
+
+        /// <summary>
+        /// Returns the lower bound of the range.
+        /// </summary>
+        public float RangeMinimum
+        {
+            get { return IsRanged? Internal_GetRangeMinimum(mCachedPtr) : 0; }
+        }
+
+        /// <summary>
+        /// Whether the field is rendered as a slider.
+        /// </summary>
+        public bool IsSlider
+        {
+            get { return (IsRanged && Internal_RenderAsSlider(mCachedPtr)); }
+        }
+
+        /// <summary>
+        /// Whether the field has an associated step value.
+        /// </summary>
+        public bool IsStepped
+        {
+            get { return (flags & (byte)SerializableFieldAttributes.Stepped) != 0; }
+        }
+
+        /// <summary>
+        /// Returns the step of the range
+        /// </summary>
+        public float Step
+        {
+            get { return IsStepped? Internal_GetStep(mCachedPtr) : 0; }
+        }
+
         /// <summary>
         /// Returns true if the field will be visible in the default inspector.
         /// </summary>
         public bool Inspectable
         {
-            get { return (flags & 0x02) != 0; } // Flags as defined in native code in BsManagedSerializableObjectInfo.h
+            get { return (flags & (byte)SerializableFieldAttributes.Inspectable) != 0; }
         }
 
         /// <summary>
@@ -73,7 +132,7 @@ namespace BansheeEngine
         /// </summary>
         public bool Serializable
         {
-            get { return (flags & 0x01) != 0; } // Flags as defined in native code in BsManagedSerializableObjectInfo.h
+            get { return (flags & (byte)SerializableFieldAttributes.Serializable) != 0; }
         }
 
         /// <summary>
@@ -120,6 +179,18 @@ namespace BansheeEngine
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetValue(IntPtr nativeInstance, object instance, object value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetRangeMaximum(IntPtr field);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetRangeMinimum(IntPtr field);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_RenderAsSlider(IntPtr field);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetStep(IntPtr field);
     }
 
     /** @} */

+ 28 - 0
Source/MBansheeEngine/Serialization/Step.cs

@@ -0,0 +1,28 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+
+namespace BansheeEngine
+{
+    /** @addtogroup Serialization
+     *  @{
+     */
+
+    /// <summary>
+    /// Makes an integer or a floating point field vary by multiples of the specified value.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Field)]
+    public sealed class Step : Attribute
+    {
+        /// <summary>
+        /// Creates a new Step attribute.
+        /// </summary>
+        /// <param name="step">Minimum change of the field. Every change will be rounded to a multiple of this value.</param>
+        public Step(float step)
+        {
+            this.step = step;
+        }
+
+        private float step;
+    }
+}

+ 3 - 1
Source/SBansheeEditor/Include/BsScriptGUIFloatField.h

@@ -42,10 +42,12 @@ namespace BansheeEngine
 			MonoString* style, MonoArray* guiOptions, bool withTitle);
 
 		static void internal_getValue(ScriptGUIFloatField* nativeInstance, float* output);
-		static void internal_setValue(ScriptGUIFloatField* nativeInstance, float value);
+		static float internal_setValue(ScriptGUIFloatField* nativeInstance, float value);
 		static void internal_hasInputFocus(ScriptGUIFloatField* nativeInstance, bool* output);
 		static void internal_setTint(ScriptGUIFloatField* nativeInstance, Color* color);
 		static void internal_setRange(ScriptGUIFloatField* nativeInstance, float min, float max);
+		static void internal_setStep(ScriptGUIFloatField* nativeInstance, float step);
+		static float internal_getStep(ScriptGUIFloatField* nativeInstance);
 
 		typedef void(__stdcall *OnChangedThunkDef) (MonoObject*, float, MonoException**);
 		typedef void(__stdcall *OnConfirmedThunkDef) (MonoObject*, MonoException**);

+ 3 - 1
Source/SBansheeEditor/Include/BsScriptGUIIntField.h

@@ -42,10 +42,12 @@ namespace BansheeEngine
 			MonoString* style, MonoArray* guiOptions, bool withTitle);
 
 		static void internal_getValue(ScriptGUIIntField* nativeInstance, INT32* output);
-		static void internal_setValue(ScriptGUIIntField* nativeInstance, INT32 value);
+		static INT32 internal_setValue(ScriptGUIIntField* nativeInstance, INT32 value);
 		static void internal_hasInputFocus(ScriptGUIIntField* nativeInstance, bool* output);
 		static void internal_setRange(ScriptGUIIntField* nativeInstance, INT32 min, INT32 max);
 		static void internal_setTint(ScriptGUIIntField* nativeInstance, Color* color);
+		static void internal_setStep(ScriptGUIIntField* nativeInstance, INT32 step);
+		static INT32 internal_getStep(ScriptGUIIntField* nativeInstance);
 
 		typedef void (__stdcall *OnChangedThunkDef) (MonoObject*, INT32, MonoException**);
 		typedef void(__stdcall *OnConfirmedThunkDef) (MonoObject*, MonoException**);

+ 3 - 1
Source/SBansheeEditor/Include/BsScriptGUISliderField.h

@@ -35,7 +35,9 @@ namespace BansheeEngine
 			MonoString* style, MonoArray* guiOptions, bool withTitle);
 
 		static float internal_getValue(ScriptGUISliderField* nativeInstance);
-		static void internal_setValue(ScriptGUISliderField* nativeInstance, float value);
+		static float internal_getStep(ScriptGUISliderField* nativeInstance);
+		static float internal_setValue(ScriptGUISliderField* nativeInstance, float value);
+		static void internal_hasInputFocus(ScriptGUISliderField* nativeInstance, bool* output);
 		static void internal_setTint(ScriptGUISliderField* nativeInstance, Color* color);
 		static void internal_setRange(ScriptGUISliderField* nativeInstance, float min, float max);
 		static void internal_setStep(ScriptGUISliderField* nativeInstance, float step);

+ 18 - 4
Source/SBansheeEditor/Source/BsScriptGUIFloatField.cpp

@@ -32,6 +32,8 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_HasInputFocus", &ScriptGUIFloatField::internal_hasInputFocus);
 		metaData.scriptClass->addInternalCall("Internal_SetTint", &ScriptGUIFloatField::internal_setTint);
 		metaData.scriptClass->addInternalCall("Internal_SetRange", &ScriptGUIFloatField::internal_setRange);
+		metaData.scriptClass->addInternalCall("Internal_SetStep", &ScriptGUIFloatField::internal_setStep);
+		metaData.scriptClass->addInternalCall("Internal_GetStep", &ScriptGUIFloatField::internal_getStep);
 
 		onChangedThunk = (OnChangedThunkDef)metaData.scriptClass->getMethod("Internal_DoOnChanged", 1)->getThunk();
 		onConfirmedThunk = (OnConfirmedThunkDef)metaData.scriptClass->getMethod("Internal_DoOnConfirmed", 0)->getThunk();
@@ -72,7 +74,7 @@ namespace BansheeEngine
 		*output = floatField->getValue();
 	}
 
-	void ScriptGUIFloatField::internal_setValue(ScriptGUIFloatField* nativeInstance, float value)
+	float ScriptGUIFloatField::internal_setValue(ScriptGUIFloatField* nativeInstance, float value)
 	{
 		GUIFloatField* floatField = static_cast<GUIFloatField*>(nativeInstance->getGUIElement());
 		return floatField->setValue(value);
@@ -84,16 +86,28 @@ namespace BansheeEngine
 		*output = floatField->hasInputFocus();
 	}
 
+	void ScriptGUIFloatField::internal_setRange(ScriptGUIFloatField* nativeInstance, float min, float max)
+	{
+		GUIFloatField* intField = static_cast<GUIFloatField*>(nativeInstance->getGUIElement());
+		intField->setRange(min, max);
+	}
+
 	void ScriptGUIFloatField::internal_setTint(ScriptGUIFloatField* nativeInstance, Color* color)
 	{
 		GUIFloatField* floatField = (GUIFloatField*)nativeInstance->getGUIElement();
 		floatField->setTint(*color);
 	}
 
-	void ScriptGUIFloatField::internal_setRange(ScriptGUIFloatField* nativeInstance, float min, float max)
+	void ScriptGUIFloatField::internal_setStep(ScriptGUIFloatField* nativeInstance, float step)
 	{
-		GUIFloatField* intField = static_cast<GUIFloatField*>(nativeInstance->getGUIElement());
-		intField->setRange(min, max);
+		GUIFloatField* floatField = (GUIFloatField*)nativeInstance->getGUIElement();
+		floatField->setStep(step);
+	}
+
+	float ScriptGUIFloatField::internal_getStep(ScriptGUIFloatField* nativeInstance)
+	{
+		GUIFloatField* floatField = (GUIFloatField*)nativeInstance->getGUIElement();
+		return floatField->getStep();
 	}
 
 	void ScriptGUIFloatField::onChanged(MonoObject* instance, float newValue)

+ 15 - 1
Source/SBansheeEditor/Source/BsScriptGUIIntField.cpp

@@ -32,6 +32,8 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_HasInputFocus", &ScriptGUIIntField::internal_hasInputFocus);
 		metaData.scriptClass->addInternalCall("Internal_SetRange", &ScriptGUIIntField::internal_setRange);
 		metaData.scriptClass->addInternalCall("Internal_SetTint", &ScriptGUIIntField::internal_setTint);
+		metaData.scriptClass->addInternalCall("Internal_SetStep", &ScriptGUIIntField::internal_setStep);
+		metaData.scriptClass->addInternalCall("Internal_GetStep", &ScriptGUIIntField::internal_getStep);
 
 		onChangedThunk = (OnChangedThunkDef)metaData.scriptClass->getMethod("Internal_DoOnChanged", 1)->getThunk();
 		onConfirmedThunk = (OnConfirmedThunkDef)metaData.scriptClass->getMethod("Internal_DoOnConfirmed", 0)->getThunk();
@@ -72,7 +74,7 @@ namespace BansheeEngine
 		*output = intField->getValue();
 	}
 
-	void ScriptGUIIntField::internal_setValue(ScriptGUIIntField* nativeInstance, INT32 value)
+	INT32 ScriptGUIIntField::internal_setValue(ScriptGUIIntField* nativeInstance, INT32 value)
 	{
 		GUIIntField* intField = static_cast<GUIIntField*>(nativeInstance->getGUIElement());
 		return intField->setValue(value);
@@ -96,6 +98,18 @@ namespace BansheeEngine
 		intField->setTint(*color);
 	}
 
+	void ScriptGUIIntField::internal_setStep(ScriptGUIIntField* nativeInstance, INT32 step)
+	{
+		GUIIntField* intField = (GUIIntField*)nativeInstance->getGUIElement();
+		intField->setStep(step);
+	}
+
+	INT32 ScriptGUIIntField::internal_getStep(ScriptGUIIntField* nativeInstance)
+	{
+		GUIIntField* intField = (GUIIntField*)nativeInstance->getGUIElement();
+		return intField->getStep();
+	}
+
 	void ScriptGUIIntField::onChanged(MonoObject* instance, INT32 newValue)
 	{
 		MonoUtil::invokeThunk(onChangedThunk, instance, newValue);

+ 15 - 1
Source/SBansheeEditor/Source/BsScriptGUISliderField.cpp

@@ -28,7 +28,9 @@ namespace BansheeEngine
 	{
 		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptGUISliderField::internal_createInstance);
 		metaData.scriptClass->addInternalCall("Internal_GetValue", &ScriptGUISliderField::internal_getValue);
+		metaData.scriptClass->addInternalCall("Internal_GetStep", &ScriptGUISliderField::internal_getStep);
 		metaData.scriptClass->addInternalCall("Internal_SetValue", &ScriptGUISliderField::internal_setValue);
+		metaData.scriptClass->addInternalCall("Internal_HasInputFocus", &ScriptGUISliderField::internal_hasInputFocus);
 		metaData.scriptClass->addInternalCall("Internal_SetTint", &ScriptGUISliderField::internal_setTint);
 		metaData.scriptClass->addInternalCall("Internal_SetRange", &ScriptGUISliderField::internal_setRange);
 		metaData.scriptClass->addInternalCall("Internal_SetStep", &ScriptGUISliderField::internal_setStep);
@@ -71,12 +73,24 @@ namespace BansheeEngine
 		return sliderField->getValue();
 	}
 
-	void ScriptGUISliderField::internal_setValue(ScriptGUISliderField* nativeInstance, float value)
+	float ScriptGUISliderField::internal_getStep(ScriptGUISliderField* nativeInstance)
+	{
+		GUISliderField* sliderField = static_cast<GUISliderField*>(nativeInstance->getGUIElement());
+		return sliderField->getStep();
+	}
+
+	float ScriptGUISliderField::internal_setValue(ScriptGUISliderField* nativeInstance, float value)
 	{
 		GUISliderField* sliderField = static_cast<GUISliderField*>(nativeInstance->getGUIElement());
 		return sliderField->setValue(value);
 	}
 
+	void ScriptGUISliderField::internal_hasInputFocus(ScriptGUISliderField* nativeInstance, bool* output)
+	{
+		GUISliderField* sliderField = static_cast<GUISliderField*>(nativeInstance->getGUIElement());
+		*output = sliderField->hasInputFocus();
+	}
+
 	void ScriptGUISliderField::internal_setTint(ScriptGUISliderField* nativeInstance, Color* color)
 	{
 		GUISliderField* sliderField = (GUISliderField*)nativeInstance->getGUIElement();

+ 4 - 0
Source/SBansheeEngine/CMakeSources.cmake

@@ -15,6 +15,8 @@ set(BS_SBANSHEEENGINE_INC_NOFILTER
 )
 
 set(BS_SBANSHEEENGINE_SRC_WRAPPERS_GUI
+	"Source/BsScriptRange.cpp"
+	"Source/BsScriptStep.cpp"
 	"Source/BsScriptGUIButton.cpp"
 	"Source/BsScriptGUIContent.cpp"
 	"Source/BsScriptGUIElementStateStyle.cpp"
@@ -144,6 +146,8 @@ set(BS_SBANSHEEENGINE_INC_WRAPPERS
 )
 
 set(BS_SBANSHEEENGINE_INC_WRAPPERS_GUI
+	"Include/BsScriptRange.h"
+	"Include/BsScriptStep.h"
 	"Include/BsScriptGUIButton.h"
 	"Include/BsScriptGUIContent.h"
 	"Include/BsScriptGUIElementStateStyle.h"

+ 15 - 1
Source/SBansheeEngine/Include/BsManagedSerializableObjectInfo.h

@@ -63,7 +63,9 @@ namespace BansheeEngine
 	enum class ScriptFieldFlags
 	{
 		Serializable = 0x01,
-		Inspectable = 0x02
+		Inspectable = 0x02,
+		Range = 0x04,
+		Step = 0x08
 	};
 
 	/**	Contains information about a type of a managed serializable object. */
@@ -256,6 +258,18 @@ namespace BansheeEngine
 		/**	Determines should the field be serialized when serializing the parent object. */
 		bool isSerializable() const { return ((UINT32)mFlags & (UINT32)ScriptFieldFlags::Serializable) != 0; }
 
+		/** Returns the minimum value associated to a Range attribute. */
+		float getRangeMinimum() const;
+
+		/** Returns the maximum value associated to a Range attribute. */
+		float getRangeMaximum() const;
+
+		/** Whether the field should be rendered as a slider. */
+		bool renderAsSlider() const;
+
+		/** Returns the step value of the field. */
+		float getStep() const;
+
 		String mName;
 		UINT32 mFieldId;
 		UINT32 mParentTypeId;

+ 8 - 0
Source/SBansheeEngine/Include/BsScriptAssemblyManager.h

@@ -77,6 +77,12 @@ namespace BansheeEngine
 
 		/**	Gets the managed class for BansheeEngine.SceneObject type. */
 		MonoClass* getSceneObjectClass() const { return mSceneObjectClass; }
+
+		/** Gets the managed class for BansheeEngine.Range attribute */
+		MonoClass* getRangeAttribute() const { return mRangeAttribute; }
+
+		/** Gets the managed class for BansheeEngine.Step attribute */
+		MonoClass* getStepAttribute() const { return mStepAttribute; }
 	private:
 		/**	Deletes all stored managed serializable object infos for all assemblies. */
 		void clearScriptObjects();
@@ -103,6 +109,8 @@ namespace BansheeEngine
 		MonoClass* mDontSerializeFieldAttribute;
 		MonoClass* mSerializeFieldAttribute;
 		MonoClass* mHideInInspectorAttribute;
+		MonoClass* mRangeAttribute;
+		MonoClass* mStepAttribute;
 	};
 
 	/** @} */

+ 6 - 0
Source/SBansheeEngine/Include/BsScriptGUISlider.h

@@ -32,7 +32,10 @@ namespace BansheeEngine
 		static float internal_getValue(ScriptGUISliderH* nativeInstance);
 		static void internal_setValue(ScriptGUISliderH* nativeInstance, float percent);
 		static void internal_setRange(ScriptGUISliderH* nativeInstance, float min, float max);
+		static float internal_getRangeMaximum(ScriptGUISliderH* nativeInstance);
+		static float internal_getRangeMinimum(ScriptGUISliderH* nativeInstance);
 		static void internal_setStep(ScriptGUISliderH* nativeInstance, float step);
+		static float internal_getStep(ScriptGUISliderH* nativeInstance);
 		static void internal_setTint(ScriptGUISliderH* nativeInstance, Color* color);
 
 		typedef void(__stdcall *OnChangedThunkDef) (MonoObject*, float, MonoException**);
@@ -60,7 +63,10 @@ namespace BansheeEngine
 		static float internal_getValue(ScriptGUISliderV* nativeInstance);
 		static void internal_setValue(ScriptGUISliderV* nativeInstance, float percent);
 		static void internal_setRange(ScriptGUISliderV* nativeInstance, float min, float max);
+		static float internal_getRangeMaximum(ScriptGUISliderV* nativeInstance);
+		static float internal_getRangeMinimum(ScriptGUISliderV* nativeInstance);
 		static void internal_setStep(ScriptGUISliderV* nativeInstance, float step);
+		static float internal_getStep(ScriptGUISliderV* nativeInstance);
 		static void internal_setTint(ScriptGUISliderV* nativeInstance, Color* color);
 
 		typedef void(__stdcall *OnChangedThunkDef) (MonoObject*, float, MonoException**);

+ 27 - 0
Source/SBansheeEngine/Include/BsScriptRange.h

@@ -0,0 +1,27 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptObject.h"
+
+namespace BansheeEngine
+{
+	/**	Interop class between C++ & CLR for Range attribute. */
+	class BS_SCR_BE_EXPORT ScriptRange : public ScriptObject <ScriptRange>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "Range")
+
+		static MonoField* getMinRangeField() { return minRangeField; }
+		static MonoField* getMaxRangeField() { return maxRangeField; }
+		static MonoField* getSliderField() { return sliderField; }
+
+	private:
+		ScriptRange(MonoObject* instance);
+
+		static MonoField* minRangeField;
+		static MonoField* maxRangeField;
+		static MonoField* sliderField;
+	};
+}

+ 4 - 1
Source/SBansheeEngine/Include/BsScriptSerializableField.h

@@ -25,7 +25,6 @@ namespace BansheeEngine
 		 *								provided parent object.
 		 */
 		static ScriptSerializableField* create(MonoObject* parentObject, const SPtr<ManagedSerializableFieldInfo>& fieldInfo);
-
 	private:
 		ScriptSerializableField(MonoObject* instance, const SPtr<ManagedSerializableFieldInfo>& fieldInfo);
 
@@ -37,6 +36,10 @@ namespace BansheeEngine
 		static MonoObject* internal_createProperty(ScriptSerializableField* nativeInstance);
 		static MonoObject* internal_getValue(ScriptSerializableField* nativeInstance, MonoObject* instance);
 		static void internal_setValue(ScriptSerializableField* nativeInstance, MonoObject* instance, MonoObject* value);
+		static float internal_getRangeMaximum(ScriptSerializableField* nativeInstance);
+		static float internal_getRangeMinimum(ScriptSerializableField* nativeInstance);
+		static bool internal_renderAsSlider(ScriptSerializableField* nativeInstance);
+		static float internal_getStep(ScriptSerializableField* nativeInstance);
 	};
 
 	/** @} */

+ 23 - 0
Source/SBansheeEngine/Include/BsScriptStep.h

@@ -0,0 +1,23 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptObject.h"
+
+namespace BansheeEngine
+{
+	/**	Interop class between C++ & CLR for Step attribute. */
+	class BS_SCR_BE_EXPORT ScriptStep : public ScriptObject <ScriptStep>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "Step")
+
+		static MonoField* getStepField() { return stepField; }
+
+	private:
+		ScriptStep(MonoObject* instance);
+
+		static MonoField* stepField;
+	};
+}

+ 68 - 1
Source/SBansheeEngine/Source/BsManagedSerializableObjectInfo.cpp

@@ -2,9 +2,11 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 #include "BsManagedSerializableObjectInfo.h"
 #include "BsManagedSerializableObjectInfoRTTI.h"
+#include "BsScriptRange.h"
 #include "BsMonoUtil.h"
 #include "BsMonoClass.h"
 #include "BsMonoManager.h"
+#include "BsMonoField.h"
 #include "BsScriptTexture2D.h"
 #include "BsScriptSpriteTexture.h"
 #include "BsScriptAssemblyManager.h"
@@ -25,6 +27,7 @@
 #include "BsScriptAnimationClip.h"
 #include "BsScriptPrefab.h"
 #include "BsScriptManagedResource.h"
+#include <BsScriptStep.h>
 
 namespace BansheeEngine
 {
@@ -95,6 +98,70 @@ namespace BansheeEngine
 
 	}
 
+	float ManagedSerializableFieldInfo::getRangeMinimum() const
+	{
+		if (((UINT32)mFlags & (UINT32)ScriptFieldFlags::Range) != 0)
+		{
+
+			MonoClass* range = ScriptAssemblyManager::instance().getRangeAttribute();
+			if (range != nullptr)
+			{
+				float min = 0;
+				ScriptRange::getMinRangeField()->getValue(mMonoField->getAttribute(range), &min);
+				return min;
+			}
+		}
+		return 0;
+	}
+
+	float ManagedSerializableFieldInfo::getRangeMaximum() const
+	{
+		if (((UINT32)mFlags & (UINT32)ScriptFieldFlags::Range) != 0)
+		{
+
+			MonoClass* range = ScriptAssemblyManager::instance().getRangeAttribute();
+			if (range != nullptr)
+			{
+				float max = 0;
+				ScriptRange::getMaxRangeField()->getValue(mMonoField->getAttribute(range), &max);
+				return max;
+			}
+		}
+		return 0;
+	}
+
+	bool ManagedSerializableFieldInfo::renderAsSlider() const
+	{
+		if (((UINT32)mFlags & (UINT32)ScriptFieldFlags::Range) != 0)
+		{
+			MonoClass* range = ScriptAssemblyManager::instance().getRangeAttribute();
+			if (range != nullptr)
+			{
+				bool slider = false;
+				ScriptRange::getSliderField()->getValue(mMonoField->getAttribute(range), &slider);
+				return slider;
+			}
+		}
+		return false;
+	}
+
+
+	float ManagedSerializableFieldInfo::getStep() const
+	{
+		if (((UINT32)mFlags & (UINT32)ScriptFieldFlags::Step) != 0)
+		{
+
+			MonoClass* step = ScriptAssemblyManager::instance().getStepAttribute();
+			if (step != nullptr)
+			{
+				float value = 0;
+				ScriptStep::getStepField()->getValue(mMonoField->getAttribute(step), &value);
+				return value;
+			}
+		}
+		return 0;
+	}
+
 	RTTITypeBase* ManagedSerializableFieldInfo::getRTTIStatic()
 	{
 		return ManagedSerializableFieldInfoRTTI::instance();
@@ -430,4 +497,4 @@ namespace BansheeEngine
 	{
 		return ManagedSerializableTypeInfoDictionary::getRTTIStatic();
 	}
-}
+}

+ 15 - 0
Source/SBansheeEngine/Source/BsScriptAssemblyManager.cpp

@@ -35,6 +35,7 @@ namespace BansheeEngine
 		, mSystemGenericDictionaryClass(nullptr), mSystemTypeClass(nullptr), mComponentClass(nullptr)
 		, mSceneObjectClass(nullptr), mMissingComponentClass(nullptr), mSerializeObjectAttribute(nullptr)
 		, mDontSerializeFieldAttribute(nullptr), mSerializeFieldAttribute(nullptr), mHideInInspectorAttribute(nullptr)
+		, mRangeAttribute(nullptr), mStepAttribute(nullptr)
 	{
 
 	}
@@ -139,6 +140,10 @@ namespace BansheeEngine
 					if (field->hasAttribute(mSerializeFieldAttribute))
 						fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Serializable);
 				}
+				if (field->hasAttribute(mRangeAttribute))
+					fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Range);
+				if (field->hasAttribute(mStepAttribute))
+					fieldInfo->mFlags = (ScriptFieldFlags)((UINT32)fieldInfo->mFlags | (UINT32)ScriptFieldFlags::Step);
 
 				objInfo->mFieldNameToId[fieldInfo->mName] = fieldInfo->mFieldId;
 				objInfo->mFields[fieldInfo->mFieldId] = fieldInfo;
@@ -436,6 +441,8 @@ namespace BansheeEngine
 
 		mSerializeFieldAttribute = nullptr;
 		mHideInInspectorAttribute = nullptr;
+		mRangeAttribute = nullptr;
+		mStepAttribute = nullptr;
 	}
 
 	void ScriptAssemblyManager::initializeBaseTypes()
@@ -473,6 +480,14 @@ namespace BansheeEngine
 		if(mDontSerializeFieldAttribute == nullptr)
 			BS_EXCEPT(InvalidStateException, "Cannot find DontSerializeField managed class.");
 
+		mRangeAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "Range");
+		if (mRangeAttribute == nullptr)
+			BS_EXCEPT(InvalidStateException, "Cannot find Range managed class.");
+
+		mStepAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "Step");
+		if (mStepAttribute == nullptr)
+			BS_EXCEPT(InvalidStateException, "Cannot find Step managed class.");
+
 		mComponentClass = bansheeEngineAssembly->getClass("BansheeEngine", "Component");
 		if(mComponentClass == nullptr)
 			BS_EXCEPT(InvalidStateException, "Cannot find Component managed class.");

+ 42 - 0
Source/SBansheeEngine/Source/BsScriptGUISlider.cpp

@@ -37,7 +37,10 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_GetValue", &ScriptGUISliderH::internal_getValue);
 		metaData.scriptClass->addInternalCall("Internal_SetValue", &ScriptGUISliderH::internal_setValue);
 		metaData.scriptClass->addInternalCall("Internal_SetRange", &ScriptGUISliderH::internal_setRange);
+		metaData.scriptClass->addInternalCall("Internal_GetRangeMaximum", &ScriptGUISliderH::internal_getRangeMaximum);
+		metaData.scriptClass->addInternalCall("Internal_GetRangeMinimum", &ScriptGUISliderH::internal_getRangeMinimum);
 		metaData.scriptClass->addInternalCall("Internal_SetStep", &ScriptGUISliderH::internal_setStep);
+		metaData.scriptClass->addInternalCall("Internal_GetStep", &ScriptGUISliderH::internal_getStep);
 
 		onChangedThunk = (OnChangedThunkDef)metaData.scriptClass->getMethod("DoOnChanged", 1)->getThunk();
 	}
@@ -87,12 +90,30 @@ namespace BansheeEngine
 		return slider->setRange(min, max);
 	}
 
+	float ScriptGUISliderH::internal_getRangeMaximum(ScriptGUISliderH* nativeInstance)
+	{
+		GUISliderHorz* slider = (GUISliderHorz*)nativeInstance->getGUIElement();
+		return slider->getRangeMaximum();
+	}
+
+	float ScriptGUISliderH::internal_getRangeMinimum(ScriptGUISliderH* nativeInstance)
+	{
+		GUISliderHorz* slider = (GUISliderHorz*)nativeInstance->getGUIElement();
+		return slider->getRangeMinimum();
+	}
+
 	void ScriptGUISliderH::internal_setStep(ScriptGUISliderH* nativeInstance, float step)
 	{
 		GUISliderHorz* slider = (GUISliderHorz*)nativeInstance->getGUIElement();
 		return slider->setStep(step);
 	}
 
+	float ScriptGUISliderH::internal_getStep(ScriptGUISliderH* nativeInstance)
+	{
+		GUISliderHorz* slider = (GUISliderHorz*)nativeInstance->getGUIElement();
+		return slider->getStep();
+	}
+
 	void ScriptGUISliderH::internal_setTint(ScriptGUISliderH* nativeInstance, Color* color)
 	{
 		GUISliderHorz* slider = (GUISliderHorz*)nativeInstance->getGUIElement();
@@ -121,7 +142,10 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_GetValue", &ScriptGUISliderV::internal_getValue);
 		metaData.scriptClass->addInternalCall("Internal_SetValue", &ScriptGUISliderV::internal_setValue);
 		metaData.scriptClass->addInternalCall("Internal_SetRange", &ScriptGUISliderV::internal_setRange);
+		metaData.scriptClass->addInternalCall("Internal_GetRangeMaximum", &ScriptGUISliderV::internal_getRangeMaximum);
+		metaData.scriptClass->addInternalCall("Internal_GetRangeMinimum", &ScriptGUISliderV::internal_getRangeMinimum);
 		metaData.scriptClass->addInternalCall("Internal_SetStep", &ScriptGUISliderV::internal_setStep);
+		metaData.scriptClass->addInternalCall("Internal_GetStep", &ScriptGUISliderV::internal_getStep);
 
 		onChangedThunk = (OnChangedThunkDef)metaData.scriptClass->getMethod("DoOnChanged", 1)->getThunk();
 	}
@@ -171,12 +195,30 @@ namespace BansheeEngine
 		return slider->setRange(min, max);
 	}
 
+	float ScriptGUISliderV::internal_getRangeMaximum(ScriptGUISliderV* nativeInstance)
+	{
+		GUISliderVert* slider = (GUISliderVert*)nativeInstance->getGUIElement();
+		return slider->getRangeMaximum();
+	}
+
+	float ScriptGUISliderV::internal_getRangeMinimum(ScriptGUISliderV* nativeInstance)
+	{
+		GUISliderVert* slider = (GUISliderVert*)nativeInstance->getGUIElement();
+		return slider->getRangeMinimum();
+	}
+
 	void ScriptGUISliderV::internal_setStep(ScriptGUISliderV* nativeInstance, float step)
 	{
 		GUISliderVert* slider = (GUISliderVert*)nativeInstance->getGUIElement();
 		return slider->setStep(step);
 	}
 
+	float ScriptGUISliderV::internal_getStep(ScriptGUISliderV* nativeInstance)
+	{
+		GUISliderVert* slider = (GUISliderVert*)nativeInstance->getGUIElement();
+		return slider->getStep();
+	}
+
 	void ScriptGUISliderV::internal_setTint(ScriptGUISliderV* nativeInstance, Color* color)
 	{
 		GUISliderVert* slider = (GUISliderVert*)nativeInstance->getGUIElement();

+ 21 - 0
Source/SBansheeEngine/Source/BsScriptRange.cpp

@@ -0,0 +1,21 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+
+#include "BsScriptRange.h"
+#include "BsScriptEnginePrerequisites.h"
+
+namespace BansheeEngine
+{
+	MonoField* ScriptRange::sliderField = nullptr;
+	MonoField* ScriptRange::minRangeField = nullptr;
+	MonoField* ScriptRange::maxRangeField = nullptr;
+
+	ScriptRange::ScriptRange(MonoObject* instance) : ScriptObject(instance)
+	{ }
+	void ScriptRange::initRuntimeData()
+	{
+		minRangeField = metaData.scriptClass->getField("min");
+		maxRangeField = metaData.scriptClass->getField("max");
+		sliderField = metaData.scriptClass->getField("slider");
+	}
+}

+ 9 - 0
Source/SBansheeEngine/Source/BsScriptSerializableField.cpp

@@ -11,6 +11,7 @@
 
 namespace BansheeEngine
 {
+
 	ScriptSerializableField::ScriptSerializableField(MonoObject* instance, const SPtr<ManagedSerializableFieldInfo>& fieldInfo)
 		:ScriptObject(instance), mFieldInfo(fieldInfo)
 	{
@@ -22,6 +23,10 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_CreateProperty", &ScriptSerializableField::internal_createProperty);
 		metaData.scriptClass->addInternalCall("Internal_GetValue", &ScriptSerializableField::internal_getValue);
 		metaData.scriptClass->addInternalCall("Internal_SetValue", &ScriptSerializableField::internal_setValue);
+		metaData.scriptClass->addInternalCall("Internal_GetRangeMaximum", &ScriptSerializableField::internal_getRangeMaximum);
+		metaData.scriptClass->addInternalCall("Internal_GetRangeMinimum", &ScriptSerializableField::internal_getRangeMinimum);
+		metaData.scriptClass->addInternalCall("Internal_RenderAsSlider", &ScriptSerializableField::internal_renderAsSlider);
+		metaData.scriptClass->addInternalCall("Internal_GetStep", &ScriptSerializableField::internal_getStep);
 	}
 
 	ScriptSerializableField* ScriptSerializableField::create(MonoObject* parentObject, const SPtr<ManagedSerializableFieldInfo>& fieldInfo)
@@ -60,4 +65,8 @@ namespace BansheeEngine
 		else
 			nativeInstance->mFieldInfo->mMonoField->setValue(instance, value);
 	}
+	float ScriptSerializableField::internal_getRangeMaximum(ScriptSerializableField* nativeInstance) { return nativeInstance->mFieldInfo->getRangeMaximum(); }
+	float ScriptSerializableField::internal_getRangeMinimum(ScriptSerializableField* nativeInstance) { return nativeInstance->mFieldInfo->getRangeMinimum(); }
+	bool ScriptSerializableField::internal_renderAsSlider(ScriptSerializableField* nativeInstance) { return  nativeInstance->mFieldInfo->renderAsSlider(); }
+	float ScriptSerializableField::internal_getStep(ScriptSerializableField* nativeInstance) { return nativeInstance->mFieldInfo->getStep(); }
 }

+ 17 - 0
Source/SBansheeEngine/Source/BsScriptStep.cpp

@@ -0,0 +1,17 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+
+#include "BsScriptEnginePrerequisites.h"
+#include <BsScriptStep.h>
+
+namespace BansheeEngine
+{
+	MonoField* ScriptStep::stepField = nullptr;
+
+	ScriptStep::ScriptStep(MonoObject* instance) : ScriptObject(instance)
+	{ }
+	void ScriptStep::initRuntimeData()
+	{
+		stepField = metaData.scriptClass->getField("step");
+	}
+}