Browse Source

Added support for GUI sub-styles
Updated editor fields so they resize properly, handle UndoRedo and handle focus

Marko Pintera 11 years ago
parent
commit
b0236b0eb1
30 changed files with 815 additions and 264 deletions
  1. 1 0
      BansheeEditor/Include/BsGUIColor.h
  2. 18 14
      BansheeEditor/Include/BsGUIColorField.h
  3. 79 32
      BansheeEditor/Include/BsGUIFieldBase.h
  4. 18 8
      BansheeEditor/Include/BsGUIFloatField.h
  5. 16 24
      BansheeEditor/Include/BsGUIGameObjectField.h
  6. 14 13
      BansheeEditor/Include/BsGUIIntField.h
  7. 15 3
      BansheeEditor/Include/BsGUITextField.h
  8. 8 3
      BansheeEditor/Include/BsGUIToggleField.h
  9. 8 1
      BansheeEditor/Include/BsGUIVector2Field.h
  10. 8 2
      BansheeEditor/Include/BsGUIVector3Field.h
  11. 8 2
      BansheeEditor/Include/BsGUIVector4Field.h
  12. 108 2
      BansheeEditor/Source/BsEditorGUI.cpp
  13. 2 1
      BansheeEditor/Source/BsGUIColor.cpp
  14. 77 27
      BansheeEditor/Source/BsGUIColorField.cpp
  15. 12 4
      BansheeEditor/Source/BsGUIFieldBase.cpp
  16. 48 9
      BansheeEditor/Source/BsGUIFloatField.cpp
  17. 92 37
      BansheeEditor/Source/BsGUIGameObjectField.cpp
  18. 20 18
      BansheeEditor/Source/BsGUIIntField.cpp
  19. 45 7
      BansheeEditor/Source/BsGUITextField.cpp
  20. 32 8
      BansheeEditor/Source/BsGUIToggleField.cpp
  21. 37 4
      BansheeEditor/Source/BsGUIVector2Field.cpp
  22. 40 5
      BansheeEditor/Source/BsGUIVector3Field.cpp
  23. 42 6
      BansheeEditor/Source/BsGUIVector4Field.cpp
  24. 16 0
      BansheeEngine/Include/BsGUIElement.h
  25. 2 0
      BansheeEngine/Include/BsGUIElementStyle.h
  26. 16 0
      BansheeEngine/Source/BsGUIElement.cpp
  27. 20 16
      Inspector.txt
  28. 5 6
      MBansheeEditor/GUI/GUIIntField.cs
  29. 2 2
      SBansheeEditor/Include/BsScriptGUIIntField.h
  30. 6 10
      SBansheeEditor/Source/BsScriptGUIIntField.cpp

+ 1 - 0
BansheeEditor/Include/BsGUIColor.h

@@ -20,6 +20,7 @@ namespace BansheeEngine
 		void setColor(const Color& color);
 		Color getColor() const { return mColor; }
 
+		Event<void(const Color&)> onValueChanged;
 	protected:
 		GUIColor(const String& styleName, const GUILayoutOptions& layoutOptions);
 		virtual ~GUIColor();

+ 18 - 14
BansheeEditor/Include/BsGUIColorField.h

@@ -2,6 +2,7 @@
 
 #include "BsEditorPrerequisites.h"
 #include "BsGUIElementContainer.h"
+#include "BsColor.h"
 
 namespace BansheeEngine
 {
@@ -11,31 +12,29 @@ namespace BansheeEngine
 
 	public:
 		static const String& getGUITypeName();
+		static const String& getLabelStyleType();
+		static const String& getColorInputStyleType();
 
 		static GUIColorField* create(const GUIContent& labelContent, 
-			const GUIOptions& layoutOptions, const String& labelStyle = StringUtil::BLANK, const String& toggleStyle = StringUtil::BLANK);
+			const GUIOptions& layoutOptions, const String& style = StringUtil::BLANK);
 
 		static GUIColorField* create(const HString& labelText, 
-			const GUIOptions& layoutOptions, const String& labelStyle = StringUtil::BLANK, const String& toggleStyle = StringUtil::BLANK);
+			const GUIOptions& layoutOptions, const String& style = StringUtil::BLANK);
 
-		static GUIColorField* create(const GUIOptions& layoutOptions, const String& labelStyle = StringUtil::BLANK, 
-			const String& toggleStyle = StringUtil::BLANK);
+		static GUIColorField* create(const GUIOptions& layoutOptions, const String& style = StringUtil::BLANK);
 
-		static GUIColorField* create(const GUIContent& labelContent, const String& labelStyle = StringUtil::BLANK, 
-			const String& toggleStyle = StringUtil::BLANK);
+		static GUIColorField* create(const GUIContent& labelContent, const String& style = StringUtil::BLANK);
 
-		static GUIColorField* create(const HString& labelText, const String& labelStyle = StringUtil::BLANK,
-			const String& toggleStyle = StringUtil::BLANK);
+		static GUIColorField* create(const HString& labelText, const String& style = StringUtil::BLANK);
 
-		static GUIColorField* create(const String& labelStyle = StringUtil::BLANK, const String& toggleStyle = StringUtil::BLANK);
+		static GUIColorField* create(const String& style = StringUtil::BLANK);
 
 		GUIColorField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, 
-			const String& labelStyle, const String& toggleStyle, const GUILayoutOptions& layoutOptions);
+			const String& style, const GUILayoutOptions& layoutOptions);
 
-		GUIColorField(const PrivatelyConstruct& dummy, const String& labelStyle, const String& toggleStyle, 
-			const GUILayoutOptions& layoutOptions);
+		GUIColorField(const PrivatelyConstruct& dummy, const String& style, const GUILayoutOptions& layoutOptions);
 
-		Color getValue() const;
+		Color getValue() const { return mValue; }
 		void setValue(const Color& value);
 
 		void setLabelWidth(UINT32 width);
@@ -44,11 +43,16 @@ namespace BansheeEngine
 			RectI clipRect, UINT8 widgetDepth, UINT16 areaDepth);
 
 		Vector2I _getOptimalSize() const;
+
+		Event<void(const Color&)> onValueChanged;
 	protected:
 		virtual ~GUIColorField();
 
-	protected:
+		void styleUpdated();
+		void valueChanged(const Color& newValue);
+
 		UINT32 mLabelWidth;
+		Color mValue;
 		GUILabel* mLabel;
 		GUIColor* mColor;
 	};

+ 79 - 32
BansheeEditor/Include/BsGUIFieldBase.h

@@ -18,10 +18,18 @@ namespace BansheeEngine
 			RectI clipRect, UINT8 widgetDepth, UINT16 areaDepth);
 
 		virtual Vector2I _getOptimalSize() const;
+
+		static const String& getLabelStyleType()
+		{
+			static String LABEL_STYLE_TYPE = "EditorFieldLabel";
+			return LABEL_STYLE_TYPE;
+		}
+
 	protected:
 		virtual ~GUIFieldBase() { }
 
-	protected:
+		virtual void styleUpdated();
+
 		static const UINT32 DEFAULT_LABEL_WIDTH;
 
 		GUILayout* mLayout;
@@ -32,77 +40,116 @@ namespace BansheeEngine
 	class TGUIField : public GUIFieldBase
 	{
 	public:
-		static T* create(const GUIContent& labelContent, UINT32 labelWidth, const GUIOptions& layoutOptions, 
-			const String& labelStyle = StringUtil::BLANK, const String& entryElementStyle = StringUtil::BLANK)
+		static T* create(const GUIContent& labelContent, UINT32 labelWidth, const GUIOptions& layoutOptions,
+			const String& style = StringUtil::BLANK)
 		{
-			return bs_new<T>(PrivatelyConstruct(), labelContent, labelWidth, labelStyle, entryElementStyle, 
+			const String* curStyle = &style;
+			if (*curStyle == StringUtil::BLANK)
+				curStyle = &T::getGUITypeName();
+
+			return bs_new<T>(PrivatelyConstruct(), labelContent, labelWidth, *curStyle,
 				GUILayoutOptions::create(layoutOptions), true);
 		}
 
-		static T* create(const GUIContent& labelContent, const GUIOptions& layoutOptions, 
-			const String& labelStyle = StringUtil::BLANK, const String& entryElementStyle = StringUtil::BLANK)
+		static T* create(const GUIContent& labelContent, const GUIOptions& layoutOptions,
+			const String& style = StringUtil::BLANK)
 		{
-			return bs_new<T>(PrivatelyConstruct(), labelContent, DEFAULT_LABEL_WIDTH, labelStyle, entryElementStyle, 
+			const String* curStyle = &style;
+			if (*curStyle == StringUtil::BLANK)
+				curStyle = &T::getGUITypeName();
+
+			return bs_new<T>(PrivatelyConstruct(), labelContent, DEFAULT_LABEL_WIDTH, *curStyle,
 				GUILayoutOptions::create(layoutOptions), true);
 		}
 
-		static T* create(const HString& labelText, UINT32 labelWidth, const GUIOptions& layoutOptions, 
-			const String& labelStyle = StringUtil::BLANK, const String& entryElementStyle = StringUtil::BLANK)
+		static T* create(const HString& labelText, UINT32 labelWidth, const GUIOptions& layoutOptions,
+			const String& style = StringUtil::BLANK)
 		{
-			return bs_new<T>(PrivatelyConstruct(), GUIContent(labelText), labelWidth, labelStyle, entryElementStyle, 
+			const String* curStyle = &style;
+			if (*curStyle == StringUtil::BLANK)
+				curStyle = &T::getGUITypeName();
+
+			return bs_new<T>(PrivatelyConstruct(), GUIContent(labelText), labelWidth, *curStyle,
 				GUILayoutOptions::create(layoutOptions), true);
 		}
 
-		static T* create(const HString& labelText, const GUIOptions& layoutOptions, 
-			const String& labelStyle = StringUtil::BLANK, const String& entryElementStyle = StringUtil::BLANK)
+		static T* create(const HString& labelText, const GUIOptions& layoutOptions,
+			const String& style = StringUtil::BLANK)
 		{
-			return bs_new<T>(PrivatelyConstruct(), GUIContent(labelText), DEFAULT_LABEL_WIDTH, labelStyle, entryElementStyle, 
+			const String* curStyle = &style;
+			if (*curStyle == StringUtil::BLANK)
+				curStyle = &T::getGUITypeName();
+
+			return bs_new<T>(PrivatelyConstruct(), GUIContent(labelText), DEFAULT_LABEL_WIDTH, *curStyle,
 				GUILayoutOptions::create(layoutOptions), true);
 		}
 
-		static T* create(const GUIOptions& layoutOptions, const String& entryElementStyle = StringUtil::BLANK)
+		static T* create(const GUIOptions& layoutOptions, const String& style = StringUtil::BLANK)
 		{
-			return bs_new<T>(PrivatelyConstruct(), GUIContent(), 0, StringUtil::BLANK, entryElementStyle,
+			const String* curStyle = &style;
+			if (*curStyle == StringUtil::BLANK)
+				curStyle = &T::getGUITypeName();
+
+			return bs_new<T>(PrivatelyConstruct(), GUIContent(), 0, *curStyle,
 				GUILayoutOptions::create(layoutOptions), false);
 		}
 
-		static T* create(const GUIContent& labelContent, UINT32 labelWidth, 
-			const String& labelStyle = StringUtil::BLANK, const String& entryElementStyle = StringUtil::BLANK)
+		static T* create(const GUIContent& labelContent, UINT32 labelWidth,
+			const String& style = StringUtil::BLANK)
 		{
-			return bs_new<T>(PrivatelyConstruct(), labelContent, labelWidth, labelStyle, entryElementStyle, 
-				GUILayoutOptions::create(), true);
+			const String* curStyle = &style;
+			if (*curStyle == StringUtil::BLANK)
+				curStyle = &T::getGUITypeName();
+
+			return bs_new<T>(PrivatelyConstruct(), labelContent, labelWidth, *curStyle, GUILayoutOptions::create(), true);
 		}
 
-		static T* create(const GUIContent& labelContent, 
-			const String& labelStyle = StringUtil::BLANK, const String& entryElementStyle = StringUtil::BLANK)
+		static T* create(const GUIContent& labelContent,
+			const String& style = StringUtil::BLANK)
 		{
-			return bs_new<T>(PrivatelyConstruct(), labelContent, DEFAULT_LABEL_WIDTH, labelStyle, entryElementStyle, 
+			const String* curStyle = &style;
+			if (*curStyle == StringUtil::BLANK)
+				curStyle = &T::getGUITypeName();
+
+			return bs_new<T>(PrivatelyConstruct(), labelContent, DEFAULT_LABEL_WIDTH, *curStyle,
 				GUILayoutOptions::create(), true);
 		}
 
-		static T* create(const HString& labelText, UINT32 labelWidth, 
-			const String& labelStyle = StringUtil::BLANK, const String& entryElementStyle = StringUtil::BLANK)
+		static T* create(const HString& labelText, UINT32 labelWidth,
+			const String& style = StringUtil::BLANK)
 		{
-			return bs_new<T>(PrivatelyConstruct(), GUIContent(labelText), labelWidth, labelStyle, entryElementStyle, 
+			const String* curStyle = &style;
+			if (*curStyle == StringUtil::BLANK)
+				curStyle = &T::getGUITypeName();
+
+			return bs_new<T>(PrivatelyConstruct(), GUIContent(labelText), labelWidth, *curStyle,
 				GUILayoutOptions::create(), true);
 		}
 
-		static T* create(const HString& labelText, 
-			const String& labelStyle = StringUtil::BLANK, const String& entryElementStyle = StringUtil::BLANK)
+		static T* create(const HString& labelText,
+			const String& style = StringUtil::BLANK)
 		{
-			return bs_new<T>(PrivatelyConstruct(), GUIContent(labelText), DEFAULT_LABEL_WIDTH, labelStyle, entryElementStyle, 
+			const String* curStyle = &style;
+			if (*curStyle == StringUtil::BLANK)
+				curStyle = &T::getGUITypeName();
+
+			return bs_new<T>(PrivatelyConstruct(), GUIContent(labelText), DEFAULT_LABEL_WIDTH, *curStyle,
 				GUILayoutOptions::create(), true);
 		}
 
-		static T* create(const String& entryElementStyle = StringUtil::BLANK)
+		static T* create(const String& style = StringUtil::BLANK)
 		{
-			return bs_new<T>(PrivatelyConstruct(), GUIContent(), 0, StringUtil::BLANK, entryElementStyle,
+			const String* curStyle = &style;
+			if (*curStyle == StringUtil::BLANK)
+				curStyle = &T::getGUITypeName();
+
+			return bs_new<T>(PrivatelyConstruct(), GUIContent(), 0, *curStyle,
 				GUILayoutOptions::create(), false);
 		}
 
 		TGUIField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
-			const String& labelStyle, const GUILayoutOptions& layoutOptions, bool withLabel)
-			:GUIFieldBase(dummy, labelContent, labelWidth, labelStyle, layoutOptions, withLabel)
+			const String& style, const GUILayoutOptions& layoutOptions, bool withLabel)
+			:GUIFieldBase(dummy, labelContent, labelWidth, style, layoutOptions, withLabel)
 		{ }
 	};
 }

+ 18 - 8
BansheeEditor/Include/BsGUIFloatField.h

@@ -9,28 +9,38 @@ namespace BansheeEngine
 	{
 	public:
 		static const String& getGUITypeName();
+		static const String& getInputStyleType();
 
 		GUIFloatField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
-			const String& labelStyle, const String& inputBoxStyle, const GUILayoutOptions& layoutOptions, bool withLabel);
+			const String& style, const GUILayoutOptions& layoutOptions, bool withLabel);
 
-		float getValue() const;
+		float getValue() const { return mValue; }
 		void setValue(float value);
 
+		bool hasInputFocus() const { return mHasInputFocus; }
+
+		Event<void(float)> onValueChanged;
 	protected:
 		virtual ~GUIFloatField();
 
 		void updateClippedBounds();
 
-	protected:
+		bool _hasCustomCursor(const Vector2I position, CursorType& type) const;
+		virtual bool mouseEvent(const GUIMouseEvent& ev);
+		void styleUpdated();
+
+		void valueChanged(const WString& newValue);
+		void focusGained();
+		void focusLost();
+
+		static bool floatFilter(const WString& str);
+
 		static const float DRAG_SPEED;
 
 		GUIInputBox* mInputBox;
+		float mValue;
 		INT32 mLastDragPos;
 		bool mIsDragging;
-
-		bool _hasCustomCursor(const Vector2I position, CursorType& type) const;
-		virtual bool mouseEvent(const GUIMouseEvent& ev);
-
-		static bool floatFilter(const WString& str);
+		bool mHasInputFocus;
 	};
 }

+ 16 - 24
BansheeEditor/Include/BsGUIGameObjectField.h

@@ -11,48 +11,40 @@ namespace BansheeEngine
 
 	public:
 		static const String& getGUITypeName();
+		static const String& getLabelStyleType();
+		static const String& getDropButtonStyleType();
+		static const String& getClearButtonStyleType();
 
 		static GUIGameObjectField* create(const GUIContent& labelContent, UINT32 labelWidth, const GUIOptions& layoutOptions, 
-			const String& labelStyle = StringUtil::BLANK, const String& dropButtonStyle = StringUtil::BLANK,
-			const String& clearButtonStyle = StringUtil::BLANK);
+			const String& style = StringUtil::BLANK);
 
 		static GUIGameObjectField* create(const GUIContent& labelContent, const GUIOptions& layoutOptions, 
-			const String& labelStyle = StringUtil::BLANK, const String& dropButtonStyle = StringUtil::BLANK,
-			const String& clearButtonStyle = StringUtil::BLANK);
+			const String& style = StringUtil::BLANK);
 
 		static GUIGameObjectField* create(const HString& labelText, UINT32 labelWidth, const GUIOptions& layoutOptions, 
-			const String& labelStyle = StringUtil::BLANK, const String& dropButtonStyle = StringUtil::BLANK,
-			const String& clearButtonStyle = StringUtil::BLANK);
+			const String& style = StringUtil::BLANK);
 
 		static GUIGameObjectField* create(const HString& labelText, const GUIOptions& layoutOptions, 
-			const String& labelStyle = StringUtil::BLANK, const String& dropButtonStyle = StringUtil::BLANK,
-			const String& clearButtonStyle = StringUtil::BLANK);
+			const String& style = StringUtil::BLANK);
 
-		static GUIGameObjectField* create(const GUIOptions& layoutOptions, const String& dropButtonStyle = StringUtil::BLANK,
-			const String& clearButtonStyle = StringUtil::BLANK);
+		static GUIGameObjectField* create(const GUIOptions& layoutOptions, const String& style = StringUtil::BLANK);
 
 		static GUIGameObjectField* create(const GUIContent& labelContent, UINT32 labelWidth, 
-			const String& labelStyle = StringUtil::BLANK, const String& dropButtonStyle = StringUtil::BLANK,
-			const String& clearButtonStyle = StringUtil::BLANK);
+			const String& style = StringUtil::BLANK);
 
 		static GUIGameObjectField* create(const GUIContent& labelContent, 
-			const String& labelStyle = StringUtil::BLANK, const String& dropButtonStyle = StringUtil::BLANK,
-			const String& clearButtonStyle = StringUtil::BLANK);
+			const String& style = StringUtil::BLANK);
 
 		static GUIGameObjectField* create(const HString& labelText, UINT32 labelWidth, 
-			const String& labelStyle = StringUtil::BLANK, const String& dropButtonStyle = StringUtil::BLANK,
-			const String& clearButtonStyle = StringUtil::BLANK);
+			const String& style = StringUtil::BLANK);
 
 		static GUIGameObjectField* create(const HString& labelText, 
-			const String& labelStyle = StringUtil::BLANK, const String& dropButtonStyle = StringUtil::BLANK,
-			const String& clearButtonStyle = StringUtil::BLANK);
+			const String& style = StringUtil::BLANK);
 
-		static GUIGameObjectField* create(const String& dropButtonStyle = StringUtil::BLANK,
-			const String& clearButtonStyle = StringUtil::BLANK);
+		static GUIGameObjectField* create(const String& style = StringUtil::BLANK);
 
 		GUIGameObjectField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, 
-			UINT32 labelWidth, const String& labelStyle, const String& dropButtonStyle,
-			const String& clearButtonStyle, const GUILayoutOptions& layoutOptions, bool withLabel);
+			UINT32 labelWidth, const String& style, const GUILayoutOptions& layoutOptions, bool withLabel);
 
 		HGameObject getValue() const;
 		void setValue(const HGameObject& value);
@@ -64,12 +56,12 @@ namespace BansheeEngine
 	private:
 		virtual ~GUIGameObjectField();
 
+		void styleUpdated();
+
 		void dataDropped(void* data);
 
 	private:
 		static const UINT32 DEFAULT_LABEL_WIDTH;
-		static const String DROP_BUTTON_STYLE;
-		static const String CLEAR_BUTTON_STYLE;
 
 		GUILayout* mLayout;
 		GUILabel* mLabel;

+ 14 - 13
BansheeEditor/Include/BsGUIIntField.h

@@ -9,38 +9,39 @@ namespace BansheeEngine
 	{
 	public:
 		static const String& getGUITypeName();
+		static const String& getInputStyleType();
 
 		GUIIntField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
-			const String& labelStyle, const String& inputBoxStyle, const GUILayoutOptions& layoutOptions, bool withLabel);
+			const String& style, const GUILayoutOptions& layoutOptions, bool withLabel);
 
 		INT32 getValue() const { return mValue; }
 		void setValue(INT32 value);
 
-		Event<void(INT32)> onValueChanged;
-
-		virtual Vector2I _getOptimalSize() const;
+		bool hasInputFocus() const { return mHasInputFocus; }
 
+		Event<void(INT32)> onValueChanged;
 	protected:
 		virtual ~GUIIntField();
 
 		void updateClippedBounds();
 
-	protected:
-		static const INT32 DRAG_SPEED;
-
-		GUIInputBox* mInputBox;
-		INT32 mValue;
-		INT32 mLastDragPos;
-		bool mIsDragging;
-		bool mIsDragCursorSet;
-
 		bool _hasCustomCursor(const Vector2I position, CursorType& type) const;
 		virtual bool mouseEvent(const GUIMouseEvent& ev);
+		void styleUpdated();
 
 		void valueChanged(const WString& newValue);
 		void focusGained();
 		void focusLost();
 
 		static bool intFilter(const WString& str);
+
+		static const INT32 DRAG_SPEED;
+
+		GUIInputBox* mInputBox;
+		INT32 mValue;
+		INT32 mLastDragPos;
+		bool mIsDragging;
+		bool mIsDragCursorSet;
+		bool mHasInputFocus;
 	};
 }

+ 15 - 3
BansheeEditor/Include/BsGUITextField.h

@@ -9,16 +9,28 @@ namespace BansheeEngine
 	{
 	public:
 		static const String& getGUITypeName();
+		static const String& getInputStyleType();
 
 		GUITextField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
-			const String& labelStyle, const String& inputBoxStyle, const GUILayoutOptions& layoutOptions, bool withLabel);
+			const String& style, const GUILayoutOptions& layoutOptions, bool withLabel);
 
-		WString getValue() const;
+		WString getValue() const { return mValue; }
 		void setValue(const WString& value);
+
+		bool hasInputFocus() const { return mHasInputFocus; }
+
+		Event<void(const WString&)> onValueChanged;
 	protected:
 		virtual ~GUITextField();
 
-	protected:
+		void styleUpdated();
+
+		void valueChanged(const WString& newValue);
+		void focusGained();
+		void focusLost();
+
 		GUIInputBox* mInputBox;
+		bool mHasInputFocus;
+		WString mValue;
 	};
 }

+ 8 - 3
BansheeEditor/Include/BsGUIToggleField.h

@@ -9,17 +9,22 @@ namespace BansheeEngine
 	{
 	public:
 		static const String& getGUITypeName();
+		static const String& getToggleStyleType();
 
 		GUIToggleField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
-			const String& labelStyle, const String& toggleStyle, const GUILayoutOptions& layoutOptions, bool withLabel);
+			const String& style, const GUILayoutOptions& layoutOptions, bool withLabel);
 
-		bool getValue() const;
+		bool getValue() const { return mValue; }
 		void setValue(bool value);
 
+		Event<void(bool)> onValueChanged;
 	protected:
 		virtual ~GUIToggleField() { }
 
-	protected:
+		void styleUpdated();
+		void valueChanged(bool newValue);
+
 		GUIToggle* mToggle;
+		bool mValue;
 	};
 }

+ 8 - 1
BansheeEditor/Include/BsGUIVector2Field.h

@@ -10,19 +10,26 @@ namespace BansheeEngine
 	{
 	public:
 		static const String& getGUITypeName();
+		static const String& getFloatFieldStyleType();
 
 		GUIVector2Field(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
-			const String& labelStyle, const String& inputBoxStyle, const GUILayoutOptions& layoutOptions, bool withLabel);
+			const String& style, const GUILayoutOptions& layoutOptions, bool withLabel);
 
 		Vector2 getValue() const;
 		void setValue(const Vector2& value);
 
+		bool hasInputFocus() const;
+
+		Event<void(const Vector2&)> onValueChanged;
 	protected:
 		virtual ~GUIVector2Field() { }
 
 	protected:
 		static const UINT32 ELEMENT_LABEL_WIDTH;
 
+		void styleUpdated();
+		void valueChanged(float newValue);
+
 		GUIFloatField* mFieldX;
 		GUIFloatField* mFieldY;
 	};

+ 8 - 2
BansheeEditor/Include/BsGUIVector3Field.h

@@ -10,17 +10,23 @@ namespace BansheeEngine
 	{
 	public:
 		static const String& getGUITypeName();
+		static const String& getFloatFieldStyleType();
 
 		GUIVector3Field(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
-			const String& labelStyle, const String& inputBoxStyle, const GUILayoutOptions& layoutOptions, bool withLabel);
+			const String& style, const GUILayoutOptions& layoutOptions, bool withLabel);
 
 		Vector3 getValue() const;
 		void setValue(const Vector3& value);
 
+		bool hasInputFocus() const;
+
+		Event<void(const Vector3&)> onValueChanged;
 	protected:
 		virtual ~GUIVector3Field() { }
 
-	protected:
+		void styleUpdated();
+		void valueChanged(float newValue);
+
 		static const UINT32 ELEMENT_LABEL_WIDTH;
 
 		GUIFloatField* mFieldX;

+ 8 - 2
BansheeEditor/Include/BsGUIVector4Field.h

@@ -10,17 +10,23 @@ namespace BansheeEngine
 	{
 	public:
 		static const String& getGUITypeName();
+		static const String& getFloatFieldStyleType();
 
 		GUIVector4Field(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
-			const String& labelStyle, const String& inputBoxStyle, const GUILayoutOptions& layoutOptions, bool withLabel);
+			const String& style, const GUILayoutOptions& layoutOptions, bool withLabel);
 
 		Vector4 getValue() const;
 		void setValue(const Vector4& value);
 
+		bool hasInputFocus() const;
+
+		Event<void(const Vector4&)> onValueChanged;
 	protected:
 		virtual ~GUIVector4Field() { }
 
-	protected:
+		void styleUpdated();
+		void valueChanged(float newValue);
+
 		static const UINT32 ELEMENT_LABEL_WIDTH;
 
 		GUIFloatField* mFieldX;

+ 108 - 2
BansheeEditor/Source/BsEditorGUI.cpp

@@ -10,6 +10,16 @@
 #include "BsSpriteTexture.h"
 #include "BsGUITreeViewEditBox.h"
 
+#include "BsGUIIntField.h"
+#include "BsGUIFloatField.h"
+#include "BsGUIColorField.h"
+#include "BsGUITextField.h"
+#include "BsGUIToggleField.h"
+#include "BsGUIVector2Field.h"
+#include "BsGUIVector3Field.h"
+#include "BsGUIVector4Field.h"
+#include "BsGUIGameObjectField.h"
+
 #include "BsFont.h"
 #include "BsFontImportOptions.h"
 #include "BsImporter.h"
@@ -803,7 +813,7 @@ namespace BansheeEngine
 		objectDropStyle.textHorzAlign = THA_Center;
 		objectDropStyle.textVertAlign = TVA_Center;
 
-		mSkin.setStyle("DropButton", objectDropStyle);
+		mSkin.setStyle(GUIGameObjectField::getDropButtonStyleType(), objectDropStyle);
 
 		GUIElementStyle objectClearBtnStyle;
 		objectClearBtnStyle.normal.texture = getTexture(ObjectClearBtnNormalTex);
@@ -814,8 +824,104 @@ namespace BansheeEngine
 		objectClearBtnStyle.height = 15;
 		objectClearBtnStyle.width = 13;
 
-		mSkin.setStyle("ObjectClearButton", objectClearBtnStyle);
+		mSkin.setStyle(GUIGameObjectField::getClearButtonStyleType(), objectClearBtnStyle);
+
+		GUIElementStyle editorObjectFieldStyle;
+		editorObjectFieldStyle.fixedHeight = true;
+		editorObjectFieldStyle.height = 15;
+		editorObjectFieldStyle.minWidth = 30;
+		editorObjectFieldStyle.subStyles[GUIGameObjectField::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorObjectFieldStyle.subStyles[GUIGameObjectField::getDropButtonStyleType()] = GUIGameObjectField::getDropButtonStyleType();
+		editorObjectFieldStyle.subStyles[GUIGameObjectField::getClearButtonStyleType()] = GUIGameObjectField::getClearButtonStyleType();
+
+		mSkin.setStyle(GUIGameObjectField::getGUITypeName(), editorObjectFieldStyle);
+
+		/************************************************************************/
+		/* 								EDITOR FIELDS                      		*/
+		/************************************************************************/
 
+		GUIElementStyle editorFieldLabelStyle;
+		editorFieldLabelStyle.font = font;
+		editorFieldLabelStyle.fontSize = DefaultFontSize;
+		editorFieldLabelStyle.fixedWidth = false;
+		editorFieldLabelStyle.fixedHeight = true;
+		editorFieldLabelStyle.height = 11;
+		editorFieldLabelStyle.minWidth = 10;
+		editorFieldLabelStyle.textHorzAlign = THA_Left;
+
+		mSkin.setStyle(GUITextField::getLabelStyleType(), editorFieldLabelStyle);
+
+		GUIElementStyle editorIntFieldStyle;
+		editorIntFieldStyle.fixedHeight = true;
+		editorIntFieldStyle.height = 15;
+		editorIntFieldStyle.minWidth = 30;
+		editorIntFieldStyle.subStyles[GUIIntField::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorIntFieldStyle.subStyles[GUIIntField::getInputStyleType()] = GUIInputBox::getGUITypeName();
+
+		mSkin.setStyle(GUIIntField::getGUITypeName(), editorIntFieldStyle);
+
+		GUIElementStyle editorFloatFieldStyle;
+		editorFloatFieldStyle.fixedHeight = true;
+		editorFloatFieldStyle.height = 15;
+		editorFloatFieldStyle.minWidth = 30;
+		editorFloatFieldStyle.subStyles[GUIFloatField::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorFloatFieldStyle.subStyles[GUIFloatField::getInputStyleType()] = GUIInputBox::getGUITypeName();
+
+		mSkin.setStyle(GUIFloatField::getGUITypeName(), editorFloatFieldStyle);
+
+		GUIElementStyle editorTextFieldStyle;
+		editorTextFieldStyle.fixedHeight = true;
+		editorTextFieldStyle.height = 15;
+		editorTextFieldStyle.minWidth = 30;
+		editorTextFieldStyle.subStyles[GUITextField::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorTextFieldStyle.subStyles[GUITextField::getInputStyleType()] = GUIInputBox::getGUITypeName();
+
+		mSkin.setStyle(GUITextField::getGUITypeName(), editorTextFieldStyle);
+
+		GUIElementStyle editorColorFieldStyle;
+		editorColorFieldStyle.fixedHeight = true;
+		editorColorFieldStyle.height = 15;
+		editorColorFieldStyle.minWidth = 30;
+		editorColorFieldStyle.subStyles[GUIColorField::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorColorFieldStyle.subStyles[GUIColorField::getColorInputStyleType()] = GUIColor::getGUITypeName();
+
+		mSkin.setStyle(GUIColorField::getGUITypeName(), editorColorFieldStyle);
+
+		GUIElementStyle editorToggleFieldStyle;
+		editorToggleFieldStyle.fixedHeight = true;
+		editorToggleFieldStyle.height = 15;
+		editorToggleFieldStyle.minWidth = 30;
+		editorToggleFieldStyle.subStyles[GUIToggleField::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorToggleFieldStyle.subStyles[GUIToggleField::getToggleStyleType()] = GUIToggle::getGUITypeName();
+
+		mSkin.setStyle(GUIToggleField::getGUITypeName(), editorToggleFieldStyle);
+
+		GUIElementStyle editorVector2FieldStyle;
+		editorVector2FieldStyle.fixedHeight = true;
+		editorVector2FieldStyle.height = 30;
+		editorVector2FieldStyle.minWidth = 30;
+		editorVector2FieldStyle.subStyles[GUIVector2Field::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorVector2FieldStyle.subStyles[GUIVector2Field::getFloatFieldStyleType()] = GUIFloatField::getGUITypeName();
+
+		mSkin.setStyle(GUIVector2Field::getGUITypeName(), editorVector2FieldStyle);
+
+		GUIElementStyle editorVector3FieldStyle;
+		editorVector3FieldStyle.fixedHeight = true;
+		editorVector3FieldStyle.height = 30;
+		editorVector3FieldStyle.minWidth = 30;
+		editorVector3FieldStyle.subStyles[GUIVector3Field::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorVector3FieldStyle.subStyles[GUIVector3Field::getFloatFieldStyleType()] = GUIFloatField::getGUITypeName();
+
+		mSkin.setStyle(GUIVector3Field::getGUITypeName(), editorVector3FieldStyle);
+
+		GUIElementStyle editorVector4FieldStyle;
+		editorVector4FieldStyle.fixedHeight = true;
+		editorVector4FieldStyle.height = 30;
+		editorVector4FieldStyle.minWidth = 30;
+		editorVector4FieldStyle.subStyles[GUIVector4Field::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorVector4FieldStyle.subStyles[GUIVector4Field::getFloatFieldStyleType()] = GUIFloatField::getGUITypeName();
+
+		mSkin.setStyle(GUIVector4Field::getGUITypeName(), editorVector4FieldStyle);
 	}
 
 	HSpriteTexture EditorGUI::getTexture(const WString& name)

+ 2 - 1
BansheeEditor/Source/BsGUIColor.cpp

@@ -149,7 +149,8 @@ namespace BansheeEngine
 	{
 		if(ev.getType() == GUIMouseEventType::MouseUp)
 		{
-			// TODO
+			// TODO - Open color picker window
+			//      - Trigger onValueChanged when done
 
 			return true;
 		}

+ 77 - 27
BansheeEditor/Source/BsGUIColorField.cpp

@@ -7,25 +7,30 @@
 #include "BsGUIWidget.h"
 #include "BsGUIMouseEvent.h"
 #include "BsGUIWidget.h"
+#include "BsCmdInputFieldValueChange.h"
+
+using namespace std::placeholders;
 
 namespace BansheeEngine
 {
 	GUIColorField::GUIColorField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, 
-		const String& labelStyle, const String& colorStyle, const GUILayoutOptions& layoutOptions)
-		:GUIElementContainer(layoutOptions), mLabel(nullptr), mColor(nullptr), mLabelWidth(100)
+		const String& style, const GUILayoutOptions& layoutOptions)
+		:GUIElementContainer(layoutOptions, style), mLabel(nullptr), mColor(nullptr), mLabelWidth(100)
 	{
-		mLabel = GUILabel::create(labelContent, labelStyle);
-		mColor = GUIColor::create(colorStyle);
+		mLabel = GUILabel::create(labelContent, getSubStyleName(getLabelStyleType()));
+		mColor = GUIColor::create(getSubStyleName(getColorInputStyleType()));
+
+		mColor->onValueChanged.connect(std::bind(&GUIColorField::valueChanged, this, _1));
 
 		_registerChildElement(mLabel);
 		_registerChildElement(mColor);
 	}
 
 	GUIColorField::GUIColorField(const PrivatelyConstruct& dummy, 
-		const String& labelStyle, const String& colorStyle, const GUILayoutOptions& layoutOptions)
-		:GUIElementContainer(layoutOptions), mLabel(nullptr), mColor(nullptr), mLabelWidth(100)
+		const String& style, const GUILayoutOptions& layoutOptions)
+		:GUIElementContainer(layoutOptions, style), mLabel(nullptr), mColor(nullptr), mLabelWidth(100)
 	{
-		mColor = GUIColor::create(colorStyle);
+		mColor = GUIColor::create(style);
 
 		_registerChildElement(mColor);
 	}
@@ -36,52 +41,69 @@ namespace BansheeEngine
 	}
 
 	GUIColorField* GUIColorField::create(const GUIContent& labelContent, const GUIOptions& layoutOptions, 
-		const String& labelStyle, const String& toggleStyle)
+		const String& style)
 	{
-		return bs_new<GUIColorField>(PrivatelyConstruct(), labelContent, labelStyle, toggleStyle, 
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIColorField>(PrivatelyConstruct(), labelContent, *curStyle,
 			GUILayoutOptions::create(layoutOptions));
 	}
 
-	GUIColorField* GUIColorField::create(const GUIContent& labelContent, const String& labelStyle, 
-		const String& toggleStyle)
+	GUIColorField* GUIColorField::create(const GUIContent& labelContent, const String& style)
 	{
-		return bs_new<GUIColorField>(PrivatelyConstruct(), labelContent, labelStyle, toggleStyle, 
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIColorField>(PrivatelyConstruct(), labelContent, *curStyle,
 			GUILayoutOptions::create());
 	}
 
 	GUIColorField* GUIColorField::create(const HString& labelContent, const GUIOptions& layoutOptions, 
-		const String& labelStyle, const String& toggleStyle)
+		const String& style)
 	{
-		return bs_new<GUIColorField>(PrivatelyConstruct(), GUIContent(labelContent), labelStyle, 
-			toggleStyle, GUILayoutOptions::create(layoutOptions));
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIColorField>(PrivatelyConstruct(), GUIContent(labelContent), *curStyle,
+			GUILayoutOptions::create(layoutOptions));
 	}
 
-	GUIColorField* GUIColorField::create( const HString& labelContent, const String& labelStyle, 
-		const String& toggleStyle)
+	GUIColorField* GUIColorField::create(const HString& labelContent, const String& style)
 	{
-		return bs_new<GUIColorField>(PrivatelyConstruct(), GUIContent(labelContent), labelStyle, toggleStyle, 
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIColorField>(PrivatelyConstruct(), GUIContent(labelContent), *curStyle,
 			GUILayoutOptions::create());
 	}
 
-	GUIColorField* GUIColorField::create(const GUIOptions& layoutOptions, const String& labelStyle, 
-		const String& toggleStyle)
+	GUIColorField* GUIColorField::create(const GUIOptions& layoutOptions, const String& style)
 	{
-		return bs_new<GUIColorField>(PrivatelyConstruct(), labelStyle, toggleStyle, 
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIColorField>(PrivatelyConstruct(), *curStyle,
 			GUILayoutOptions::create(layoutOptions));
 	}
 
-	GUIColorField* GUIColorField::create(const String& labelStyle, const String& toggleStyle)
+	GUIColorField* GUIColorField::create(const String& style)
 	{
-		return bs_new<GUIColorField>(PrivatelyConstruct(), labelStyle, toggleStyle, GUILayoutOptions::create());
-	}
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
 
-	Color GUIColorField::getValue() const
-	{
-		return mColor->getColor();
+		return bs_new<GUIColorField>(PrivatelyConstruct(), *curStyle, GUILayoutOptions::create());
 	}
 
 	void GUIColorField::setValue(const Color& color)
 	{
+		mValue = color;
 		mColor->setColor(color);
 	}
 
@@ -148,9 +170,37 @@ namespace BansheeEngine
 		return optimalsize;
 	}
 
+	void GUIColorField::styleUpdated()
+	{
+		if (mLabel != nullptr)
+			mLabel->setStyle(getSubStyleName(getLabelStyleType()));
+
+		mColor->setStyle(getSubStyleName(getColorInputStyleType()));
+	}
+
+	void GUIColorField::valueChanged(const Color& newValue)
+	{
+		setValue(newValue);
+
+		if (!onValueChanged.empty())
+			onValueChanged(newValue);
+	}
+
 	const String& GUIColorField::getGUITypeName()
 	{
 		static String typeName = "GUIColorField";
 		return typeName;
 	}
+
+	const String& GUIColorField::getLabelStyleType()
+	{
+		static String STYLE_TYPE = "EditorFieldLabel";
+		return STYLE_TYPE;
+	}
+
+	const String& GUIColorField::getColorInputStyleType()
+	{
+		static String STYLE_TYPE = "EditorFieldColor";
+		return STYLE_TYPE;
+	}
 }

+ 12 - 4
BansheeEditor/Source/BsGUIFieldBase.cpp

@@ -3,20 +3,21 @@
 #include "BsGUILayout.h"
 #include "BsGUIWidget.h"
 #include "BsGUISkin.h"
+#include "BsGUILayoutUtility.h"
 
 namespace BansheeEngine
 {
 	const UINT32 GUIFieldBase::DEFAULT_LABEL_WIDTH = 100;
 
 	GUIFieldBase::GUIFieldBase(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
-		const String& labelStyle, const GUILayoutOptions& layoutOptions, bool withLabel)
-		:GUIElementContainer(layoutOptions), mLabel(nullptr)
+		const String& style, const GUILayoutOptions& layoutOptions, bool withLabel)
+		:GUIElementContainer(layoutOptions, style), mLabel(nullptr)
 	{
 		mLayout = &addLayoutXInternal(this);
 
 		if(withLabel)
 		{
-			mLabel = GUILabel::create(labelContent, GUIOptions(GUIOption::fixedWidth(labelWidth)), labelStyle);
+			mLabel = GUILabel::create(labelContent, GUIOptions(GUIOption::fixedWidth(labelWidth)), getSubStyleName(getLabelStyleType()));
 			mLayout->addElement(mLabel);
 		}
 	}
@@ -29,6 +30,13 @@ namespace BansheeEngine
 
 	Vector2I GUIFieldBase::_getOptimalSize() const
 	{
-		return mLayout->_getOptimalSize();
+		return GUILayoutUtility::calcOptimalSize(mLayout);
+	}
+
+
+	void GUIFieldBase::styleUpdated()
+	{
+		if (mLabel != nullptr)
+			mLabel->setStyle(getSubStyleName(getLabelStyleType()));
 	}
 }

+ 48 - 9
BansheeEditor/Source/BsGUIFloatField.cpp

@@ -10,20 +10,27 @@
 #include "BsCursor.h"
 #include "BsGUIWidget.h"
 #include "BsViewport.h"
+#include "BsCmdInputFieldValueChange.h"
 #include <regex>
 
+using namespace std::placeholders;
+
 namespace BansheeEngine
 {
 	const float GUIFloatField::DRAG_SPEED = 0.05f;
 
 	GUIFloatField::GUIFloatField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth, 
-		const String& labelStyle, const String& inputBoxStyle, const GUILayoutOptions& layoutOptions, bool withLabel)
-		:TGUIField(dummy, labelContent, labelWidth, labelStyle, layoutOptions, withLabel), mInputBox(nullptr), mIsDragging(false),
-		mLastDragPos(0)
+		const String& style, const GUILayoutOptions& layoutOptions, bool withLabel)
+		:TGUIField(dummy, labelContent, labelWidth, style, layoutOptions, withLabel), mInputBox(nullptr), mIsDragging(false),
+		mLastDragPos(0), mHasInputFocus(false), mValue(0.0f)
 	{
-		mInputBox = GUIInputBox::create(false, GUIOptions(GUIOption::flexibleWidth()), inputBoxStyle);
+		mInputBox = GUIInputBox::create(false, GUIOptions(GUIOption::flexibleWidth()), getSubStyleName(getInputStyleType()));
 		mInputBox->setFilter(&GUIFloatField::floatFilter);
 
+		mInputBox->onValueChanged.connect(std::bind(&GUIFloatField::valueChanged, this, _1));
+		mInputBox->onFocusGained.connect(std::bind(&GUIFloatField::focusGained, this));
+		mInputBox->onFocusLost.connect(std::bind(&GUIFloatField::focusLost, this));
+
 		mLayout->addElement(mInputBox);
 
 		setValue(0);
@@ -114,13 +121,9 @@ namespace BansheeEngine
 		return false;
 	}
 
-	float GUIFloatField::getValue() const
-	{
-		return parseFloat(mInputBox->getText());
-	}
-
 	void GUIFloatField::setValue(float value)
 	{
+		mValue = value;
 		mInputBox->setText(toWString(value));
 	}
 
@@ -136,6 +139,42 @@ namespace BansheeEngine
 		return typeName;
 	}
 
+	const String& GUIFloatField::getInputStyleType()
+	{
+		static String LABEL_STYLE_TYPE = "EditorFieldInput";
+		return LABEL_STYLE_TYPE;
+	}
+
+	void GUIFloatField::styleUpdated()
+	{
+		if (mLabel != nullptr)
+			mLabel->setStyle(getSubStyleName(getLabelStyleType()));
+
+		mInputBox->setStyle(getSubStyleName(getInputStyleType()));
+	}
+
+	void GUIFloatField::valueChanged(const WString& newValue)
+	{
+		float newFloatValue = parseFloat(newValue);
+
+		CmdInputFieldValueChange<GUIFloatField, float>::execute(this, newFloatValue);
+
+		if (!onValueChanged.empty())
+			onValueChanged(newFloatValue);
+	}
+
+	void GUIFloatField::focusGained()
+	{
+		UndoRedo::instance().pushGroup("InputBox");
+		mHasInputFocus = true;
+	}
+
+	void GUIFloatField::focusLost()
+	{
+		UndoRedo::instance().popGroup("InputBox");
+		mHasInputFocus = false;
+	}
+
 	bool GUIFloatField::floatFilter(const WString& str)
 	{
 		return std::regex_match(str, std::wregex(L"-?(\\d+(\\.\\d*)?)?"));

+ 92 - 37
BansheeEditor/Source/BsGUIGameObjectField.cpp

@@ -16,32 +16,21 @@ using namespace std::placeholders;
 namespace BansheeEngine
 {
 	const UINT32 GUIGameObjectField::DEFAULT_LABEL_WIDTH = 100;
-	const String GUIGameObjectField::DROP_BUTTON_STYLE = "DropButton";
-	const String GUIGameObjectField::CLEAR_BUTTON_STYLE = "ObjectClearButton";
 
 	GUIGameObjectField::GUIGameObjectField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
-		const String& labelStyle, const String& dropButtonStyle, const String& clearButtonStyle, const GUILayoutOptions& layoutOptions, bool withLabel)
-		:GUIElementContainer(layoutOptions), mLabel(nullptr), mClearButton(nullptr), mDropButton(nullptr), mInstanceId(0)
+		const String& style, const GUILayoutOptions& layoutOptions, bool withLabel)
+		:GUIElementContainer(layoutOptions, style), mLabel(nullptr), mClearButton(nullptr), mDropButton(nullptr), mInstanceId(0)
 	{
 		mLayout = &addLayoutXInternal(this);
 
 		if(withLabel)
 		{
-			mLabel = GUILabel::create(labelContent, GUIOptions(GUIOption::fixedWidth(labelWidth)), labelStyle);
+			mLabel = GUILabel::create(labelContent, GUIOptions(GUIOption::fixedWidth(labelWidth)), getSubStyleName(getLabelStyleType()));
 			mLayout->addElement(mLabel);
 		}
 
-		const String* curDropButtonStyle = &dropButtonStyle;
-		const String* curClearButtonStyle = &clearButtonStyle;
-
-		if(*curDropButtonStyle == StringUtil::BLANK)
-			curDropButtonStyle = &DROP_BUTTON_STYLE;
-
-		if(*curClearButtonStyle == StringUtil::BLANK)
-			curClearButtonStyle = &CLEAR_BUTTON_STYLE;
-
-		mDropButton = GUIDropButton::create((UINT32)DragAndDropType::SceneObject, GUIOptions(GUIOption::flexibleWidth()), *curDropButtonStyle);
-		mClearButton = GUIButton::create(HString(L""), *curClearButtonStyle);
+		mDropButton = GUIDropButton::create((UINT32)DragAndDropType::SceneObject, GUIOptions(GUIOption::flexibleWidth()), getSubStyleName(getDropButtonStyleType()));
+		mClearButton = GUIButton::create(HString(L""), getSubStyleName(getClearButtonStyleType()));
 
 		mLayout->addElement(mDropButton);
 		mLayout->addElement(mClearButton);
@@ -55,71 +44,110 @@ namespace BansheeEngine
 	}
 
 	GUIGameObjectField* GUIGameObjectField::create(const GUIContent& labelContent, UINT32 labelWidth, const GUIOptions& layoutOptions, 
-		const String& labelStyle, const String& dropButtonStyle, const String& clearButtonStyle)
+		const String& style)
 	{
-		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), labelContent, labelWidth, labelStyle, dropButtonStyle, clearButtonStyle,
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), labelContent, labelWidth, *curStyle,
 			GUILayoutOptions::create(layoutOptions), true);
 	}
 
 	GUIGameObjectField* GUIGameObjectField::create(const GUIContent& labelContent, const GUIOptions& layoutOptions, 
-		const String& labelStyle, const String& dropButtonStyle, const String& clearButtonStyle)
+		const String& style)
 	{
-		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), labelContent, DEFAULT_LABEL_WIDTH, labelStyle, dropButtonStyle, clearButtonStyle,
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), labelContent, DEFAULT_LABEL_WIDTH, *curStyle,
 			GUILayoutOptions::create(layoutOptions), true);
 	}
 
 	GUIGameObjectField* GUIGameObjectField::create(const HString& labelText, UINT32 labelWidth, const GUIOptions& layoutOptions, 
-		const String& labelStyle, const String& dropButtonStyle, const String& clearButtonStyle)
+		const String& style)
 	{
-		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), GUIContent(labelText), labelWidth, labelStyle, dropButtonStyle, clearButtonStyle,
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), GUIContent(labelText), labelWidth, *curStyle,
 			GUILayoutOptions::create(layoutOptions), true);
 	}
 
 	GUIGameObjectField* GUIGameObjectField::create(const HString& labelText, const GUIOptions& layoutOptions, 
-		const String& labelStyle, const String& dropButtonStyle, const String& clearButtonStyle)
+		const String& style)
 	{
-		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), GUIContent(labelText), DEFAULT_LABEL_WIDTH, labelStyle, dropButtonStyle, clearButtonStyle, 
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), GUIContent(labelText), DEFAULT_LABEL_WIDTH, *curStyle,
 			GUILayoutOptions::create(layoutOptions), true);
 	}
 
-	GUIGameObjectField* GUIGameObjectField::create(const GUIOptions& layoutOptions, const String& dropButtonStyle,
-		const String& clearButtonStyle)
+	GUIGameObjectField* GUIGameObjectField::create(const GUIOptions& layoutOptions, const String& style)
 	{
-		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), GUIContent(), 0, nullptr, dropButtonStyle, clearButtonStyle,
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), GUIContent(), 0, *curStyle,
 			GUILayoutOptions::create(layoutOptions), false);
 	}
 
 	GUIGameObjectField* GUIGameObjectField::create(const GUIContent& labelContent, UINT32 labelWidth, 
-		const String& labelStyle, const String& dropButtonStyle, const String& clearButtonStyle)
+		const String& style)
 	{
-		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), labelContent, labelWidth, labelStyle, dropButtonStyle, clearButtonStyle,
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), labelContent, labelWidth, *curStyle,
 			GUILayoutOptions::create(), true);
 	}
 
 	GUIGameObjectField* GUIGameObjectField::create(const GUIContent& labelContent, 
-		const String& labelStyle, const String& dropButtonStyle, const String& clearButtonStyle)
+		const String& style)
 	{
-		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), labelContent, DEFAULT_LABEL_WIDTH, labelStyle, dropButtonStyle, clearButtonStyle,
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), labelContent, DEFAULT_LABEL_WIDTH, *curStyle,
 			GUILayoutOptions::create(), true);
 	}
 
 	GUIGameObjectField* GUIGameObjectField::create(const HString& labelText, UINT32 labelWidth, 
-		const String& labelStyle, const String& dropButtonStyle, const String& clearButtonStyle)
+		const String& style)
 	{
-		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), GUIContent(labelText), labelWidth, labelStyle, dropButtonStyle, clearButtonStyle,
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), GUIContent(labelText), labelWidth, *curStyle,
 			GUILayoutOptions::create(), true);
 	}
 
 	GUIGameObjectField* GUIGameObjectField::create(const HString& labelText, 
-		const String& labelStyle, const String& dropButtonStyle, const String& clearButtonStyle)
+		const String& style)
 	{
-		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), GUIContent(labelText), DEFAULT_LABEL_WIDTH, labelStyle, dropButtonStyle, clearButtonStyle, 
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), GUIContent(labelText), DEFAULT_LABEL_WIDTH, *curStyle,
 			GUILayoutOptions::create(), true);
 	}
 
-	GUIGameObjectField* GUIGameObjectField::create(const String& dropButtonStyle, const String& clearButtonStyle)
+	GUIGameObjectField* GUIGameObjectField::create(const String& style)
 	{
-		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), GUIContent(), 0, nullptr, dropButtonStyle, clearButtonStyle,
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &getGUITypeName();
+
+		return bs_new<GUIGameObjectField>(PrivatelyConstruct(), GUIContent(), 0, *curStyle,
 			GUILayoutOptions::create(), false);
 	}
 
@@ -165,9 +193,36 @@ namespace BansheeEngine
 		// TODO
 	}
 
+	void GUIGameObjectField::styleUpdated()
+	{
+		if (mLabel != nullptr)
+			mLabel->setStyle(getSubStyleName(getLabelStyleType()));
+
+		mDropButton->setStyle(getSubStyleName(getDropButtonStyleType()));
+		mClearButton->setStyle(getSubStyleName(getClearButtonStyleType()));
+	}
+
 	const String& GUIGameObjectField::getGUITypeName()
 	{
 		static String typeName = "GUIGameObjectField";
 		return typeName;
 	}
+
+	const String& GUIGameObjectField::getLabelStyleType()
+	{
+		static String STYLE_TYPE = "EditorFieldLabel";
+		return STYLE_TYPE;
+	}
+
+	const String& GUIGameObjectField::getDropButtonStyleType()
+	{
+		static String typeName = "DropButton";
+		return typeName;
+	}
+
+	const String& GUIGameObjectField::getClearButtonStyleType()
+	{
+		static String typeName = "ObjectClearButton";
+		return typeName;
+	}
 }

+ 20 - 18
BansheeEditor/Source/BsGUIIntField.cpp

@@ -21,11 +21,11 @@ namespace BansheeEngine
 	const INT32 GUIIntField::DRAG_SPEED = 5;
 
 	GUIIntField::GUIIntField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
-		const String& labelStyle, const String& inputBoxStyle, const GUILayoutOptions& layoutOptions, bool withLabel)
-		:TGUIField(dummy, labelContent, labelWidth, labelStyle, layoutOptions, withLabel), mInputBox(nullptr), mIsDragging(false),
-		mLastDragPos(0), mIsDragCursorSet(false)
+		const String& style, const GUILayoutOptions& layoutOptions, bool withLabel)
+		:TGUIField(dummy, labelContent, labelWidth, style, layoutOptions, withLabel), mInputBox(nullptr), mIsDragging(false),
+		mLastDragPos(0), mIsDragCursorSet(false), mHasInputFocus(false)
 	{
-		mInputBox = GUIInputBox::create(false, GUIOptions(GUIOption::flexibleWidth()), inputBoxStyle);
+		mInputBox = GUIInputBox::create(false, GUIOptions(GUIOption::flexibleWidth()), getSubStyleName(getInputStyleType()));
 		mInputBox->setFilter(&GUIIntField::intFilter);
 
 		mInputBox->onValueChanged.connect(std::bind(&GUIIntField::valueChanged, this, _1));
@@ -42,20 +42,6 @@ namespace BansheeEngine
 
 	}
 
-	Vector2I GUIIntField::_getOptimalSize() const
-	{
-		UINT32 width = (UINT32)mInputBox->_getOptimalSize().x;
-		UINT32 height = (UINT32)mInputBox->_getOptimalSize().y;
-
-		if (mLabel != nullptr)
-		{
-			width += mLabel->_getOptimalSize().x;
-			height = std::max(height, (UINT32)mLabel->_getOptimalSize().y);
-		}
-
-		return Vector2I(width, height);
-	}
-
 	bool GUIIntField::_hasCustomCursor(const Vector2I position, CursorType& type) const
 	{
 		RectI draggableArea;
@@ -153,6 +139,14 @@ namespace BansheeEngine
 		return false;
 	}
 
+	void GUIIntField::styleUpdated()
+	{
+		if (mLabel != nullptr)
+			mLabel->setStyle(getSubStyleName(getLabelStyleType()));
+
+		mInputBox->setStyle(getSubStyleName(getInputStyleType()));
+	}
+
 	void GUIIntField::setValue(INT32 value)
 	{
 		mValue = value;
@@ -171,6 +165,12 @@ namespace BansheeEngine
 		return typeName;
 	}
 
+	const String& GUIIntField::getInputStyleType()
+	{
+		static String LABEL_STYLE_TYPE = "EditorFieldInput";
+		return LABEL_STYLE_TYPE;
+	}
+
 	void GUIIntField::valueChanged(const WString& newValue)
 	{
 		INT32 newIntValue = parseInt(newValue);
@@ -184,11 +184,13 @@ namespace BansheeEngine
 	void GUIIntField::focusGained()
 	{
 		UndoRedo::instance().pushGroup("InputBox");
+		mHasInputFocus = true;
 	}
 
 	void GUIIntField::focusLost()
 	{
 		UndoRedo::instance().popGroup("InputBox");
+		mHasInputFocus = false;
 	}
 
 	bool GUIIntField::intFilter(const WString& str)

+ 45 - 7
BansheeEditor/Source/BsGUITextField.cpp

@@ -7,15 +7,23 @@
 #include "BsGUIWidget.h"
 #include "BsGUIMouseEvent.h"
 #include "BsGUIWidget.h"
+#include "BsCmdInputFieldValueChange.h"
+
+using namespace std::placeholders;
 
 namespace BansheeEngine
 {
 	GUITextField::GUITextField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth, 
-		const String& labelStyle, const String& inputBoxStyle, const GUILayoutOptions& layoutOptions, bool withLabel)
-		:TGUIField(dummy, labelContent, labelWidth, labelStyle, layoutOptions, withLabel), mInputBox(nullptr)
+		const String& style, const GUILayoutOptions& layoutOptions, bool withLabel)
+		:TGUIField(dummy, labelContent, labelWidth, style, layoutOptions, withLabel), 
+		mInputBox(nullptr), mValue(L""), mHasInputFocus(false)
 	{
-		mInputBox = GUIInputBox::create(false, inputBoxStyle);
+		mInputBox = GUIInputBox::create(false, getSubStyleName(getInputStyleType()));
 		mLayout->addElement(mInputBox);
+
+		mInputBox->onValueChanged.connect(std::bind(&GUITextField::valueChanged, this, _1));
+		mInputBox->onFocusGained.connect(std::bind(&GUITextField::focusGained, this));
+		mInputBox->onFocusLost.connect(std::bind(&GUITextField::focusLost, this));
 	}
 
 	GUITextField::~GUITextField()
@@ -23,14 +31,38 @@ namespace BansheeEngine
 
 	}
 
-	WString GUITextField::getValue() const
+	void GUITextField::setValue(const WString& value)
 	{
-		return mInputBox->getText();
+		mValue = value;
+		mInputBox->setText(value);
 	}
 
-	void GUITextField::setValue(const WString& value)
+	void GUITextField::styleUpdated()
 	{
-		mInputBox->setText(value);
+		if (mLabel != nullptr)
+			mLabel->setStyle(getSubStyleName(getLabelStyleType()));
+
+		mInputBox->setStyle(getSubStyleName(getInputStyleType()));
+	}
+
+	void GUITextField::valueChanged(const WString& newValue)
+	{
+		CmdInputFieldValueChange<GUITextField, WString>::execute(this, newValue);
+
+		if (!onValueChanged.empty())
+			onValueChanged(newValue);
+	}
+
+	void GUITextField::focusGained()
+	{
+		UndoRedo::instance().pushGroup("InputBox");
+		mHasInputFocus = true;
+	}
+
+	void GUITextField::focusLost()
+	{
+		UndoRedo::instance().popGroup("InputBox");
+		mHasInputFocus = false;
 	}
 
 	const String& GUITextField::getGUITypeName()
@@ -38,4 +70,10 @@ namespace BansheeEngine
 		static String typeName = "GUITextField";
 		return typeName;
 	}
+
+	const String& GUITextField::getInputStyleType()
+	{
+		static String LABEL_STYLE_TYPE = "EditorFieldInput";
+		return LABEL_STYLE_TYPE;
+	}
 }

+ 32 - 8
BansheeEditor/Source/BsGUIToggleField.cpp

@@ -7,33 +7,57 @@
 #include "BsGUIWidget.h"
 #include "BsGUIMouseEvent.h"
 #include "BsGUIWidget.h"
+#include "BsCmdInputFieldValueChange.h"
+
+using namespace std::placeholders;
 
 namespace BansheeEngine
 {
 	GUIToggleField::GUIToggleField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, 
-		UINT32 labelWidth, const String& labelStyle, const String& toggleStyle, const GUILayoutOptions& layoutOptions, bool withLabel)
-		:TGUIField(dummy, labelContent, labelWidth, labelStyle, layoutOptions, withLabel), mToggle(nullptr)
+		UINT32 labelWidth, const String& style, const GUILayoutOptions& layoutOptions, bool withLabel)
+		:TGUIField(dummy, labelContent, labelWidth, style, layoutOptions, withLabel), mToggle(nullptr), mValue(false)
 	{
-		mToggle = GUIToggle::create(HString(L""), toggleStyle);
-		mLayout->addElement(mToggle);
-	}
+		mToggle = GUIToggle::create(HString(L""), getSubStyleName(getToggleStyleType()));
+		mToggle->onToggled.connect(std::bind(&GUIToggleField::valueChanged, this, _1));
 
-	bool GUIToggleField::getValue() const
-	{
-		return mToggle->isToggled();
+		mLayout->addElement(mToggle);
 	}
 
 	void GUIToggleField::setValue(bool value)
 	{
+		mValue = value;
+
 		if(value) 
 			mToggle->toggleOn();
 		else
 			mToggle->toggleOff();
 	}
 
+	void GUIToggleField::styleUpdated()
+	{
+		if (mLabel != nullptr)
+			mLabel->setStyle(getSubStyleName(getLabelStyleType()));
+
+		mToggle->setStyle(getSubStyleName(getToggleStyleType()));
+	}
+
+	void GUIToggleField::valueChanged(bool newValue)
+	{
+		CmdInputFieldValueChange<GUIToggleField, bool>::execute(this, newValue);
+
+		if (!onValueChanged.empty())
+			onValueChanged(newValue);
+	}
+
 	const String& GUIToggleField::getGUITypeName()
 	{
 		static String typeName = "GUIToggleField";
 		return typeName;
 	}
+
+	const String& GUIToggleField::getToggleStyleType()
+	{
+		static String STYLE_TYPE = "EditorFieldToggleInput";
+		return STYLE_TYPE;
+	}
 }

+ 37 - 4
BansheeEditor/Source/BsGUIVector2Field.cpp

@@ -6,23 +6,31 @@
 #include "BsBuiltinResources.h"
 #include "BsGUIWidget.h"
 #include "BsGUIMouseEvent.h"
+#include "BsGUISpace.h"
 #include "BsGUIWidget.h"
 
+using namespace std::placeholders;
+
 namespace BansheeEngine
 {
 	const UINT32 GUIVector2Field::ELEMENT_LABEL_WIDTH = 10;
 
 	GUIVector2Field::GUIVector2Field(const PrivatelyConstruct& dummy, const GUIContent& labelContent, 
-		UINT32 labelWidth, const String& labelStyle, const String& inputBoxStyle, const GUILayoutOptions& layoutOptions, bool withLabel)
-		:TGUIField(dummy, labelContent, labelWidth, labelStyle, layoutOptions, withLabel), mFieldX(nullptr), mFieldY(nullptr)
+		UINT32 labelWidth, const String& style, const GUILayoutOptions& layoutOptions, bool withLabel)
+		:TGUIField(dummy, labelContent, labelWidth, style, layoutOptions, withLabel), 
+		mFieldX(nullptr), mFieldY(nullptr)
 	{
-		mFieldX = GUIFloatField::create(HString(L"X"), ELEMENT_LABEL_WIDTH, labelStyle, inputBoxStyle);
-		mFieldY = GUIFloatField::create(HString(L"Y"), ELEMENT_LABEL_WIDTH, labelStyle, inputBoxStyle);
+		mFieldX = GUIFloatField::create(HString(L"X"), ELEMENT_LABEL_WIDTH, getSubStyleName(getFloatFieldStyleType()));
+		mFieldY = GUIFloatField::create(HString(L"Y"), ELEMENT_LABEL_WIDTH, getSubStyleName(getFloatFieldStyleType()));
+
+		mFieldX->onValueChanged.connect(std::bind(&GUIVector2Field::valueChanged, this, _1));
+		mFieldY->onValueChanged.connect(std::bind(&GUIVector2Field::valueChanged, this, _1));
 
 		mLayout->removeElement(mLabel);
 
 		GUILayout* layout = &mLayout->addLayoutY();
 		layout->addElement(mLabel);
+		mLabel->setLayoutOptions(GUIOptions());
 
 		GUILayout* elementLayout = &layout->addLayoutX();
 
@@ -45,9 +53,34 @@ namespace BansheeEngine
 		mFieldY->setValue(value.y);
 	}
 
+	bool GUIVector2Field::hasInputFocus() const
+	{
+		return mFieldX->hasInputFocus() || mFieldY->hasInputFocus();
+	}
+
+	void GUIVector2Field::valueChanged(float newValue)
+	{
+		onValueChanged(getValue());
+	}
+
+	void GUIVector2Field::styleUpdated()
+	{
+		if (mLabel != nullptr)
+			mLabel->setStyle(getSubStyleName(getLabelStyleType()));
+
+		mFieldX->setStyle(getSubStyleName(getFloatFieldStyleType()));
+		mFieldY->setStyle(getSubStyleName(getFloatFieldStyleType()));
+	}
+
 	const String& GUIVector2Field::getGUITypeName()
 	{
 		static String typeName = "GUIVector2Field";
 		return typeName;
 	}
+
+	const String& GUIVector2Field::getFloatFieldStyleType()
+	{
+		static String LABEL_STYLE_TYPE = "EditorFloatField";
+		return LABEL_STYLE_TYPE;
+	}
 }

+ 40 - 5
BansheeEditor/Source/BsGUIVector3Field.cpp

@@ -6,24 +6,33 @@
 #include "BsBuiltinResources.h"
 #include "BsGUIWidget.h"
 #include "BsGUIMouseEvent.h"
+#include "BsGUISpace.h"
 #include "BsGUIWidget.h"
 
+using namespace std::placeholders;
+
 namespace BansheeEngine
 {
 	const UINT32 GUIVector3Field::ELEMENT_LABEL_WIDTH = 10;
 
 	GUIVector3Field::GUIVector3Field(const PrivatelyConstruct& dummy, const GUIContent& labelContent, 
-		UINT32 labelWidth, const String& labelStyle, const String& inputBoxStyle, const GUILayoutOptions& layoutOptions, bool withLabel)
-		:TGUIField(dummy, labelContent, labelWidth, labelStyle, layoutOptions, withLabel), mFieldX(nullptr), mFieldY(nullptr)
+		UINT32 labelWidth, const String& style, const GUILayoutOptions& layoutOptions, bool withLabel)
+		:TGUIField(dummy, labelContent, labelWidth, style, layoutOptions, withLabel), 
+		mFieldX(nullptr), mFieldY(nullptr), mFieldZ(nullptr)
 	{
-		mFieldX = GUIFloatField::create(HString(L"X"), ELEMENT_LABEL_WIDTH, labelStyle, inputBoxStyle);
-		mFieldY = GUIFloatField::create(HString(L"Y"), ELEMENT_LABEL_WIDTH, labelStyle, inputBoxStyle);
-		mFieldZ = GUIFloatField::create(HString(L"Z"), ELEMENT_LABEL_WIDTH, labelStyle, inputBoxStyle);
+		mFieldX = GUIFloatField::create(HString(L"X"), ELEMENT_LABEL_WIDTH, getSubStyleName(getFloatFieldStyleType()));
+		mFieldY = GUIFloatField::create(HString(L"Y"), ELEMENT_LABEL_WIDTH, getSubStyleName(getFloatFieldStyleType()));
+		mFieldZ = GUIFloatField::create(HString(L"Z"), ELEMENT_LABEL_WIDTH, getSubStyleName(getFloatFieldStyleType()));
+
+		mFieldX->onValueChanged.connect(std::bind(&GUIVector3Field::valueChanged, this, _1));
+		mFieldY->onValueChanged.connect(std::bind(&GUIVector3Field::valueChanged, this, _1));
+		mFieldZ->onValueChanged.connect(std::bind(&GUIVector3Field::valueChanged, this, _1));
 
 		mLayout->removeElement(mLabel);
 
 		GUILayout* layout = &mLayout->addLayoutY();
 		layout->addElement(mLabel);
+		mLabel->setLayoutOptions(GUIOptions());
 
 		GUILayout* elementLayout = &layout->addLayoutX();
 
@@ -49,9 +58,35 @@ namespace BansheeEngine
 		mFieldZ->setValue(value.z);
 	}
 
+	bool GUIVector3Field::hasInputFocus() const
+	{
+		return mFieldX->hasInputFocus() || mFieldY->hasInputFocus() || mFieldZ->hasInputFocus();
+	}
+
+	void GUIVector3Field::styleUpdated()
+	{
+		if (mLabel != nullptr)
+			mLabel->setStyle(getSubStyleName(getLabelStyleType()));
+
+		mFieldX->setStyle(getSubStyleName(getFloatFieldStyleType()));
+		mFieldY->setStyle(getSubStyleName(getFloatFieldStyleType()));
+		mFieldZ->setStyle(getSubStyleName(getFloatFieldStyleType()));
+	}
+
+	void GUIVector3Field::valueChanged(float newValue)
+	{
+		onValueChanged(getValue());
+	}
+
 	const String& GUIVector3Field::getGUITypeName()
 	{
 		static String typeName = "GUIVector3Field";
 		return typeName;
 	}
+
+	const String& GUIVector3Field::getFloatFieldStyleType()
+	{
+		static String LABEL_STYLE_TYPE = "EditorFloatField";
+		return LABEL_STYLE_TYPE;
+	}
 }

+ 42 - 6
BansheeEditor/Source/BsGUIVector4Field.cpp

@@ -6,25 +6,34 @@
 #include "BsBuiltinResources.h"
 #include "BsGUIWidget.h"
 #include "BsGUIMouseEvent.h"
+#include "BsGUISpace.h"
 #include "BsGUIWidget.h"
 
+using namespace std::placeholders;
+
 namespace BansheeEngine
 {
 	const UINT32 GUIVector4Field::ELEMENT_LABEL_WIDTH = 10;
 
 	GUIVector4Field::GUIVector4Field(const PrivatelyConstruct& dummy, const GUIContent& labelContent, 
-		UINT32 labelWidth, const String& labelStyle, const String& inputBoxStyle, const GUILayoutOptions& layoutOptions, bool withLabel)
-		:TGUIField(dummy, labelContent, labelWidth, labelStyle, layoutOptions, withLabel), mFieldX(nullptr), mFieldY(nullptr)
+		UINT32 labelWidth, const String& style, const GUILayoutOptions& layoutOptions, bool withLabel)
+		:TGUIField(dummy, labelContent, labelWidth, style, layoutOptions, withLabel), mFieldX(nullptr), mFieldY(nullptr)
 	{
-		mFieldX = GUIFloatField::create(HString(L"X"), ELEMENT_LABEL_WIDTH, labelStyle, inputBoxStyle);
-		mFieldY = GUIFloatField::create(HString(L"Y"), ELEMENT_LABEL_WIDTH, labelStyle, inputBoxStyle);
-		mFieldZ = GUIFloatField::create(HString(L"Z"), ELEMENT_LABEL_WIDTH, labelStyle, inputBoxStyle);
-		mFieldW = GUIFloatField::create(HString(L"W"), ELEMENT_LABEL_WIDTH, labelStyle, inputBoxStyle);
+		mFieldX = GUIFloatField::create(HString(L"X"), ELEMENT_LABEL_WIDTH, getSubStyleName(getFloatFieldStyleType()));
+		mFieldY = GUIFloatField::create(HString(L"Y"), ELEMENT_LABEL_WIDTH, getSubStyleName(getFloatFieldStyleType()));
+		mFieldZ = GUIFloatField::create(HString(L"Z"), ELEMENT_LABEL_WIDTH, getSubStyleName(getFloatFieldStyleType()));
+		mFieldW = GUIFloatField::create(HString(L"W"), ELEMENT_LABEL_WIDTH, getSubStyleName(getFloatFieldStyleType()));
+
+		mFieldX->onValueChanged.connect(std::bind(&GUIVector4Field::valueChanged, this, _1));
+		mFieldY->onValueChanged.connect(std::bind(&GUIVector4Field::valueChanged, this, _1));
+		mFieldZ->onValueChanged.connect(std::bind(&GUIVector4Field::valueChanged, this, _1));
+		mFieldW->onValueChanged.connect(std::bind(&GUIVector4Field::valueChanged, this, _1));
 
 		mLayout->removeElement(mLabel);
 
 		GUILayout* layout = &mLayout->addLayoutY();
 		layout->addElement(mLabel);
+		mLabel->setLayoutOptions(GUIOptions());
 
 		GUILayout* elementLayout = &layout->addLayoutX();
 
@@ -53,9 +62,36 @@ namespace BansheeEngine
 		mFieldW->setValue(value.w);
 	}
 
+	bool GUIVector4Field::hasInputFocus() const
+	{
+		return mFieldX->hasInputFocus() || mFieldY->hasInputFocus() || mFieldZ->hasInputFocus() || mFieldW->hasInputFocus();
+	}
+
+	void GUIVector4Field::styleUpdated()
+	{
+		if (mLabel != nullptr)
+			mLabel->setStyle(getSubStyleName(getLabelStyleType()));
+
+		mFieldX->setStyle(getSubStyleName(getFloatFieldStyleType()));
+		mFieldY->setStyle(getSubStyleName(getFloatFieldStyleType()));
+		mFieldZ->setStyle(getSubStyleName(getFloatFieldStyleType()));
+		mFieldW->setStyle(getSubStyleName(getFloatFieldStyleType()));
+	}
+
+	void GUIVector4Field::valueChanged(float newValue)
+	{
+		onValueChanged(getValue());
+	}
+
 	const String& GUIVector4Field::getGUITypeName()
 	{
 		static String typeName = "GUIVector4Field";
 		return typeName;
 	}
+
+	const String& GUIVector4Field::getFloatFieldStyleType()
+	{
+		static String LABEL_STYLE_TYPE = "EditorFloatField";
+		return LABEL_STYLE_TYPE;
+	}
 }

+ 16 - 0
BansheeEngine/Include/BsGUIElement.h

@@ -109,6 +109,11 @@ namespace BansheeEngine
 		 */
 		void setLayoutOptions(const GUIOptions& layoutOptions);
 
+		/**
+		 * @brief	Sets new style to be used by the element.
+		 */
+		void setStyle(const String& styleName);
+
 		/**
 		 * @brief	Gets internal element style representing the exact type of GUI element
 		 *			in this object.
@@ -390,6 +395,17 @@ namespace BansheeEngine
 			return overrideStyle;
 		}
 
+		/**
+		 * @brief	Attempts to find a sub-style for the specified type in the currently
+		 *			set GUI element style. If one cannot be found empty string is returned.
+		 */
+		const String& getSubStyleName(const String& subStyleTypeName);
+
+		/**
+		 * @brief	Method that gets triggered whenever element style changes.
+		 */
+		virtual void styleUpdated() { }
+
 		/**
 		 * @brief	Returns clipped bounds excluding the margins. Relative to parent widget.
 		 */

+ 2 - 0
BansheeEngine/Include/BsGUIElementStyle.h

@@ -68,5 +68,7 @@ namespace BansheeEngine
 		UINT32 minHeight, maxHeight; /**< Minimum and maximum height allowed for this object. Used by the layout only when exact height is not specified. */
 		bool fixedWidth; /**< If width is fixed, layout will not attempt to resize the element depending on available size. */
 		bool fixedHeight; /**< If height is fixed, layout will not attempt to resize the element depending on available size. */
+
+		Map<String, String> subStyles; /**< Sub-styles used by certain more complex elements. */
 	};
 }

+ 16 - 0
BansheeEngine/Source/BsGUIElement.cpp

@@ -48,6 +48,11 @@ namespace BansheeEngine
 		mLayoutOptions = layoutOptions; 
 	}
 
+	void GUIElement::setStyle(const String& styleName)
+	{
+		mStyleName = styleName;
+		_refreshStyle();
+	}
 
 	bool GUIElement::mouseEvent(const GUIMouseEvent& ev)
 	{
@@ -272,11 +277,22 @@ namespace BansheeEngine
 		{
 			mStyle = newStyle;
 			mLayoutOptions.updateWithStyle(mStyle);
+			styleUpdated();
 
 			markContentAsDirty();
 		}
 	}
 
+	const String& GUIElement::getSubStyleName(const String& subStyleTypeName)
+	{
+		auto iterFind = mStyle->subStyles.find(subStyleTypeName);
+
+		if (iterFind != mStyle->subStyles.end())
+			return iterFind->second;
+		else
+			return StringUtil::BLANK;
+	}
+
 	void GUIElement::destroy(GUIElement* element)
 	{
 		if(element->mIsDestroyed)

+ 20 - 16
Inspector.txt

@@ -1,20 +1,18 @@
-
-IMPLEMENTATION STEPS:
-2. Each GUIElement needs to be aware of its parent GUIArea
-
-3. In ScriptGUILayoutUtility I have no way of casting a MonoObject to GUIElementBase. This will likely require a refactor.
-
-4. When constructing ScriptObject I store it as actual type. But in ScriptGUIElement internal methods I expect ScriptGUIElementBase type.
-   This will also likely require a refactor. Related to above.
+Update all elements to use new sub-styles
+ - Including GUIFoldout and potentially others
+ - Override styleUpdated()
+Update C# GUIElementStyle
 
 TODO:
  - Hook up int field set/get callbacks
     - Ensure int field isn't updated from app when in focus
  - Hook up foldout expand/collapse callbacks
  - Think about how to handle arrays, adding and deleting elements from them.
- - Add labels to foldouts
+   - Will likely need GUILayout::GetElementIndex()
+ - I should add project and scene tree views to the main editor window to make inspector testing easier
+ - Entire foldout should be clickable, not just the toggle button
  - Extend text field so it can be multi-line
- - Port to C# (+ see below for additional fixes to C++ versions):
+ - Port to C#:
    - IntField
    - FloatField
    - ColorField
@@ -30,8 +28,18 @@ TODO:
  - Extend GameObject field so it can only accept a certain type
  - Ensure Undo/redo works as intended
    - This task needs decomposing. Likely need to port UndoRedo to C# first.
+ - GUIColor needs to be hooked up to a window that actually changes its value.
+ - Need to add GUIResourceField along with GUIGameObjectField and figure out a way to make them
+   accept arbitrary types.
+     - Probably move them to SBansheeEditor
+ - I need to register UndoRedo command after user finishes modifying a field. This should be referencing an object using an URI?
+
+TO PONDER:
+ - How to limit resource/object fields to a custom type (user created type possibly)
+ - Need to figure out a better way of setting styles for container GUI elements (e.g. GUIFoldout requires three different styles)
 
 KEEP IN MIND:
+ - Clicking on an object/resource in inspector should ping it in their window
  - Inspector needs to be organized in such a way that scroll areas work. That should be possible with GUIPanelContainer.
  - When inspector object changes I need to rebuild that inspector element
    - This can happen if user drags a new object
@@ -40,11 +48,8 @@ KEEP IN MIND:
  - Modify C++ Editor fields so that calling setValue doesn't update the visual value until focus is lost
   - When user is currently writing in an input box I don't want refresh to overwrite that value.
 
-BUGS
- - Composite GUI elements like Vector3Field need to set a style with min/max or fixed bounds to their GUIElementContainer
-   otherwise they get clipped when their parent layout is too small
- - Modify all editor fields so they implement virtual Vector2I _getOptimalSize() const; and remove it from GUIFieldBase.
-   See IntField for example
+
+
 
 
 
@@ -90,7 +95,6 @@ UndoRedo should work on URI type basis where it remembers object ID, and path ac
  ----------------------
 
  Non-inspector:
-
   - Deleting first entry in input field moves the cursor incorrectly
   - Test if parsing int/float value from int/float field actually works
   - ProfilerOverlay elements are constantly dirty? even though I'm not calling update

+ 5 - 6
MBansheeEditor/GUI/GUIIntField.cs

@@ -16,15 +16,14 @@ namespace BansheeEditor
             set { Internal_SetValue(mCachedPtr, value); }
         }
 
-        public GUIIntField(GUIContent title, int titleWidth = 100, string titleStyle = "",
-                           string inputStyle = "", params GUIOption[] options)
+        public GUIIntField(GUIContent title, int titleWidth = 100, string style = "", params GUIOption[] options)
         {
-            Internal_CreateInstance(this, title, titleWidth, titleStyle, inputStyle, options, true);
+            Internal_CreateInstance(this, title, titleWidth, style, options, true);
         }
 
-        public GUIIntField(string inputStyle = "", params GUIOption[] options)
+        public GUIIntField(string style = "", params GUIOption[] options)
         {
-            Internal_CreateInstance(this, null, 0, "", inputStyle, options, false);
+            Internal_CreateInstance(this, null, 0, style, options, false);
         }
 
         private void DoOnChanged(int newValue)
@@ -35,7 +34,7 @@ namespace BansheeEditor
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_CreateInstance(GUIIntField instance, GUIContent title, int titleWidth, 
-            string titleStyle, string inputStyle, GUIOption[] options, bool withTitle);
+            string style, GUIOption[] options, bool withTitle);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern int Internal_GetValue(IntPtr nativeInstance);

+ 2 - 2
SBansheeEditor/Include/BsScriptGUIIntField.h

@@ -11,8 +11,8 @@ namespace BansheeEngine
 		SCRIPT_OBJ(BansheeEditorAssemblyName, "BansheeEditor", "GUIIntField")
 
 	private:
-		static void internal_createInstance(MonoObject* instance, MonoObject* title, UINT32 titleWidth, MonoString* titleStyle, 
-			MonoString* inputStyle, MonoArray* guiOptions, bool withTitle);
+		static void internal_createInstance(MonoObject* instance, MonoObject* title, UINT32 titleWidth, 
+			MonoString* style, MonoArray* guiOptions, bool withTitle);
 
 		static INT32 internal_getValue(ScriptGUIIntField* nativeInstance);
 		static void internal_setValue(ScriptGUIIntField* nativeInstance, INT32 value);

+ 6 - 10
SBansheeEditor/Source/BsScriptGUIIntField.cpp

@@ -37,8 +37,8 @@ namespace BansheeEngine
 		onChangedThunk = (OnChangedThunkDef)metaData.scriptClass->getMethod("DoOnChanged", 1).getThunk();
 	}
 
-	void ScriptGUIIntField::internal_createInstance(MonoObject* instance, MonoObject* title, UINT32 titleWidth, MonoString* titleStyle, 
-		MonoString* inputStyle, MonoArray* guiOptions, bool withTitle)
+	void ScriptGUIIntField::internal_createInstance(MonoObject* instance, MonoObject* title, UINT32 titleWidth, 
+		MonoString* style, MonoArray* guiOptions, bool withTitle)
 	{
 		GUIOptions options;
 
@@ -46,21 +46,17 @@ namespace BansheeEngine
 		for(UINT32 i = 0; i < arrayLen; i++)
 			options.addOption(mono_array_get(guiOptions, GUIOption, i));
 
+		String styleName = toString(MonoUtil::monoToWString(style));
+
 		GUIIntField* guiIntField = nullptr;
 		if(withTitle)
 		{
-			String titleStyleName = toString(MonoUtil::monoToWString(titleStyle));
-			String inputStyleName = toString(MonoUtil::monoToWString(inputStyle));
-
 			GUIContent nativeContent(ScriptGUIContent::getText(title), ScriptGUIContent::getImage(title), ScriptGUIContent::getTooltip(title));
-			guiIntField = GUIIntField::create(nativeContent, titleWidth, options,
-				titleStyleName, inputStyleName);
+			guiIntField = GUIIntField::create(nativeContent, titleWidth, options, styleName);
 		}
 		else
 		{
-			String inputStyleName = toString(MonoUtil::monoToWString(inputStyle));
-
-			guiIntField = GUIIntField::create(options, inputStyleName);
+			guiIntField = GUIIntField::create(options, styleName);
 		}
 
 		guiIntField->onValueChanged.connect(std::bind(&ScriptGUIIntField::onChanged, instance, _1));