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

WIP UndoRedo group system
Added IntField to C#
Refactored IntField a bit

Marko Pintera пре 11 година
родитељ
комит
ae856ed0f4

+ 1 - 0
BansheeEditor/BansheeEditor.vcxproj

@@ -263,6 +263,7 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="Include\BsCmdEditPlainFieldGO.h" />
     <ClInclude Include="Include\BsCmdEditPlainFieldGO.h" />
+    <ClInclude Include="Include\BsCmdInputFieldValueChange.h" />
     <ClInclude Include="Include\BsCmdReparentSO.h" />
     <ClInclude Include="Include\BsCmdReparentSO.h" />
     <ClInclude Include="Include\BsDbgTestGameObjectRef.h" />
     <ClInclude Include="Include\BsDbgTestGameObjectRef.h" />
     <ClInclude Include="Include\BsDbgTestGameObjectRefRTTI.h" />
     <ClInclude Include="Include\BsDbgTestGameObjectRefRTTI.h" />

+ 3 - 0
BansheeEditor/BansheeEditor.vcxproj.filters

@@ -192,6 +192,9 @@
     <ClInclude Include="Include\BsGUIFieldBase.h">
     <ClInclude Include="Include\BsGUIFieldBase.h">
       <Filter>Header Files\Editor</Filter>
       <Filter>Header Files\Editor</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsCmdInputFieldValueChange.h">
+      <Filter>Header Files\Editor\Commands</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsEditorWidgetContainer.cpp">
     <ClCompile Include="Source\BsEditorWidgetContainer.cpp">

+ 41 - 0
BansheeEditor/Include/BsCmdInputFieldValueChange.h

@@ -0,0 +1,41 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsEditorCommand.h"
+#include "BsUndoRedo.h"
+
+namespace BansheeEngine
+{
+	template <class InputFieldType, class ValueType>
+	class CmdInputFieldValueChange : public EditorCommand
+	{
+	public:
+		static void execute(InputFieldType* inputField, const ValueType& value)
+		{
+			CmdInputFieldValueChange* command = new (cm_alloc<CmdInputFieldValueChange>()) CmdInputFieldValueChange(inputField, value);
+			UndoRedo::instance().registerCommand(command);
+			command->commit();
+		}
+
+		void commit()
+		{
+			mInputField->setValue(mNewValue);
+		}
+
+		void revert()
+		{
+			mInputField->setValue(mOldValue);
+		}
+
+	private:
+		friend class UndoRedo;
+
+		CmdInputFieldValueChange(InputFieldType* inputField, const ValueType& value)
+			:mInputField(inputField), mOldValue(inputField->getValue()), mNewValue(value)
+		{ }
+
+		ValueType mOldValue;
+		ValueType mNewValue;
+		InputFieldType* mInputField;
+	};
+}

+ 8 - 1
BansheeEditor/Include/BsGUIIntField.h

@@ -13,9 +13,11 @@ namespace BansheeEngine
 		GUIIntField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
 		GUIIntField(const PrivatelyConstruct& dummy, const GUIContent& labelContent, UINT32 labelWidth,
 			const String& labelStyle, const String& inputBoxStyle, const GUILayoutOptions& layoutOptions, bool withLabel);
 			const String& labelStyle, const String& inputBoxStyle, const GUILayoutOptions& layoutOptions, bool withLabel);
 
 
-		INT32 getValue() const;
+		INT32 getValue() const { return mValue; }
 		void setValue(INT32 value);
 		void setValue(INT32 value);
 
 
+		boost::signal<void(INT32)> onValueChanged;
+
 	protected:
 	protected:
 		virtual ~GUIIntField();
 		virtual ~GUIIntField();
 
 
@@ -25,6 +27,7 @@ namespace BansheeEngine
 		static const INT32 DRAG_SPEED;
 		static const INT32 DRAG_SPEED;
 
 
 		GUIInputBox* mInputBox;
 		GUIInputBox* mInputBox;
+		INT32 mValue;
 		INT32 mLastDragPos;
 		INT32 mLastDragPos;
 		bool mIsDragging;
 		bool mIsDragging;
 		bool mIsDragCursorSet;
 		bool mIsDragCursorSet;
@@ -32,6 +35,10 @@ namespace BansheeEngine
 		bool _hasCustomCursor(const Vector2I position, CursorType& type) const;
 		bool _hasCustomCursor(const Vector2I position, CursorType& type) const;
 		virtual bool mouseEvent(const GUIMouseEvent& ev);
 		virtual bool mouseEvent(const GUIMouseEvent& ev);
 
 
+		void valueChanged(const WString& newValue);
+		void focusGained();
+		void focusLost();
+
 		static bool intFilter(const WString& str);
 		static bool intFilter(const WString& str);
 	};
 	};
 }
 }

+ 14 - 0
BansheeEditor/Include/BsUndoRedo.h

@@ -7,6 +7,12 @@ namespace BansheeEngine
 {
 {
 	class UndoRedo : public Module<UndoRedo>
 	class UndoRedo : public Module<UndoRedo>
 	{
 	{
+		struct GroupData
+		{
+			String name;
+			UINT32 numEntries;
+		};
+
 	public:
 	public:
 		UndoRedo();
 		UndoRedo();
 		~UndoRedo();
 		~UndoRedo();
@@ -14,6 +20,9 @@ namespace BansheeEngine
 		void undo();
 		void undo();
 		void redo();
 		void redo();
 
 
+		void pushGroup(const String& name);
+		void popGroup(const String& name);
+
 		void registerCommand(EditorCommand* command);
 		void registerCommand(EditorCommand* command);
 
 
 	private:
 	private:
@@ -28,6 +37,11 @@ namespace BansheeEngine
 		UINT32 mRedoStackPtr;
 		UINT32 mRedoStackPtr;
 		UINT32 mRedoNumElements;
 		UINT32 mRedoNumElements;
 
 
+		Stack<GroupData>::type mGroups;
+
+		EditorCommand* removeLastFromUndoStack();
+		void addToUndoStack(EditorCommand* command);
+
 		void clearUndoStack();
 		void clearUndoStack();
 		void clearRedoStack();
 		void clearRedoStack();
 	};
 	};

+ 30 - 6
BansheeEditor/Source/BsGUIIntField.cpp

@@ -9,9 +9,13 @@
 #include "BsGUIMouseEvent.h"
 #include "BsGUIMouseEvent.h"
 #include "BsGUIWidget.h"
 #include "BsGUIWidget.h"
 #include "BsCursor.h"
 #include "BsCursor.h"
+#include "BsUndoRedo.h"
 #include "CmViewport.h"
 #include "CmViewport.h"
+#include "BsCmdInputFieldValueChange.h"
 #include <regex>
 #include <regex>
 
 
+using namespace std::placeholders;
+
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	const INT32 GUIIntField::DRAG_SPEED = 5;
 	const INT32 GUIIntField::DRAG_SPEED = 5;
@@ -24,6 +28,10 @@ namespace BansheeEngine
 		mInputBox = GUIInputBox::create(false, GUIOptions(GUIOption::flexibleWidth()), inputBoxStyle);
 		mInputBox = GUIInputBox::create(false, GUIOptions(GUIOption::flexibleWidth()), inputBoxStyle);
 		mInputBox->setFilter(&GUIIntField::intFilter);
 		mInputBox->setFilter(&GUIIntField::intFilter);
 
 
+		mInputBox->onValueChanged.connect(std::bind(&GUIIntField::valueChanged, this, _1));
+		mInputBox->onFocusGained.connect(std::bind(&GUIIntField::focusGained, this));
+		mInputBox->onFocusLost.connect(std::bind(&GUIIntField::focusLost, this));
+
 		mLayout->addElement(mInputBox);
 		mLayout->addElement(mInputBox);
 
 
 		setValue(0);
 		setValue(0);
@@ -112,7 +120,7 @@ namespace BansheeEngine
 						xDiff += DRAG_SPEED;
 						xDiff += DRAG_SPEED;
 					}
 					}
 				}
 				}
-				
+
 				mLastDragPos += (newValue - oldValue) * DRAG_SPEED + jumpAmount;
 				mLastDragPos += (newValue - oldValue) * DRAG_SPEED + jumpAmount;
 
 
 				if(oldValue != newValue)
 				if(oldValue != newValue)
@@ -131,13 +139,9 @@ namespace BansheeEngine
 		return false;
 		return false;
 	}
 	}
 
 
-	INT32 GUIIntField::getValue() const
-	{
-		return parseInt(mInputBox->getText());
-	}
-
 	void GUIIntField::setValue(INT32 value)
 	void GUIIntField::setValue(INT32 value)
 	{
 	{
+		mValue = value;
 		mInputBox->setText(toWString(value));
 		mInputBox->setText(toWString(value));
 	}
 	}
 
 
@@ -153,6 +157,26 @@ namespace BansheeEngine
 		return typeName;
 		return typeName;
 	}
 	}
 
 
+	void GUIIntField::valueChanged(const WString& newValue)
+	{
+		INT32 newIntValue = parseInt(newValue);
+
+		CmdInputFieldValueChange<GUIIntField, INT32>::execute(this, newIntValue);
+
+		if(!onValueChanged.empty())
+			onValueChanged(newIntValue);
+	}
+
+	void GUIIntField::focusGained()
+	{
+		UndoRedo::instance().pushGroup("InputBox");
+	}
+
+	void GUIIntField::focusLost()
+	{
+		UndoRedo::instance().popGroup("InputBox");
+	}
+
 	bool GUIIntField::intFilter(const WString& str)
 	bool GUIIntField::intFilter(const WString& str)
 	{
 	{
 		return std::regex_match(str, std::wregex(L"-?(\\d+)?"));
 		return std::regex_match(str, std::wregex(L"-?(\\d+)?"));

+ 75 - 10
BansheeEditor/Source/BsUndoRedo.cpp

@@ -28,13 +28,11 @@ namespace BansheeEngine
 		if(mUndoNumElements == 0)
 		if(mUndoNumElements == 0)
 			return;
 			return;
 
 
-		EditorCommand* command = mUndoStack[mUndoStackPtr];
-		mUndoStackPtr = (mUndoStackPtr - 1) % MAX_STACK_ELEMENTS;
-		mUndoNumElements--;
-
+		EditorCommand* command = removeLastFromUndoStack();
+		
 		mRedoStackPtr = (mRedoStackPtr + 1) % MAX_STACK_ELEMENTS;
 		mRedoStackPtr = (mRedoStackPtr + 1) % MAX_STACK_ELEMENTS;
 		mRedoStack[mRedoStackPtr] = command;
 		mRedoStack[mRedoStackPtr] = command;
-		mRedoNumElements++;
+		mRedoNumElements = std::min(mRedoNumElements + 1, MAX_STACK_ELEMENTS);
 
 
 		command->revert();
 		command->revert();
 	}
 	}
@@ -48,20 +46,84 @@ namespace BansheeEngine
 		mRedoStackPtr = (mRedoStackPtr - 1) % MAX_STACK_ELEMENTS;
 		mRedoStackPtr = (mRedoStackPtr - 1) % MAX_STACK_ELEMENTS;
 		mRedoNumElements--;
 		mRedoNumElements--;
 
 
-		mUndoStackPtr = (mUndoStackPtr + 1) % MAX_STACK_ELEMENTS;
-		mUndoStack[mUndoStackPtr] = command;
-		mUndoNumElements++;
+		addToUndoStack(command);
 
 
 		command->commit();
 		command->commit();
 	}
 	}
 
 
+	void UndoRedo::pushGroup(const String& name)
+	{
+		mGroups.push(GroupData());
+		GroupData& newGroup = mGroups.top();
+
+		newGroup.name = name;
+		newGroup.numEntries = 0;
+
+		clearRedoStack();
+	}
+
+	void UndoRedo::popGroup(const String& name)
+	{
+		if(mGroups.empty())
+			CM_EXCEPT(InvalidStateException, "Attempting to pop an UndoRedo group that doesn't exist: " + name);
+
+		GroupData& topGroup = mGroups.top();
+		if(topGroup.name != name)
+			CM_EXCEPT(InvalidStateException, "Attempting to pop invalid UndoRedo group. Got: " + name + ". Expected: " + topGroup.name);
+
+		for(UINT32 i = 0; i < topGroup.numEntries; i++)
+		{
+			EditorCommand* command = mUndoStack[mUndoStackPtr];
+			mUndoStackPtr = (mUndoStackPtr - 1) % MAX_STACK_ELEMENTS;
+			mUndoNumElements--;
+
+			EditorCommand::destroy(command);
+		}
+
+		mGroups.pop();
+		clearRedoStack();
+	}
+
 	void UndoRedo::registerCommand(EditorCommand* command)
 	void UndoRedo::registerCommand(EditorCommand* command)
+	{
+		addToUndoStack(command);
+
+		clearRedoStack();
+	}
+
+	EditorCommand* UndoRedo::removeLastFromUndoStack()
+	{
+		EditorCommand* command = mUndoStack[mUndoStackPtr];
+		mUndoStackPtr = (mUndoStackPtr - 1) % MAX_STACK_ELEMENTS;
+		mUndoNumElements--;
+
+		if(!mGroups.empty())
+		{
+			GroupData& topGroup = mGroups.top();
+
+			if(topGroup.numEntries == 0)
+			{
+				CM_EXCEPT(InvalidStateException, "Removing an element from UndoRedo stack while in an " \
+					"invalid UndoRedo group. Current group: " + topGroup.name);
+			}
+
+			topGroup.numEntries--;
+		}
+
+		return command;
+	}
+
+	void UndoRedo::addToUndoStack(EditorCommand* command)
 	{
 	{
 		mUndoStackPtr = (mUndoStackPtr + 1) % MAX_STACK_ELEMENTS;
 		mUndoStackPtr = (mUndoStackPtr + 1) % MAX_STACK_ELEMENTS;
 		mUndoStack[mUndoStackPtr] = command;
 		mUndoStack[mUndoStackPtr] = command;
-		mUndoNumElements++;
+		mUndoNumElements = std::min(mUndoNumElements + 1, MAX_STACK_ELEMENTS);
 
 
-		clearRedoStack();
+		if(!mGroups.empty())
+		{
+			GroupData& topGroup = mGroups.top();
+			topGroup.numEntries = std::min(topGroup.numEntries + 1, MAX_STACK_ELEMENTS);
+		}
 	}
 	}
 
 
 	void UndoRedo::clearUndoStack()
 	void UndoRedo::clearUndoStack()
@@ -74,6 +136,9 @@ namespace BansheeEngine
 
 
 			EditorCommand::destroy(command);
 			EditorCommand::destroy(command);
 		}
 		}
+
+		while(!mGroups.empty())
+			mGroups.pop();
 	}
 	}
 
 
 	void UndoRedo::clearRedoStack()
 	void UndoRedo::clearRedoStack()

+ 4 - 0
BansheeEngine/Include/BsGUIInputBox.h

@@ -32,6 +32,10 @@ namespace BansheeEngine
 		virtual ElementType getElementType() const { return ElementType::InputBox; }
 		virtual ElementType getElementType() const { return ElementType::InputBox; }
 
 
 		virtual Vector2I _getOptimalSize() const;
 		virtual Vector2I _getOptimalSize() const;
+
+		boost::signal<void(const WString&)> onValueChanged;
+		boost::signal<void()> onFocusGained;
+		boost::signal<void()> onFocusLost;
 	protected:
 	protected:
 		GUIInputBox(const String& styleName, const GUILayoutOptions& layoutOptions, bool multiline);
 		GUIInputBox(const String& styleName, const GUILayoutOptions& layoutOptions, bool multiline);
 		virtual ~GUIInputBox();
 		virtual ~GUIInputBox();

+ 27 - 0
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -72,6 +72,7 @@ namespace BansheeEngine
 
 
 		if(filterOkay)
 		if(filterOkay)
 		{
 		{
+			WString oldText = mText;
 			mText = text;
 			mText = text;
 
 
 			TEXT_SPRITE_DESC textDesc = getTextDesc();
 			TEXT_SPRITE_DESC textDesc = getTextDesc();
@@ -516,6 +517,9 @@ namespace BansheeEngine
 			scrollTextToCaret();
 			scrollTextToCaret();
 
 
 			markContentAsDirty();
 			markContentAsDirty();
+
+			if(!onValueChanged.empty())
+				onValueChanged(mText);
 		}
 		}
 
 
 		return true;
 		return true;
@@ -539,6 +543,10 @@ namespace BansheeEngine
 			markContentAsDirty();
 			markContentAsDirty();
 
 
 			mHasFocus = true;
 			mHasFocus = true;
+
+			if(!onFocusGained.empty())
+				onFocusGained();
+
 			return true;
 			return true;
 		}
 		}
 		
 		
@@ -551,6 +559,10 @@ namespace BansheeEngine
 			markContentAsDirty();
 			markContentAsDirty();
 
 
 			mHasFocus = false;
 			mHasFocus = false;
+
+			if(!onFocusLost.empty())
+				onFocusLost();
+
 			return true;
 			return true;
 		}
 		}
 		
 		
@@ -587,6 +599,9 @@ namespace BansheeEngine
 							gGUIManager().getInputCaretTool()->moveCaretToChar(charIdx, CARET_AFTER);
 							gGUIManager().getInputCaretTool()->moveCaretToChar(charIdx, CARET_AFTER);
 
 
 							scrollTextToCaret();
 							scrollTextToCaret();
+
+							if(!onValueChanged.empty())
+								onValueChanged(mText);
 						}
 						}
 					}
 					}
 				}
 				}
@@ -629,6 +644,9 @@ namespace BansheeEngine
 							gGUIManager().getInputCaretTool()->moveCaretToChar(charIdx, CARET_AFTER);
 							gGUIManager().getInputCaretTool()->moveCaretToChar(charIdx, CARET_AFTER);
 
 
 							scrollTextToCaret();
 							scrollTextToCaret();
+
+							if(!onValueChanged.empty())
+								onValueChanged(mText);
 						}
 						}
 					}
 					}
 				}
 				}
@@ -779,6 +797,9 @@ namespace BansheeEngine
 					scrollTextToCaret();
 					scrollTextToCaret();
 
 
 					markContentAsDirty();
 					markContentAsDirty();
+
+					if(!onValueChanged.empty())
+						onValueChanged(mText);
 				}
 				}
 
 
 				return true;
 				return true;
@@ -991,6 +1012,9 @@ namespace BansheeEngine
 			}
 			}
 
 
 			scrollTextToCaret();
 			scrollTextToCaret();
+
+			if(!onValueChanged.empty())
+				onValueChanged(mText);
 		}
 		}
 
 
 		clearSelection();
 		clearSelection();
@@ -1107,6 +1131,9 @@ namespace BansheeEngine
 			scrollTextToCaret();
 			scrollTextToCaret();
 
 
 			markContentAsDirty();
 			markContentAsDirty();
+
+			if(!onValueChanged.empty())
+				onValueChanged(mText);
 		}
 		}
 	}
 	}
 }
 }

+ 0 - 0
MBansheeEditor/GUIFoldout.cs → MBansheeEditor/GUI/GUIFoldout.cs


+ 46 - 0
MBansheeEditor/GUI/GUIIntField.cs

@@ -0,0 +1,46 @@
+using System;
+using System.Runtime.CompilerServices;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public sealed class GUIIntField : GUIElement
+    {
+        public delegate void OnChangedDelegate(int newValue);
+
+        public event OnChangedDelegate OnChanged;
+
+        public int Value
+        {
+            get { return Internal_GetValue(mCachedPtr); }
+            set { Internal_SetValue(mCachedPtr, value); }
+        }
+
+        public GUIIntField(GUIContent title, int titleWidth = 100, string titleStyle = "",
+                           string inputStyle = "", params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, title, titleWidth, titleStyle, inputStyle, options, true);
+        }
+
+        public GUIIntField(string inputStyle = "", params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, null, 0, "", inputStyle, options, false);
+        }
+
+        private void DoOnChanged(int newValue)
+        {
+            if (OnChanged != null)
+                OnChanged(newValue);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(GUIIntField instance, GUIContent title, int titleWidth, 
+            string titleStyle, string inputStyle, GUIOption[] options, bool withTitle);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int Internal_GetValue(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetValue(IntPtr nativeInstance, int value);
+    }
+}

+ 2 - 1
MBansheeEditor/MBansheeEditor.csproj

@@ -45,7 +45,8 @@
     <Compile Include="Debug_Component2.cs" />
     <Compile Include="Debug_Component2.cs" />
     <Compile Include="EditorApplication.cs" />
     <Compile Include="EditorApplication.cs" />
     <Compile Include="EditorWindow.cs" />
     <Compile Include="EditorWindow.cs" />
-    <Compile Include="GUIFoldout.cs" />
+    <Compile Include="GUI\GUIFoldout.cs" />
+    <Compile Include="GUI\GUIIntField.cs" />
     <Compile Include="Inspector\CustomInspector.cs" />
     <Compile Include="Inspector\CustomInspector.cs" />
     <Compile Include="Inspector\GenericInspector.cs" />
     <Compile Include="Inspector\GenericInspector.cs" />
     <Compile Include="Inspector\InspectableArray.cs" />
     <Compile Include="Inspector\InspectableArray.cs" />

+ 28 - 0
SBansheeEditor/Include/BsScriptGUIIntField.h

@@ -0,0 +1,28 @@
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsScriptGUIElement.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BED_EXPORT ScriptGUIIntField : public TScriptGUIElement<ScriptGUIIntField>
+	{
+	public:
+		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 INT32 internal_getValue(ScriptGUIIntField* nativeInstance);
+		static void internal_setValue(ScriptGUIIntField* nativeInstance, INT32 value);
+
+		static void onChanged(MonoObject* instance, INT32 newValue);
+
+		ScriptGUIIntField(MonoObject* instance, GUIIntField* intField);
+
+		typedef void (__stdcall *OnChangedThunkDef) (MonoObject*, INT32, MonoException**);
+
+		static OnChangedThunkDef onChangedThunk;
+	};
+}

+ 2 - 0
SBansheeEditor/SBansheeEditor.vcxproj

@@ -229,11 +229,13 @@
     <ClInclude Include="Include\BsScriptEditorPrerequisites.h" />
     <ClInclude Include="Include\BsScriptEditorPrerequisites.h" />
     <ClInclude Include="Include\BsScriptEditorWindow.h" />
     <ClInclude Include="Include\BsScriptEditorWindow.h" />
     <ClInclude Include="Include\BsScriptGUIFoldout.h" />
     <ClInclude Include="Include\BsScriptGUIFoldout.h" />
+    <ClInclude Include="Include\BsScriptGUIIntField.h" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp" />
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp" />
     <ClCompile Include="Source\BsScriptEditorWindow.cpp" />
     <ClCompile Include="Source\BsScriptEditorWindow.cpp" />
     <ClCompile Include="Source\BsScriptGUIFoldout.cpp" />
     <ClCompile Include="Source\BsScriptGUIFoldout.cpp" />
+    <ClCompile Include="Source\BsScriptGUIIntField.cpp" />
   </ItemGroup>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">

+ 6 - 0
SBansheeEditor/SBansheeEditor.vcxproj.filters

@@ -24,6 +24,9 @@
     <ClInclude Include="Include\BsScriptGUIFoldout.h">
     <ClInclude Include="Include\BsScriptGUIFoldout.h">
       <Filter>Header Files</Filter>
       <Filter>Header Files</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptGUIIntField.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp">
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp">
@@ -35,5 +38,8 @@
     <ClCompile Include="Source\BsScriptGUIFoldout.cpp">
     <ClCompile Include="Source\BsScriptGUIFoldout.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptGUIIntField.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 88 - 0
SBansheeEditor/Source/BsScriptGUIIntField.cpp

@@ -0,0 +1,88 @@
+#include "BsScriptGUIIntField.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoManager.h"
+#include "BsMonoMethod.h"
+#include "BsSpriteTexture.h"
+#include "BsMonoUtil.h"
+#include "BsGUILayout.h"
+#include "BsGUIIntField.h"
+#include "BsGUIOptions.h"
+#include "BsGUIContent.h"
+#include "BsScriptGUIElementStyle.h"
+#include "BsScriptGUILayout.h"
+#include "BsScriptGUIArea.h"
+#include "BsScriptHString.h"
+#include "BsScriptGUIContent.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	ScriptGUIIntField::OnChangedThunkDef ScriptGUIIntField::onChangedThunk;
+
+	ScriptGUIIntField::ScriptGUIIntField(MonoObject* instance, GUIIntField* intField)
+		:TScriptGUIElement(instance, intField)
+	{
+
+	}
+
+	void ScriptGUIIntField::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptGUIIntField::internal_createInstance);
+		metaData.scriptClass->addInternalCall("Internal_GetValue", &ScriptGUIIntField::internal_getValue);
+		metaData.scriptClass->addInternalCall("Internal_SetValue", &ScriptGUIIntField::internal_setValue);
+
+		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)
+	{
+		GUIOptions options;
+
+		UINT32 arrayLen = (UINT32)mono_array_length(guiOptions);
+		for(UINT32 i = 0; i < arrayLen; i++)
+			options.addOption(mono_array_get(guiOptions, GUIOption, i));
+
+		GUIIntField* guiIntField = nullptr;
+		if(withTitle)
+		{
+			GUIContent nativeContent(ScriptGUIContent::getText(title), ScriptGUIContent::getImage(title), ScriptGUIContent::getTooltip(title));
+			guiIntField = GUIIntField::create(nativeContent, titleWidth, options,
+				toString(MonoUtil::monoToWString(titleStyle)),
+				toString(MonoUtil::monoToWString(inputStyle)));
+		}
+		else
+		{
+			guiIntField = GUIIntField::create(options, toString(MonoUtil::monoToWString(inputStyle)));
+		}
+
+		guiIntField->onValueChanged.connect(std::bind(&ScriptGUIIntField::onChanged, instance, _1));
+
+		ScriptGUIIntField* nativeInstance = new (cm_alloc<ScriptGUIIntField>()) ScriptGUIIntField(instance, guiIntField);
+	}
+
+	INT32 ScriptGUIIntField::internal_getValue(ScriptGUIIntField* nativeInstance)
+	{
+		GUIIntField* intField = static_cast<GUIIntField*>(nativeInstance->getGUIElement());
+
+		return intField->getValue();
+	}
+
+	void ScriptGUIIntField::internal_setValue(ScriptGUIIntField* nativeInstance, INT32 value)
+	{
+		GUIIntField* intField = static_cast<GUIIntField*>(nativeInstance->getGUIElement());
+
+		return intField->setValue(value);
+	}
+
+	void ScriptGUIIntField::onChanged(MonoObject* instance, INT32 newValue)
+	{
+		MonoException* exception = nullptr;
+		onChangedThunk(instance, newValue, &exception);
+
+		MonoUtil::throwIfException(exception);
+	}
+}