Browse Source

Fixing an issue with GUI sliders where they would be constantly triggering onChanged events in inspector

BearishSun 10 years ago
parent
commit
b428af3c08

+ 59 - 59
BansheeEditor/Include/BsCmdInputFieldValueChange.h

@@ -1,60 +1,60 @@
-#pragma once
-
-#include "BsEditorPrerequisites.h"
-#include "BsEditorCommand.h"
-#include "BsUndoRedo.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	A command used for undo/redo purposes. It records a value of a GUI input field
-	 *			(specified by template type) and allows you to apply or revert a change to that field
-	 *			as needed.
-	 */
-	template <class InputFieldType, class ValueType>
-	class BS_ED_EXPORT CmdInputFieldValueChange : public EditorCommand
-	{
-	public:
-		/**
-		 * @brief	Creates and executes the command on the provided object and field.
-		 *			Automatically registers the command with undo/redo system.
-		 *
-		 * @param	inputField	Input field to modify the value on.
-		 * @param	value		New value for the field.
-		 * @param	description	Optional description of what exactly the command does.
-		 */
-		static void execute(InputFieldType* inputField, const ValueType& value, const WString& description = StringUtil::WBLANK)
-		{
-			CmdInputFieldValueChange* command = new (bs_alloc<CmdInputFieldValueChange>()) CmdInputFieldValueChange(description, inputField, value);
-			UndoRedo::instance().registerCommand(command);
-			command->commit();
-		}
-
-		/**
-		 * @copydoc	EditorCommand::commit
-		 */
-		void commit() override
-		{
-			mInputField->setValue(mNewValue);
-		}
-
-		/**
-		 * @copydoc	EditorCommand::revert
-		 */
-		void revert() override
-		{
-			mInputField->setValue(mOldValue);
-		}
-
-	private:
-		friend class UndoRedo;
-
-		CmdInputFieldValueChange(const WString& description, InputFieldType* inputField, const ValueType& value)
-			:EditorCommand(description), mInputField(inputField), mOldValue(inputField->getValue()), mNewValue(value)
-		{ }
-
-		ValueType mOldValue;
-		ValueType mNewValue;
-		InputFieldType* mInputField;
-	};
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsEditorCommand.h"
+#include "BsUndoRedo.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	A command used for undo/redo purposes. It records a value of a GUI input field
+	 *			(specified by template type) and allows you to apply or revert a change to that field
+	 *			as needed.
+	 */
+	template <class InputFieldType, class ValueType>
+	class BS_ED_EXPORT CmdInputFieldValueChange : public EditorCommand
+	{
+	public:
+		/**
+		 * @brief	Creates and executes the command on the provided object and field.
+		 *			Automatically registers the command with undo/redo system.
+		 *
+		 * @param	inputField	Input field to modify the value on.
+		 * @param	value		New value for the field.
+		 * @param	description	Optional description of what exactly the command does.
+		 */
+		static void execute(InputFieldType* inputField, const ValueType& value, const WString& description = StringUtil::WBLANK)
+		{
+			CmdInputFieldValueChange* command = new (bs_alloc<CmdInputFieldValueChange>()) CmdInputFieldValueChange(description, inputField, value);
+			UndoRedo::instance().registerCommand(command);
+			command->commit();
+		}
+
+		/**
+		 * @copydoc	EditorCommand::commit
+		 */
+		void commit() override
+		{
+			mInputField->_setValue(mNewValue, true);
+		}
+
+		/**
+		 * @copydoc	EditorCommand::revert
+		 */
+		void revert() override
+		{
+			mInputField->_setValue(mOldValue, true);
+		}
+
+	private:
+		friend class UndoRedo;
+
+		CmdInputFieldValueChange(const WString& description, InputFieldType* inputField, const ValueType& value)
+			:EditorCommand(description), mInputField(inputField), mOldValue(inputField->getValue()), mNewValue(value)
+		{ }
+
+		ValueType mOldValue;
+		ValueType mNewValue;
+		InputFieldType* mInputField;
+	};
 }

+ 7 - 1
BansheeEditor/Include/BsGUIFloatField.h

@@ -50,7 +50,13 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	GUIElement::setTint
 		 */
-		virtual void setTint(const Color& color) override;
+		void setTint(const Color& color) override;
+
+		/**
+		 * @brief	Sets a new value in the input field, and also allows you to choose should the field trigger an
+		 *			onValueChanged event.
+		 */
+		void _setValue(float value, bool triggerEvent);
 
 		Event<void(float)> onValueChanged; /**< Triggers when the field value changes. */
 		Event<void()> onConfirm; /**< Triggered when the user hits the Enter key with the input box in focus. */

+ 7 - 1
BansheeEditor/Include/BsGUIIntField.h

@@ -50,7 +50,13 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	GUIElement::setTint
 		 */
-		virtual void setTint(const Color& color) override;
+		void setTint(const Color& color) override;
+
+		/**
+		 * @brief	Sets a new value in the input field, and also allows you to choose should the field trigger an
+		 *			onValueChanged event.
+		 */
+		void _setValue(INT32 value, bool triggerEvent);
 
 		Event<void(INT32)> onValueChanged; /**< Triggers when the internal value changes. */
 		Event<void()> onConfirm; /**< Triggered when the user hits the Enter key with the input box in focus. */

+ 94 - 93
BansheeEditor/Include/BsGUISliderField.h

@@ -1,94 +1,95 @@
-#pragma once
-
-#include "BsEditorPrerequisites.h"
-#include "BsGUIFieldBase.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	A composite GUI object representing an editor field. Editor fields are a combination
-	 *			of a label and an input field. Label is optional. This specific implementation
-	 *			displays a horizontal slider and a floating point input box.
-	 */
-	class BS_ED_EXPORT GUISliderField : public TGUIField<GUISliderField>
-	{
-	public:
-		/**
-		 * Returns type name of the GUI element used for finding GUI element styles. 
-		 */
-		static const String& getGUITypeName();
-
-		/**
-		 * Style type name for the internal input box.
-		 */
-		static const String& getInputStyleType();
-
-		/**
-		 * Style type name for the internal slider.
-		 */
-		static const String& getSliderStyleType();
-
-		GUISliderField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
-			const String& style, const GUIDimensions& dimensions, bool withLabel);
-
-		/**
-		 * @brief	Returns the value of the input field/slider.
-		 */
-		float getValue() const;
-
-		/**
-		 * @brief	Sets a new value in the input field/slider.
-		 */
-		void setValue(float value);
-
-		/**
-		 * @brief	Sets a minimum and maximum allow values in the input field.
-		 *			Set to large negative/positive values if you don't require clamping.
-		 */
-		void setRange(float min, float max);
-
-		/**
-		 * @brief	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);
-
-		/**
-		 * @copydoc	GUIElement::setTint
-		 */
-		virtual void setTint(const Color& color) override;
-
-		Event<void(float)> onValueChanged; /**< Triggers when the field value changes. */
-	protected:
-		virtual ~GUISliderField();
-
-		/**
-		 * @brief	Sets a new value in the input field/slider without setting off an event.
-		 */
-		void setValueInternal(float value);
-
-		/**
-		 * @copydoc	GUIElementContainer::styleUpdated
-		 */
-		void styleUpdated() override;
-
-		/**
-		 * @brief	Triggered when the input box value changes.
-		 */
-		void valueChanged(const WString& newValue);
-
-		/**
-		 * @brief	Triggered when the slider is moved.
-		 */
-		void sliderChanged(float newValue);
-
-		/**
-		 * @brief	Callback that checks can the provided string be
-		 *			converted to a floating point value.
-		 */
-		static bool floatFilter(const WString& str);
-
-		GUIInputBox* mInputBox;
-		GUISliderHorz* mSlider;
-	};
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsGUIFieldBase.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	A composite GUI object representing an editor field. Editor fields are a combination
+	 *			of a label and an input field. Label is optional. This specific implementation
+	 *			displays a horizontal slider and a floating point input box.
+	 */
+	class BS_ED_EXPORT GUISliderField : public TGUIField<GUISliderField>
+	{
+	public:
+		/**
+		 * Returns type name of the GUI element used for finding GUI element styles. 
+		 */
+		static const String& getGUITypeName();
+
+		/**
+		 * Style type name for the internal input box.
+		 */
+		static const String& getInputStyleType();
+
+		/**
+		 * Style type name for the internal slider.
+		 */
+		static const String& getSliderStyleType();
+
+		GUISliderField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
+			const String& style, const GUIDimensions& dimensions, bool withLabel);
+
+		/**
+		 * @brief	Returns the value of the input field/slider.
+		 */
+		float getValue() const;
+
+		/**
+		 * @brief	Sets a new value in the input field/slider.
+		 */
+		void setValue(float value);
+
+		/**
+		 * @brief	Sets a minimum and maximum allow values in the input field.
+		 *			Set to large negative/positive values if you don't require clamping.
+		 */
+		void setRange(float min, float max);
+
+		/**
+		 * @brief	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);
+
+		/**
+		 * @copydoc	GUIElement::setTint
+		 */
+		void setTint(const Color& color) override;
+
+		/**
+		 * @brief	Sets a new value in the input field, and also allows you to choose should the field trigger an
+		 *			onValueChanged event.
+		 */
+		void _setValue(float value, bool triggerEvent);
+
+		Event<void(float)> onValueChanged; /**< Triggers when the field value changes. */
+	protected:
+		virtual ~GUISliderField();
+
+		/**
+		 * @copydoc	GUIElementContainer::styleUpdated
+		 */
+		void styleUpdated() override;
+
+		/**
+		 * @brief	Triggered when the input box value changes.
+		 */
+		void valueChanged(const WString& newValue);
+
+		/**
+		 * @brief	Triggered when the slider is moved.
+		 */
+		void sliderChanged(float newValue);
+
+		/**
+		 * @brief	Callback that checks can the provided string be
+		 *			converted to a floating point value.
+		 */
+		static bool floatFilter(const WString& str);
+
+		GUIInputBox* mInputBox;
+		GUISliderHorz* mSlider;
+	};
 }

+ 7 - 1
BansheeEditor/Include/BsGUITextField.h

@@ -181,7 +181,13 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	GUIElement::setTint
 		 */
-		virtual void setTint(const Color& color) override;
+		void setTint(const Color& color) override;
+		
+		/**
+		 * @brief	Sets a new value in the input field, and also allows you to choose should the field trigger an
+		 *			onValueChanged event.
+		 */
+		void _setValue(const WString& value, bool triggerEvent);
 
 		Event<void(const WString&)> onValueChanged; /** Triggered when the value in the field changes. */
 		Event<void()> onConfirm; /**< Triggered when the user hits the Enter key with the input box in focus. */

+ 7 - 1
BansheeEditor/Include/BsGUIToggleField.h

@@ -39,7 +39,13 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	GUIElement::setTint
 		 */
-		virtual void setTint(const Color& color) override;
+		void setTint(const Color& color) override;
+
+		/**
+		 * @brief	Sets a new value in the input field, and also allows you to choose should the field trigger an
+		 *			onValueChanged event.
+		 */
+		void _setValue(bool value, bool triggerEvent);
 
 		Event<void(bool)> onValueChanged; /** Triggered when the value of the toggle changes. */
 	protected:

+ 8 - 3
BansheeEditor/Source/BsGUIFloatField.cpp

@@ -161,6 +161,14 @@ namespace BansheeEngine
 		mInputBox->setTint(color);
 	}
 
+	void GUIFloatField::_setValue(float value, bool triggerEvent)
+	{
+		setValue(value);
+
+		if(triggerEvent)
+			onValueChanged(value);
+	}
+
 	const String& GUIFloatField::getGUITypeName()
 	{
 		static String typeName = "GUIFloatField";
@@ -189,9 +197,6 @@ namespace BansheeEngine
 	void GUIFloatField::valueChanged(float newValue)
 	{
 		CmdInputFieldValueChange<GUIFloatField, float>::execute(this, newValue);
-
-		if (!onValueChanged.empty())
-			onValueChanged(newValue);
 	}
 
 	void GUIFloatField::focusChanged(bool focus)

+ 8 - 1
BansheeEditor/Source/BsGUIIntField.cpp

@@ -187,6 +187,14 @@ namespace BansheeEngine
 		mInputBox->setTint(color);
 	}
 
+	void GUIIntField::_setValue(INT32 value, bool triggerEvent)
+	{
+		setValue(value);
+
+		if (triggerEvent)
+			onValueChanged(value);
+	}
+
 	const String& GUIIntField::getGUITypeName()
 	{
 		static String typeName = "GUIIntField";
@@ -207,7 +215,6 @@ namespace BansheeEngine
 	void GUIIntField::valueChanged(INT32 newValue)
 	{
 		CmdInputFieldValueChange<GUIIntField, INT32>::execute(this, newValue);
-		onValueChanged(newValue);
 	}
 
 	void GUIIntField::focusChanged(bool focus)

+ 136 - 133
BansheeEditor/Source/BsGUISliderField.cpp

@@ -1,134 +1,137 @@
-#include "BsGUISliderField.h"
-#include "BsGUILayout.h"
-#include "BsGUILabel.h"
-#include "BsGUIInputBox.h"
-#include "BsGUISpace.h"
-#include "BsBuiltinResources.h"
-#include "BsCGUIWidget.h"
-#include "BsGUIMouseEvent.h"
-#include "BsCursor.h"
-#include "BsCGUIWidget.h"
-#include "BsViewport.h"
-#include "BsGUISlider.h"
-#include "BsCmdInputFieldValueChange.h"
-#include <regex>
-
-using namespace std::placeholders;
-
-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)
-	{
-		mSlider = GUISliderHorz::create(GUIOptions(GUIOption::flexibleWidth()), getSubStyleName(getSliderStyleType()));
-		mSlider->onChanged.connect(std::bind(&GUISliderField::sliderChanged, this, _1));
-
-		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));
-
-		mLayout->addElement(mSlider);
-		mLayout->addNewElement<GUIFixedSpace>(5);
-		mLayout->addElement(mInputBox);
-
-		setValueInternal(0);
-		mInputBox->setText(L"0");
-	}
-
-	GUISliderField::~GUISliderField()
-	{
-
-	}
-
-	float GUISliderField::getValue() const
-	{
-		return mSlider->getValue();
-	}
-
-	void GUISliderField::setValue(float value)
-	{
-		setValueInternal(value);
-
-		onValueChanged(value);
-	}
-
-	void GUISliderField::setValueInternal(float value)
-	{
-		float origValue = mSlider->getValue();
-		if (origValue != value)
-			mSlider->setValue(value);
-
-		float clampedValue = mSlider->getValue();
-
-		// 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 (clampedValue != curValue)
-			mInputBox->setText(toWString(clampedValue));
-	}
-
-	void GUISliderField::setRange(float min, float max)
-	{
-		mSlider->setRange(min, max);
-	}
-
-	void GUISliderField::setStep(float step)
-	{
-		mSlider->setStep(step);
-	}
-
-	void GUISliderField::setTint(const Color& color)
-	{
-		if (mLabel != nullptr)
-			mLabel->setTint(color);
-
-		mInputBox->setTint(color);
-	}
-
-	const String& GUISliderField::getGUITypeName()
-	{
-		static String typeName = "GUISliderField";
-		return typeName;
-	}
-
-	const String& GUISliderField::getInputStyleType()
-	{
-		static String LABEL_STYLE_TYPE = "EditorFieldInput";
-		return LABEL_STYLE_TYPE;
-	}
-
-	const String& GUISliderField::getSliderStyleType()
-	{
-		static String SLIDER_STYLE_TYPE = "EditorSliderInput";
-		return SLIDER_STYLE_TYPE;
-	}
-
-	void GUISliderField::styleUpdated()
-	{
-		if (mLabel != nullptr)
-			mLabel->setStyle(getSubStyleName(getLabelStyleType()));
-
-		mSlider->setStyle(getSubStyleName(getSliderStyleType()));
-		mInputBox->setStyle(getSubStyleName(getInputStyleType()));
-	}
-
-	void GUISliderField::valueChanged(const WString& newValue)
-	{
-		float newFloatValue = parseFloat(newValue);
-
-		CmdInputFieldValueChange<GUISliderField, float>::execute(this, newFloatValue);
-	}
-
-	void GUISliderField::sliderChanged(float newValue)
-	{
-		setValue(mSlider->getValue());
-	}
-
-	bool GUISliderField::floatFilter(const WString& str)
-	{
-		return std::regex_match(str, std::wregex(L"-?(\\d+(\\.\\d*)?)?"));
-	}
+#include "BsGUISliderField.h"
+#include "BsGUILayout.h"
+#include "BsGUILabel.h"
+#include "BsGUIInputBox.h"
+#include "BsGUISpace.h"
+#include "BsBuiltinResources.h"
+#include "BsCGUIWidget.h"
+#include "BsGUIMouseEvent.h"
+#include "BsCursor.h"
+#include "BsCGUIWidget.h"
+#include "BsViewport.h"
+#include "BsGUISlider.h"
+#include "BsCmdInputFieldValueChange.h"
+#include <regex>
+
+using namespace std::placeholders;
+
+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)
+	{
+		mSlider = GUISliderHorz::create(GUIOptions(GUIOption::flexibleWidth()), getSubStyleName(getSliderStyleType()));
+		mSlider->onChanged.connect(std::bind(&GUISliderField::sliderChanged, this, _1));
+
+		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));
+
+		mLayout->addElement(mSlider);
+		mLayout->addNewElement<GUIFixedSpace>(5);
+		mLayout->addElement(mInputBox);
+
+		setValue(0);
+		mInputBox->setText(L"0");
+	}
+
+	GUISliderField::~GUISliderField()
+	{
+
+	}
+
+	float GUISliderField::getValue() const
+	{
+		return mSlider->getValue();
+	}
+
+	void GUISliderField::setValue(float value)
+	{
+		float origValue = mSlider->getValue();
+		if (origValue != value)
+			mSlider->setValue(value);
+
+		float clampedValue = mSlider->getValue();
+
+		// 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 (clampedValue != curValue)
+			mInputBox->setText(toWString(clampedValue));
+	}
+
+	void GUISliderField::setRange(float min, float max)
+	{
+		mSlider->setRange(min, max);
+	}
+
+	void GUISliderField::setStep(float step)
+	{
+		mSlider->setStep(step);
+	}
+
+	void GUISliderField::setTint(const Color& color)
+	{
+		if (mLabel != nullptr)
+			mLabel->setTint(color);
+
+		mInputBox->setTint(color);
+	}
+
+	void GUISliderField::_setValue(float value, bool triggerEvent)
+	{
+		setValue(value);
+
+		if (triggerEvent)
+			onValueChanged(value);
+	}
+
+	const String& GUISliderField::getGUITypeName()
+	{
+		static String typeName = "GUISliderField";
+		return typeName;
+	}
+
+	const String& GUISliderField::getInputStyleType()
+	{
+		static String LABEL_STYLE_TYPE = "EditorFieldInput";
+		return LABEL_STYLE_TYPE;
+	}
+
+	const String& GUISliderField::getSliderStyleType()
+	{
+		static String SLIDER_STYLE_TYPE = "EditorSliderInput";
+		return SLIDER_STYLE_TYPE;
+	}
+
+	void GUISliderField::styleUpdated()
+	{
+		if (mLabel != nullptr)
+			mLabel->setStyle(getSubStyleName(getLabelStyleType()));
+
+		mSlider->setStyle(getSubStyleName(getSliderStyleType()));
+		mInputBox->setStyle(getSubStyleName(getInputStyleType()));
+	}
+
+	void GUISliderField::valueChanged(const WString& newValue)
+	{
+		float newFloatValue = parseFloat(newValue);
+
+		CmdInputFieldValueChange<GUISliderField, float>::execute(this, newFloatValue);
+	}
+
+	void GUISliderField::sliderChanged(float newValue)
+	{
+		setValue(mSlider->getValue());
+
+		onValueChanged(newValue);
+	}
+
+	bool GUISliderField::floatFilter(const WString& str)
+	{
+		return std::regex_match(str, std::wregex(L"-?(\\d+(\\.\\d*)?)?"));
+	}
 }

+ 8 - 3
BansheeEditor/Source/BsGUITextField.cpp

@@ -163,6 +163,14 @@ namespace BansheeEngine
 		mInputBox->setTint(color);
 	}
 
+	void GUITextField::_setValue(const WString& value, bool triggerEvent)
+	{
+		setValue(value);
+
+		if (triggerEvent)
+			onValueChanged(value);
+	}
+
 	void GUITextField::_updateLayoutInternal(const GUILayoutData& data)
 	{
 		mLayout->_setLayoutData(data);
@@ -185,9 +193,6 @@ namespace BansheeEngine
 	void GUITextField::valueChanged(const WString& newValue)
 	{
 		CmdInputFieldValueChange<GUITextField, WString>::execute(this, newValue);
-
-		if (!onValueChanged.empty())
-			onValueChanged(newValue);
 	}
 
 	void GUITextField::focusChanged(bool focus)

+ 8 - 3
BansheeEditor/Source/BsGUIToggleField.cpp

@@ -43,6 +43,14 @@ namespace BansheeEngine
 		mToggle->setTint(color);
 	}
 
+	void GUIToggleField::_setValue(bool value, bool triggerEvent)
+	{
+		setValue(value);
+
+		if (triggerEvent)
+			onValueChanged(value);
+	}
+
 	void GUIToggleField::styleUpdated()
 	{
 		if (mLabel != nullptr)
@@ -54,9 +62,6 @@ namespace BansheeEngine
 	void GUIToggleField::valueChanged(bool newValue)
 	{
 		CmdInputFieldValueChange<GUIToggleField, bool>::execute(this, newValue);
-
-		if (!onValueChanged.empty())
-			onValueChanged(newValue);
 	}
 
 	const String& GUIToggleField::getGUITypeName()

+ 231 - 231
BansheeEngine/Source/BsGUISlider.cpp

@@ -1,232 +1,232 @@
-#include "BsGUISlider.h"
-#include "BsCGUIWidget.h"
-#include "BsGUISkin.h"
-#include "BsGUISliderHandle.h"
-#include "BsGUITexture.h"
-#include "BsSpriteTexture.h"
-#include "BsGUIDimensions.h"
-
-using namespace std::placeholders;
-
-namespace BansheeEngine
-{
-	GUISlider::GUISlider(bool horizontal, const String& styleName, const GUIDimensions& dimensions)
-		:GUIElementContainer(dimensions, styleName), mHorizontal(horizontal), mMinRange(0.0f), mMaxRange(1.0f)
-	{
-		mSliderHandle = GUISliderHandle::create(horizontal, true, getSubStyleName(getHandleStyleType()));
-		mBackground = GUITexture::create(getSubStyleName(getBackgroundStyleType()));
-		mFillBackground = GUITexture::create(getSubStyleName(getFillStyleType()));
-
-		mBackground->_setElementDepth(mSliderHandle->_getRenderElementDepthRange() + mFillBackground->_getRenderElementDepthRange());
-		mFillBackground->_setElementDepth(mSliderHandle->_getRenderElementDepthRange());
-
-		_registerChildElement(mSliderHandle);
-		_registerChildElement(mBackground);
-		_registerChildElement(mFillBackground);
-
-		mHandleMovedConn = mSliderHandle->onHandleMoved.connect(std::bind(&GUISlider::onHandleMoved, this, _1));
-	}
-
-	GUISlider::~GUISlider()
-	{
-		mHandleMovedConn.disconnect();
-	}
-
-	const String& GUISlider::getHandleStyleType()
-	{
-		static String HANDLE_STYLE_TYPE = "SliderHandle";
-		return HANDLE_STYLE_TYPE;
-	}
-
-	const String& GUISlider::getBackgroundStyleType()
-	{
-		static String BACKGROUND_STYLE_TYPE = "SliderBackground";
-		return BACKGROUND_STYLE_TYPE;
-	}
-
-	const String& GUISlider::getFillStyleType()
-	{
-		static String FILL_STYLE_TYPE = "SliderFill";
-		return FILL_STYLE_TYPE;
-	}
-
-	Vector2I GUISlider::_getOptimalSize() const
-	{
-		Vector2I optimalSize = mSliderHandle->_getOptimalSize();
-
-		Vector2I backgroundSize = mBackground->_getOptimalSize();
-		optimalSize.x = std::max(optimalSize.x, backgroundSize.x);
-		optimalSize.y = std::max(optimalSize.y, backgroundSize.y);
-
-		return optimalSize;
-	}
-
-	void GUISlider::_updateLayoutInternal(const GUILayoutData& data)
-	{
-		GUILayoutData childData = data;
-
-		if (mHorizontal)
-		{
-			Vector2I optimalSize = mBackground->_getOptimalSize();
-			childData.area.height = optimalSize.y;
-			childData.area.y = data.area.y + (INT32)((data.area.height - childData.area.height) * 0.5f);
-
-			childData.clipRect = data.area;
-			childData.clipRect.clip(data.clipRect);
-
-			mBackground->_setLayoutData(childData);
-
-			optimalSize = mSliderHandle->_getOptimalSize();
-			childData.area.height = optimalSize.y;
-			childData.area.y = data.area.y + (INT32)((data.area.height - childData.area.height) * 0.5f);
-
-			childData.clipRect = data.area;
-			childData.clipRect.clip(data.clipRect);
-
-			mSliderHandle->_setLayoutData(childData);
-			UINT32 handleWidth = optimalSize.x;
-
-			optimalSize = mFillBackground->_getOptimalSize();
-			childData.area.height = optimalSize.y;
-			childData.area.y = data.area.y + (INT32)((data.area.height - childData.area.height) * 0.5f);
-			childData.area.width = mSliderHandle->getHandlePosPx() + handleWidth / 2;
-
-			childData.clipRect = data.area;
-			childData.clipRect.clip(data.clipRect);
-
-			mFillBackground->_setLayoutData(childData);
-		}
-		else
-		{
-			Vector2I optimalSize = mBackground->_getOptimalSize();
-			childData.area.width = optimalSize.x;
-			childData.area.x = data.area.x + (INT32)((data.area.width - childData.area.width) * 0.5f);
-
-			childData.clipRect = data.area;
-			childData.clipRect.clip(data.clipRect);
-
-			mBackground->_setLayoutData(childData);
-
-			optimalSize = mSliderHandle->_getOptimalSize();
-			childData.area.width = optimalSize.x;
-			childData.area.x = data.area.x + (INT32)((data.area.width - childData.area.width) * 0.5f);
-
-			childData.clipRect = data.area;
-			childData.clipRect.clip(data.clipRect);
-
-			mSliderHandle->_setLayoutData(childData);
-			UINT32 handleHeight = optimalSize.y;
-
-			optimalSize = mFillBackground->_getOptimalSize();
-			childData.area.width = optimalSize.x;
-			childData.area.x = data.area.x + (INT32)((data.area.width - childData.area.width) * 0.5f);
-			childData.area.height = mSliderHandle->getHandlePosPx() + handleHeight / 2;
-
-			childData.clipRect = data.area;
-			childData.clipRect.clip(data.clipRect);
-
-			mFillBackground->_setLayoutData(childData);
-		}
-	}
-
-	void GUISlider::styleUpdated()
-	{
-		mBackground->setStyle(getSubStyleName(getBackgroundStyleType()));
-		mFillBackground->setStyle(getSubStyleName(getFillStyleType()));
-		mSliderHandle->setStyle(getSubStyleName(getHandleStyleType()));
-	}
-
-	void GUISlider::setPercent(float pct)
-	{
-		float oldHandlePos = mSliderHandle->getHandlePos();
-		mSliderHandle->_setHandlePos(pct);
-
-		if (oldHandlePos != mSliderHandle->getHandlePos())
-			mSliderHandle->_markLayoutAsDirty();
-	}
-
-	float GUISlider::getPercent() const
-	{
-		return mSliderHandle->getHandlePos();
-	}
-
-	float GUISlider::getValue() const
-	{
-		float diff = mMaxRange - mMinRange;
-		return mMinRange + diff * mSliderHandle->getHandlePos();
-	}
-
-	void GUISlider::setValue(float value)
-	{
-		float diff = mMaxRange - mMinRange;
-		float pct = (value - mMinRange) / diff;
-
-		setPercent(pct);
-	}
-
-	void GUISlider::setRange(float min, float max)
-	{
-		mMinRange = min;
-		mMaxRange = max;
-	}
-
-	void GUISlider::setStep(float step)
-	{
-		mSliderHandle->setStep(step);
-	}
-
-	void GUISlider::setTint(const Color& color)
-	{
-		mBackground->setTint(color);
-		mSliderHandle->setTint(color);
-	}
-
-	void GUISlider::onHandleMoved(float newPosition)
-	{
-		onChanged(newPosition);
-	}
-
-	GUISliderHorz::GUISliderHorz(const String& styleName, const GUIDimensions& dimensions)
-		:GUISlider(true, styleName, dimensions)
-	{
-
-	}
-
-	GUISliderHorz* GUISliderHorz::create(const String& styleName)
-	{
-		return new (bs_alloc<GUISliderHorz>()) GUISliderHorz(getStyleName<GUISliderHorz>(styleName), GUIDimensions::create());
-	}
-
-	GUISliderHorz* GUISliderHorz::create(const GUIOptions& options, const String& styleName)
-	{
-		return new (bs_alloc<GUISliderHorz>()) GUISliderHorz(getStyleName<GUISliderHorz>(styleName), GUIDimensions::create(options));
-	}
-
-	const String& GUISliderHorz::getGUITypeName()
-	{
-		static String typeName = "SliderHorz";
-		return typeName;
-	}
-
-	GUISliderVert::GUISliderVert(const String& styleName, const GUIDimensions& dimensions)
-		:GUISlider(false, styleName, dimensions)
-	{
-
-	}
-
-	GUISliderVert* GUISliderVert::create(const String& styleName)
-	{
-		return new (bs_alloc<GUISliderVert>()) GUISliderVert(getStyleName<GUISliderVert>(styleName), GUIDimensions::create());
-	}
-
-	GUISliderVert* GUISliderVert::create(const GUIOptions& options, const String& styleName)
-	{
-		return new (bs_alloc<GUISliderVert>()) GUISliderVert(getStyleName<GUISliderVert>(styleName), GUIDimensions::create(options));
-	}
-
-	const String& GUISliderVert::getGUITypeName()
-	{
-		static String typeName = "SliderVert";
-		return typeName;
-	}
+#include "BsGUISlider.h"
+#include "BsCGUIWidget.h"
+#include "BsGUISkin.h"
+#include "BsGUISliderHandle.h"
+#include "BsGUITexture.h"
+#include "BsSpriteTexture.h"
+#include "BsGUIDimensions.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	GUISlider::GUISlider(bool horizontal, const String& styleName, const GUIDimensions& dimensions)
+		:GUIElementContainer(dimensions, styleName), mHorizontal(horizontal), mMinRange(0.0f), mMaxRange(1.0f)
+	{
+		mSliderHandle = GUISliderHandle::create(horizontal, true, getSubStyleName(getHandleStyleType()));
+		mBackground = GUITexture::create(getSubStyleName(getBackgroundStyleType()));
+		mFillBackground = GUITexture::create(getSubStyleName(getFillStyleType()));
+
+		mBackground->_setElementDepth(mSliderHandle->_getRenderElementDepthRange() + mFillBackground->_getRenderElementDepthRange());
+		mFillBackground->_setElementDepth(mSliderHandle->_getRenderElementDepthRange());
+
+		_registerChildElement(mSliderHandle);
+		_registerChildElement(mBackground);
+		_registerChildElement(mFillBackground);
+
+		mHandleMovedConn = mSliderHandle->onHandleMoved.connect(std::bind(&GUISlider::onHandleMoved, this, _1));
+	}
+
+	GUISlider::~GUISlider()
+	{
+		mHandleMovedConn.disconnect();
+	}
+
+	const String& GUISlider::getHandleStyleType()
+	{
+		static String HANDLE_STYLE_TYPE = "SliderHandle";
+		return HANDLE_STYLE_TYPE;
+	}
+
+	const String& GUISlider::getBackgroundStyleType()
+	{
+		static String BACKGROUND_STYLE_TYPE = "SliderBackground";
+		return BACKGROUND_STYLE_TYPE;
+	}
+
+	const String& GUISlider::getFillStyleType()
+	{
+		static String FILL_STYLE_TYPE = "SliderFill";
+		return FILL_STYLE_TYPE;
+	}
+
+	Vector2I GUISlider::_getOptimalSize() const
+	{
+		Vector2I optimalSize = mSliderHandle->_getOptimalSize();
+
+		Vector2I backgroundSize = mBackground->_getOptimalSize();
+		optimalSize.x = std::max(optimalSize.x, backgroundSize.x);
+		optimalSize.y = std::max(optimalSize.y, backgroundSize.y);
+
+		return optimalSize;
+	}
+
+	void GUISlider::_updateLayoutInternal(const GUILayoutData& data)
+	{
+		GUILayoutData childData = data;
+
+		if (mHorizontal)
+		{
+			Vector2I optimalSize = mBackground->_getOptimalSize();
+			childData.area.height = optimalSize.y;
+			childData.area.y = data.area.y + (INT32)((data.area.height - childData.area.height) * 0.5f);
+
+			childData.clipRect = data.area;
+			childData.clipRect.clip(data.clipRect);
+
+			mBackground->_setLayoutData(childData);
+
+			optimalSize = mSliderHandle->_getOptimalSize();
+			childData.area.height = optimalSize.y;
+			childData.area.y = data.area.y + (INT32)((data.area.height - childData.area.height) * 0.5f);
+
+			childData.clipRect = data.area;
+			childData.clipRect.clip(data.clipRect);
+
+			mSliderHandle->_setLayoutData(childData);
+			UINT32 handleWidth = optimalSize.x;
+
+			optimalSize = mFillBackground->_getOptimalSize();
+			childData.area.height = optimalSize.y;
+			childData.area.y = data.area.y + (INT32)((data.area.height - childData.area.height) * 0.5f);
+			childData.area.width = mSliderHandle->getHandlePosPx() + handleWidth / 2;
+
+			childData.clipRect = data.area;
+			childData.clipRect.clip(data.clipRect);
+
+			mFillBackground->_setLayoutData(childData);
+		}
+		else
+		{
+			Vector2I optimalSize = mBackground->_getOptimalSize();
+			childData.area.width = optimalSize.x;
+			childData.area.x = data.area.x + (INT32)((data.area.width - childData.area.width) * 0.5f);
+
+			childData.clipRect = data.area;
+			childData.clipRect.clip(data.clipRect);
+
+			mBackground->_setLayoutData(childData);
+
+			optimalSize = mSliderHandle->_getOptimalSize();
+			childData.area.width = optimalSize.x;
+			childData.area.x = data.area.x + (INT32)((data.area.width - childData.area.width) * 0.5f);
+
+			childData.clipRect = data.area;
+			childData.clipRect.clip(data.clipRect);
+
+			mSliderHandle->_setLayoutData(childData);
+			UINT32 handleHeight = optimalSize.y;
+
+			optimalSize = mFillBackground->_getOptimalSize();
+			childData.area.width = optimalSize.x;
+			childData.area.x = data.area.x + (INT32)((data.area.width - childData.area.width) * 0.5f);
+			childData.area.height = mSliderHandle->getHandlePosPx() + handleHeight / 2;
+
+			childData.clipRect = data.area;
+			childData.clipRect.clip(data.clipRect);
+
+			mFillBackground->_setLayoutData(childData);
+		}
+	}
+
+	void GUISlider::styleUpdated()
+	{
+		mBackground->setStyle(getSubStyleName(getBackgroundStyleType()));
+		mFillBackground->setStyle(getSubStyleName(getFillStyleType()));
+		mSliderHandle->setStyle(getSubStyleName(getHandleStyleType()));
+	}
+
+	void GUISlider::setPercent(float pct)
+	{
+		float oldHandlePos = mSliderHandle->getHandlePos();
+		mSliderHandle->_setHandlePos(pct);
+
+		if (oldHandlePos != mSliderHandle->getHandlePos())
+			mSliderHandle->_markLayoutAsDirty();
+	}
+
+	float GUISlider::getPercent() const
+	{
+		return mSliderHandle->getHandlePos();
+	}
+
+	float GUISlider::getValue() const
+	{
+		float diff = mMaxRange - mMinRange;
+		return mMinRange + diff * mSliderHandle->getHandlePos();
+	}
+
+	void GUISlider::setValue(float value)
+	{
+		float diff = mMaxRange - mMinRange;
+		float pct = (value - mMinRange) / diff;
+
+		setPercent(pct);
+	}
+
+	void GUISlider::setRange(float min, float max)
+	{
+		mMinRange = min;
+		mMaxRange = max;
+	}
+
+	void GUISlider::setStep(float step)
+	{
+		mSliderHandle->setStep(step);
+	}
+
+	void GUISlider::setTint(const Color& color)
+	{
+		mBackground->setTint(color);
+		mSliderHandle->setTint(color);
+	}
+
+	void GUISlider::onHandleMoved(float newPosition)
+	{
+		onChanged(getValue());
+	}
+
+	GUISliderHorz::GUISliderHorz(const String& styleName, const GUIDimensions& dimensions)
+		:GUISlider(true, styleName, dimensions)
+	{
+
+	}
+
+	GUISliderHorz* GUISliderHorz::create(const String& styleName)
+	{
+		return new (bs_alloc<GUISliderHorz>()) GUISliderHorz(getStyleName<GUISliderHorz>(styleName), GUIDimensions::create());
+	}
+
+	GUISliderHorz* GUISliderHorz::create(const GUIOptions& options, const String& styleName)
+	{
+		return new (bs_alloc<GUISliderHorz>()) GUISliderHorz(getStyleName<GUISliderHorz>(styleName), GUIDimensions::create(options));
+	}
+
+	const String& GUISliderHorz::getGUITypeName()
+	{
+		static String typeName = "SliderHorz";
+		return typeName;
+	}
+
+	GUISliderVert::GUISliderVert(const String& styleName, const GUIDimensions& dimensions)
+		:GUISlider(false, styleName, dimensions)
+	{
+
+	}
+
+	GUISliderVert* GUISliderVert::create(const String& styleName)
+	{
+		return new (bs_alloc<GUISliderVert>()) GUISliderVert(getStyleName<GUISliderVert>(styleName), GUIDimensions::create());
+	}
+
+	GUISliderVert* GUISliderVert::create(const GUIOptions& options, const String& styleName)
+	{
+		return new (bs_alloc<GUISliderVert>()) GUISliderVert(getStyleName<GUISliderVert>(styleName), GUIDimensions::create(options));
+	}
+
+	const String& GUISliderVert::getGUITypeName()
+	{
+		static String typeName = "SliderVert";
+		return typeName;
+	}
 }

+ 147 - 147
MBansheeEditor/Inspectors/LightInspector.cs

@@ -1,147 +1,147 @@
-using System.Collections.Generic;
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Renders an inspector for the <see cref="Light"/> component.
-    /// </summary>
-    [CustomInspector(typeof(Light))]
-    public class LightInspector : Inspector
-    {
-        private GUIEnumField lightTypeField = new GUIEnumField(typeof(LightType), new LocEdString("Light type"));
-        private GUIColorField colorField = new GUIColorField(new LocEdString("Color"));
-        private GUIFloatField rangeField = new GUIFloatField(new LocEdString("Range"));
-        private GUIFloatField intensityField = new GUIFloatField(new LocEdString("Intensity"));
-        private GUISliderField spotAngleField = new GUISliderField(1, 180, new LocEdString("Spot angle"));
-        private GUISliderField spotFalloffAngleField = new GUISliderField(1, 180, new LocEdString("Spot falloff angle"));
-        private GUIToggleField castShadowField = new GUIToggleField(new LocEdString("Cast shadow"));
-
-        private InspectableState modifyState;
-
-        /// <inheritdoc/>
-        protected internal override void Initialize()
-        {
-            if (InspectedObject != null)
-            {
-                Light light = (Light)InspectedObject;
-
-                lightTypeField.OnSelectionChanged += x =>
-                {
-                    light.Type = (LightType)x;
-
-                    ToggleTypeSpecificFields((LightType) x);
-                };
-
-                colorField.OnChanged += x =>
-                {
-                    light.Color = x;
-                    MarkAsModified();
-                    ConfirmModify();
-                };
-
-                rangeField.OnChanged += x => { light.Range = x; MarkAsModified(); };
-                rangeField.OnConfirmed += ConfirmModify;
-                rangeField.OnFocusLost += ConfirmModify;
-
-                intensityField.OnChanged += x => { light.Intensity = x; MarkAsModified(); };
-                intensityField.OnConfirmed += ConfirmModify;
-                intensityField.OnFocusLost += ConfirmModify;
-
-                spotAngleField.OnChanged += x => { light.SpotAngle = x; MarkAsModified(); };
-                spotAngleField.OnFocusLost += ConfirmModify;
-
-                spotFalloffAngleField.OnChanged += x => { light.SpotFalloffAngle = x; MarkAsModified(); };
-                spotFalloffAngleField.OnFocusLost += ConfirmModify;
-
-                castShadowField.OnChanged += x =>
-                {
-                    light.CastsShadow = x;
-                    MarkAsModified();
-                    ConfirmModify();
-                };
-                
-                Layout.AddElement(lightTypeField);
-                Layout.AddElement(colorField);
-                Layout.AddElement(intensityField);
-                Layout.AddElement(rangeField);
-                Layout.AddElement(spotAngleField);
-                Layout.AddElement(spotFalloffAngleField);
-                Layout.AddElement(castShadowField);
-
-                ToggleTypeSpecificFields(light.Type);
-            }
-        }
-
-        /// <inheritdoc/>
-        protected internal override InspectableState Refresh()
-        {
-            Light light = InspectedObject as Light;
-            if (light == null)
-                return InspectableState.NotModified;
-
-            LightType lightType = light.Type;
-            if (lightTypeField.Value != (ulong)lightType)
-            {
-                lightTypeField.Value = (ulong)lightType;
-                ToggleTypeSpecificFields(lightType);
-            }
-
-            colorField.Value = light.Color;
-            intensityField.Value = light.Intensity;
-            rangeField.Value = light.Range;
-            spotAngleField.Value = light.SpotAngle.Degrees;
-            spotFalloffAngleField.Value = light.SpotFalloffAngle.Degrees;
-            castShadowField.Value = light.CastsShadow;
-
-            InspectableState oldState = modifyState;
-            if (modifyState.HasFlag(InspectableState.Modified))
-                modifyState = InspectableState.NotModified;
-
-            return oldState;
-        }
-
-        /// <summary>
-        /// Enables or disables different GUI elements depending on the light type.
-        /// </summary>
-        /// <param name="type">Light type to show GUI elements for.</param>
-        private void ToggleTypeSpecificFields(LightType type)
-        {
-            if (type == LightType.Directional)
-            {
-                rangeField.Active = false;
-                spotAngleField.Active = false;
-                spotFalloffAngleField.Active = false;
-            }
-            else if (type == LightType.Point)
-            {
-                rangeField.Active = true;
-                spotAngleField.Active = false;
-                spotFalloffAngleField.Active = false;
-            }
-            else
-            {
-                rangeField.Active = true;
-                spotAngleField.Active = true;
-                spotFalloffAngleField.Active = true;
-            }
-        }
-
-        /// <summary>
-        /// Marks the contents of the inspector as modified.
-        /// </summary>
-        protected void MarkAsModified()
-        {
-            modifyState |= InspectableState.ModifyInProgress;
-        }
-
-        /// <summary>
-        /// Confirms any queued modifications.
-        /// </summary>
-        protected void ConfirmModify()
-        {
-            if (modifyState.HasFlag(InspectableState.ModifyInProgress))
-                modifyState |= InspectableState.Modified;
-        }
-    }
-}
+using System.Collections.Generic;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Renders an inspector for the <see cref="Light"/> component.
+    /// </summary>
+    [CustomInspector(typeof(Light))]
+    public class LightInspector : Inspector
+    {
+        private GUIEnumField lightTypeField = new GUIEnumField(typeof(LightType), new LocEdString("Light type"));
+        private GUIColorField colorField = new GUIColorField(new LocEdString("Color"));
+        private GUIFloatField rangeField = new GUIFloatField(new LocEdString("Range"));
+        private GUIFloatField intensityField = new GUIFloatField(new LocEdString("Intensity"));
+        private GUISliderField spotAngleField = new GUISliderField(1, 180, new LocEdString("Spot angle"));
+        private GUISliderField spotFalloffAngleField = new GUISliderField(1, 180, new LocEdString("Spot falloff angle"));
+        private GUIToggleField castShadowField = new GUIToggleField(new LocEdString("Cast shadow"));
+
+        private InspectableState modifyState;
+
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            if (InspectedObject != null)
+            {
+                Light light = (Light)InspectedObject;
+
+                lightTypeField.OnSelectionChanged += x =>
+                {
+                    light.Type = (LightType)x;
+
+                    ToggleTypeSpecificFields((LightType) x);
+                };
+
+                colorField.OnChanged += x =>
+                {
+                    light.Color = x;
+                    MarkAsModified();
+                    ConfirmModify();
+                };
+
+                rangeField.OnChanged += x => { light.Range = x; MarkAsModified(); };
+                rangeField.OnConfirmed += ConfirmModify;
+                rangeField.OnFocusLost += ConfirmModify;
+
+                intensityField.OnChanged += x => { light.Intensity = x; MarkAsModified(); };
+                intensityField.OnConfirmed += ConfirmModify;
+                intensityField.OnFocusLost += ConfirmModify;
+
+                spotAngleField.OnChanged += x => { light.SpotAngle = x; MarkAsModified(); };
+                spotAngleField.OnFocusLost += ConfirmModify;
+
+                spotFalloffAngleField.OnChanged += x => { light.SpotFalloffAngle = x; MarkAsModified(); };
+                spotFalloffAngleField.OnFocusLost += ConfirmModify;
+
+                castShadowField.OnChanged += x =>
+                {
+                    light.CastsShadow = x;
+                    MarkAsModified();
+                    ConfirmModify();
+                };
+                
+                Layout.AddElement(lightTypeField);
+                Layout.AddElement(colorField);
+                Layout.AddElement(intensityField);
+                Layout.AddElement(rangeField);
+                Layout.AddElement(spotAngleField);
+                Layout.AddElement(spotFalloffAngleField);
+                Layout.AddElement(castShadowField);
+
+                ToggleTypeSpecificFields(light.Type);
+            }
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            Light light = InspectedObject as Light;
+            if (light == null)
+                return InspectableState.NotModified;
+
+            LightType lightType = light.Type;
+            if (lightTypeField.Value != (ulong)lightType)
+            {
+                lightTypeField.Value = (ulong)lightType;
+                ToggleTypeSpecificFields(lightType);
+            }
+
+            colorField.Value = light.Color;
+            intensityField.Value = light.Intensity;
+            rangeField.Value = light.Range;
+            spotAngleField.Value = light.SpotAngle.Degrees;
+            spotFalloffAngleField.Value = light.SpotFalloffAngle.Degrees;
+            castShadowField.Value = light.CastsShadow;
+
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Enables or disables different GUI elements depending on the light type.
+        /// </summary>
+        /// <param name="type">Light type to show GUI elements for.</param>
+        private void ToggleTypeSpecificFields(LightType type)
+        {
+            if (type == LightType.Directional)
+            {
+                rangeField.Active = false;
+                spotAngleField.Active = false;
+                spotFalloffAngleField.Active = false;
+            }
+            else if (type == LightType.Point)
+            {
+                rangeField.Active = true;
+                spotAngleField.Active = false;
+                spotFalloffAngleField.Active = false;
+            }
+            else
+            {
+                rangeField.Active = true;
+                spotAngleField.Active = true;
+                spotFalloffAngleField.Active = true;
+            }
+        }
+
+        /// <summary>
+        /// Marks the contents of the inspector as modified.
+        /// </summary>
+        protected void MarkAsModified()
+        {
+            modifyState |= InspectableState.ModifyInProgress;
+        }
+
+        /// <summary>
+        /// Confirms any queued modifications.
+        /// </summary>
+        protected void ConfirmModify()
+        {
+            if (modifyState.HasFlag(InspectableState.ModifyInProgress))
+                modifyState |= InspectableState.Modified;
+        }
+    }
+}