Browse Source

Added a GUIListBoxField and a GUIEnumField

BearishSun 10 years ago
parent
commit
50bcd9e76d

+ 2 - 0
BansheeEditor/BansheeEditor.vcxproj

@@ -298,6 +298,7 @@
     <ClInclude Include="Include\BsGUIHoverHitBox.h" />
     <ClInclude Include="Include\BsGUIIntField.h" />
     <ClInclude Include="Include\BsGUIDropButton.h" />
+    <ClInclude Include="Include\BsGUIListBoxField.h" />
     <ClInclude Include="Include\BsGUIStatusBar.h" />
     <ClInclude Include="Include\BsGUITextField.h" />
     <ClInclude Include="Include\BsGUIToggleField.h" />
@@ -384,6 +385,7 @@
     <ClCompile Include="Source\BsGUIFloatField.cpp" />
     <ClCompile Include="Source\BsGUIHoverHitBox.cpp" />
     <ClCompile Include="Source\BsGUIIntField.cpp" />
+    <ClCompile Include="Source\BsGUIListBoxField.cpp" />
     <ClCompile Include="Source\BsGUIMenuBar.cpp" />
     <ClCompile Include="Source\BsGUIDropButton.cpp" />
     <ClCompile Include="Source\BsGUIResourceTreeView.cpp" />

+ 6 - 0
BansheeEditor/BansheeEditor.vcxproj.filters

@@ -285,6 +285,9 @@
     <ClInclude Include="Include\BsGUIHoverHitBox.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsGUIListBoxField.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsEditorCommand.cpp">
@@ -509,5 +512,8 @@
     <ClCompile Include="Source\BsGUIHoverHitBox.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsGUIListBoxField.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 1 - 0
BansheeEditor/Include/BsEditorPrerequisites.h

@@ -38,6 +38,7 @@ namespace BansheeEngine
 	class GUIVector3Field;
 	class GUIVector4Field;
 	class GUIColorField;
+	class GUIListBoxField;
 	class GUIColor;
 	class GUIStatusBar;
 	class GUIDropButton;

+ 218 - 0
BansheeEditor/Include/BsGUIListBoxField.h

@@ -0,0 +1,218 @@
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsGUIElementContainer.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	A composite GUI object representing an editor field. Editor fields are a combination
+	 *			of a label and an input field. Label is optional. This specific implementation
+	 *			displays a list box field.
+	 */
+	class BS_ED_EXPORT GUIListBoxField : public GUIElementContainer
+	{
+		struct PrivatelyConstruct {};
+
+	public:
+		/**
+		 * Returns type name of the GUI element used for finding GUI element styles. 
+		 */
+		static const String& getGUITypeName();
+
+		/**
+		 * Returns style type name of the internal GUILabel element.
+		 */
+		static const String& getLabelStyleType();
+
+		/**
+		 * Style type name for the internal list box.
+		 */
+		static const String& getListBoxStyleType();
+
+		/**
+		 * @brief	Creates a new GUI list box field with a label.
+		 *
+		 * @param	elements		Elements to display in the list box.
+		 * @param	labelContent	Content to display in the editor field label.
+		 * @param	labelWidth		Width of the label in pixels.
+		 * @param	options			Options that allow you to control how is the element positioned and sized.
+		 *							This will override any similar options set by style.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUIListBoxField* create(const Vector<HString>& elements, const GUIContent& labelContent, UINT32 labelWidth, 
+			const GUIOptions& options, const String& style = StringUtil::BLANK);
+
+		/**
+		 * @brief	Creates a new GUI list box field with a label.
+		 *
+		 * @param	elements		Elements to display in the list box.
+		 * @param	labelContent	Content to display in the editor field label.
+		 * @param	options			Options that allow you to control how is the element positioned and sized.
+		 *							This will override any similar options set by style.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUIListBoxField* create(const Vector<HString>& elements, const GUIContent& labelContent, 
+			const GUIOptions& options, const String& style = StringUtil::BLANK);
+
+		/**
+		 * @brief	Creates a new GUI list box field with a label.
+		 *
+		 * @param	elements		Elements to display in the list box.
+		 * @param	labelText		String to display in the editor field label.
+		 * @param	labelWidth		Width of the label in pixels.
+		 * @param	options			Options that allow you to control how is the element positioned and sized.
+		 *							This will override any similar options set by style.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUIListBoxField* create(const Vector<HString>& elements, const HString& labelText, UINT32 labelWidth, 
+			const GUIOptions& options, const String& style = StringUtil::BLANK);
+
+		/**
+		 * @brief	Creates a new GUI list box field with a label.
+		 *
+		 * @param	elements		Elements to display in the list box.
+		 * @param	labelText		String to display in the editor field label.
+		 * @param	options			Options that allow you to control how is the element positioned and sized.
+		 *							This will override any similar options set by style.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUIListBoxField* create(const Vector<HString>& elements, const HString& labelText, const GUIOptions& options,
+			const String& style = StringUtil::BLANK);
+
+		/**
+		 * @brief	Creates a new GUI list box field without a label.
+		 *
+		 * @param	elements		Elements to display in the list box.
+		 * @param	options			Options that allow you to control how is the element positioned and sized.
+		 *							This will override any similar options set by style.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUIListBoxField* create(const Vector<HString>& elements, const GUIOptions& options, 
+			const String& style = StringUtil::BLANK);
+
+		/**
+		 * @brief	Creates a new GUI list box field with a label.
+		 *
+		 * @param	elements		Elements to display in the list box.
+		 * @param	labelContent	Content to display in the editor field label.
+		 * @param	labelWidth		Width of the label in pixels.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUIListBoxField* create(const Vector<HString>& elements, const GUIContent& labelContent, UINT32 labelWidth,
+			const String& style = StringUtil::BLANK);
+
+		/**
+		 * @brief	Creates a new GUI list box field with a label.
+		 *
+		 * @param	elements		Elements to display in the list box.
+		 * @param	labelContent	Content to display in the editor field label.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUIListBoxField* create(const Vector<HString>& elements, const GUIContent& labelContent,
+			const String& style = StringUtil::BLANK);
+
+		/**
+		 * @brief	Creates a new GUI list box field with a label.
+		 *
+		 * @param	elements		Elements to display in the list box.
+		 * @param	labelText		String to display in the editor field label.
+		 * @param	labelWidth		Width of the label in pixels.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUIListBoxField* create(const Vector<HString>& elements, const HString& labelText, UINT32 labelWidth,
+			const String& style = StringUtil::BLANK);
+
+		/**
+		 * @brief	Creates a new GUI list box field with a label.
+		 *
+		 * @param	elements		Elements to display in the list box.
+		 * @param	labelText		String to display in the editor field label.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUIListBoxField* create(const Vector<HString>& elements, const HString& labelText,
+			const String& style = StringUtil::BLANK);
+
+		/**
+		 * @brief	Creates a new GUI list box field without a label.
+		 *
+		 * @param	elements		Elements to display in the list box.
+		 * @param	styleName		Optional style to use for the element. Style will be retrieved
+		 *							from GUISkin of the GUIWidget the element is used on. If not specified
+		 *							default style is used.
+		 */
+		static GUIListBoxField* create(const Vector<HString>& elements, const String& style = StringUtil::BLANK);
+
+		GUIListBoxField(const PrivatelyConstruct& dummy, const Vector<HString>& elements, const GUIContent& labelContent, 
+			UINT32 labelWidth, const String& style, const GUIDimensions& dimensions, bool withLabel);
+
+		/**
+		 * @brief	Changes the list box elements.
+		 */
+		void setElements(const Vector<HString>& elements);
+
+		/**
+		 * @brief	Returns the index of the currently selected element.
+		 */
+		UINT32 getIndex() const { return mIndex; }
+
+		/**
+		 * @brief	Selects an element with the specified index.
+		 */
+		void setIndex(UINT32 value);
+
+		/**
+		 * @copydoc	GUIElement::setTint
+		 */
+		virtual void setTint(const Color& color) override;
+
+		Event<void(UINT32)> onSelectionChanged; /**< Triggers when a new element is selected. Provides index to the element. */
+	protected:
+		static const UINT32 DEFAULT_LABEL_WIDTH;
+
+		virtual ~GUIListBoxField();
+
+		/**
+		 * @copydoc	GUIElement::_updateLayoutInternal
+		 */
+		void _updateLayoutInternal(const GUILayoutData& data) override;
+
+		/**
+		 * @copydoc	GUIElement::_getOptimalSize
+		 */
+		Vector2I _getOptimalSize() const override;
+
+		/**
+		 * @copydoc	GUIElement::styleUpdated
+		 */
+		void styleUpdated() override;
+
+		/**
+		 * @brief	Triggered when the selected list box element changes.
+		 */
+		void selectionChanged(UINT32 newIndex);
+
+		GUIListBox* mListBox;
+		GUILayout* mLayout;
+		GUILabel* mLabel;
+		UINT32 mIndex;
+	};
+}

+ 12 - 1
BansheeEditor/Source/BsBuiltinEditorResources.cpp

@@ -20,11 +20,13 @@
 #include "BsGUIVector2Field.h"
 #include "BsGUIVector3Field.h"
 #include "BsGUIVector4Field.h"
+#include "BsGUIListBoxField.h"
 #include "BsGUIProgressBar.h"
 #include "BsGUISlider.h"
 #include "BsGUIDropDownContent.h"
 #include "BsGUIStatusBar.h"
 #include "BsGUIMenuBar.h"
+#include "BsGUIListBox.h"
 
 #include "BsFont.h"
 #include "BsFontImportOptions.h"
@@ -805,7 +807,7 @@ namespace BansheeEngine
 		dropDownListStyle.textHorzAlign = THA_Left;
 		dropDownListStyle.textVertAlign = TVA_Center;
 
-		skin->setStyle("ListBox", dropDownListStyle);
+		skin->setStyle(GUIListBox::getGUITypeName(), dropDownListStyle);
 
 		// DropDown scroll up button
 		GUIElementStyle dropDownScrollUpBtnStyle;
@@ -1343,6 +1345,15 @@ namespace BansheeEngine
 
 		skin->setStyle(GUIVector4Field::getGUITypeName(), editorVector4FieldStyle);
 
+		GUIElementStyle editorListBoxFieldStyle;
+		editorListBoxFieldStyle.fixedHeight = true;
+		editorListBoxFieldStyle.height = 30;
+		editorListBoxFieldStyle.minWidth = 30;
+		editorListBoxFieldStyle.subStyles[GUIListBoxField::getLabelStyleType()] = GUIListBoxField::getLabelStyleType();
+		editorListBoxFieldStyle.subStyles[GUIListBoxField::getListBoxStyleType()] = GUIListBox::getGUITypeName();
+
+		skin->setStyle(GUIListBoxField::getGUITypeName(), editorListBoxFieldStyle);
+
 		/************************************************************************/
 		/* 							     FOLDOUT                      		    */
 		/************************************************************************/

+ 210 - 0
BansheeEditor/Source/BsGUIListBoxField.cpp

@@ -0,0 +1,210 @@
+#include "BsGUIListBoxField.h"
+#include "BsGUILayoutX.h"
+#include "BsGUILabel.h"
+#include "BsGUIListBox.h"
+#include "BsBuiltinResources.h"
+#include "BsCGUIWidget.h"
+#include "BsGUIMouseEvent.h"
+#include "BsCGUIWidget.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	const UINT32 GUIListBoxField::DEFAULT_LABEL_WIDTH = 100;
+
+	GUIListBoxField::GUIListBoxField(const PrivatelyConstruct& dummy, const Vector<HString>& elements, 
+		const GUIContent& labelContent, UINT32 labelWidth, const String& style, const GUIDimensions& dimensions, bool withLabel)
+		:GUIElementContainer(dimensions, style),
+		mListBox(nullptr), mIndex(0), mLayout(nullptr), mLabel(nullptr)
+	{
+		mLayout = GUILayoutX::create();
+		_registerChildElement(mLayout);
+
+		if (withLabel)
+		{
+			mLabel = GUILabel::create(labelContent, GUIOptions(GUIOption::fixedWidth(labelWidth)), getSubStyleName(getLabelStyleType()));
+			mLayout->addElement(mLabel);
+		}
+
+		mListBox = GUIListBox::create(elements, getSubStyleName(getListBoxStyleType()));
+		mLayout->addElement(mListBox);
+
+		mListBox->onSelectionChanged.connect(std::bind(&GUIListBoxField::selectionChanged, this, _1));
+	}
+
+	GUIListBoxField::~GUIListBoxField()
+	{
+
+	}
+
+	GUIListBoxField* GUIListBoxField::create(const Vector<HString>& elements, const GUIContent& labelContent, UINT32 labelWidth, 
+		const GUIOptions& options, const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &GUIListBoxField::getGUITypeName();
+
+		return bs_new<GUIListBoxField>(PrivatelyConstruct(), elements, labelContent, labelWidth, *curStyle,
+			GUIDimensions::create(options), true);
+	}
+
+	GUIListBoxField* GUIListBoxField::create(const Vector<HString>& elements, const GUIContent& labelContent, const GUIOptions& options,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &GUIListBoxField::getGUITypeName();
+
+		return bs_new<GUIListBoxField>(PrivatelyConstruct(), elements, labelContent, DEFAULT_LABEL_WIDTH, *curStyle,
+			GUIDimensions::create(options), true);
+	}
+
+	GUIListBoxField* GUIListBoxField::create(const Vector<HString>& elements, const HString& labelText, UINT32 labelWidth, const GUIOptions& options,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &GUIListBoxField::getGUITypeName();
+
+		return bs_new<GUIListBoxField>(PrivatelyConstruct(), elements, GUIContent(labelText), labelWidth, *curStyle,
+			GUIDimensions::create(options), true);
+	}
+
+	GUIListBoxField* GUIListBoxField::create(const Vector<HString>& elements, const HString& labelText, const GUIOptions& options,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &GUIListBoxField::getGUITypeName();
+
+		return bs_new<GUIListBoxField>(PrivatelyConstruct(), elements, GUIContent(labelText), DEFAULT_LABEL_WIDTH, *curStyle,
+			GUIDimensions::create(options), true);
+	}
+
+	GUIListBoxField* GUIListBoxField::create(const Vector<HString>& elements, const GUIOptions& options, const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &GUIListBoxField::getGUITypeName();
+
+		return bs_new<GUIListBoxField>(PrivatelyConstruct(), elements, GUIContent(), 0, *curStyle,
+			GUIDimensions::create(options), false);
+	}
+
+	GUIListBoxField* GUIListBoxField::create(const Vector<HString>& elements, const GUIContent& labelContent, UINT32 labelWidth,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &GUIListBoxField::getGUITypeName();
+
+		return bs_new<GUIListBoxField>(PrivatelyConstruct(), elements, labelContent, labelWidth, *curStyle,
+			GUIDimensions::create(), true);
+	}
+
+	GUIListBoxField* GUIListBoxField::create(const Vector<HString>& elements, const GUIContent& labelContent,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &GUIListBoxField::getGUITypeName();
+
+		return bs_new<GUIListBoxField>(PrivatelyConstruct(), elements, labelContent, DEFAULT_LABEL_WIDTH, *curStyle,
+			GUIDimensions::create(), true);
+	}
+
+	GUIListBoxField* GUIListBoxField::create(const Vector<HString>& elements, const HString& labelText, UINT32 labelWidth,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &GUIListBoxField::getGUITypeName();
+
+		return bs_new<GUIListBoxField>(PrivatelyConstruct(), elements, GUIContent(labelText), labelWidth, *curStyle,
+			GUIDimensions::create(), true);
+	}
+
+	GUIListBoxField* GUIListBoxField::create(const Vector<HString>& elements, const HString& labelText,
+		const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &GUIListBoxField::getGUITypeName();
+
+		return bs_new<GUIListBoxField>(PrivatelyConstruct(), elements, GUIContent(labelText), DEFAULT_LABEL_WIDTH, *curStyle,
+			GUIDimensions::create(), true);
+	}
+
+	GUIListBoxField* GUIListBoxField::create(const Vector<HString>& elements, const String& style)
+	{
+		const String* curStyle = &style;
+		if (*curStyle == StringUtil::BLANK)
+			curStyle = &GUIListBoxField::getGUITypeName();
+
+		return bs_new<GUIListBoxField>(PrivatelyConstruct(), elements, GUIContent(), 0, *curStyle,
+			GUIDimensions::create(), false);
+	}
+
+	void GUIListBoxField::setElements(const Vector<HString>& elements)
+	{
+		mListBox->setElements(elements);
+	}
+
+	void GUIListBoxField::setIndex(UINT32 index)
+	{
+		mIndex = index;
+		mListBox->selectElement(index);
+	}
+
+	void GUIListBoxField::setTint(const Color& color)
+	{
+		if (mLabel != nullptr)
+			mLabel->setTint(color);
+
+		mListBox->setTint(color);
+	}
+
+	void GUIListBoxField::_updateLayoutInternal(const GUILayoutData& data)
+	{
+		mLayout->_setLayoutData(data);
+		mLayout->_updateLayoutInternal(data);
+	}
+
+	Vector2I GUIListBoxField::_getOptimalSize() const
+	{
+		return mLayout->_getOptimalSize();
+	}
+
+	void GUIListBoxField::styleUpdated()
+	{
+		if (mLabel != nullptr)
+			mLabel->setStyle(getSubStyleName(getLabelStyleType()));
+
+		mListBox->setStyle(getSubStyleName(getListBoxStyleType()));
+	}
+
+	void GUIListBoxField::selectionChanged(UINT32 newIndex)
+	{
+		mIndex = newIndex;
+		onSelectionChanged(newIndex);
+	}
+
+	const String& GUIListBoxField::getGUITypeName()
+	{
+		static String typeName = "GUIListBoxField";
+		return typeName;
+	}
+
+	const String& GUIListBoxField::getListBoxStyleType()
+	{
+		static String LISTBOX_STYLE_TYPE = "EditorFieldListBox";
+		return LISTBOX_STYLE_TYPE;
+	}
+
+	const String& GUIListBoxField::getLabelStyleType()
+	{
+		static String LABEL_STYLE_TYPE = "EditorFieldLabel";
+		return LABEL_STYLE_TYPE;
+	}
+}

+ 3 - 0
BansheeEngine/Source/BsGUIListBox.cpp

@@ -82,6 +82,9 @@ namespace BansheeEngine
 
 	void GUIListBox::elementSelected(UINT32 idx)
 	{
+		if (idx >= (UINT32)mElements.size())
+			return;
+
 		if(!onSelectionChanged.empty())
 			onSelectionChanged(idx);
 

+ 11 - 7
BansheeMono/Include/BsMonoArray.h

@@ -39,19 +39,22 @@ namespace BansheeEngine
 		void set<WString>(UINT32 idx, const WString& value);
 
 		template<class T>
-		T* getRawPtr(UINT32 offset = 0)
+		T* getRawPtr(UINT32 idx = 0)
 		{
 #if BS_DEBUG_MODE
-			int nativeSize = sizeof(T);
+			assert(sizeof(T) == elementSize());
+#endif
 
-			::MonoClass* arrayClass = mono_object_get_class((MonoObject*)(mInternal));
-			::MonoClass* elementClass = mono_class_get_element_class(arrayClass);
+			return (T*)mono_array_addr(mInternal, T, idx);
+		}
 
-			int monoSize = mono_class_array_element_size(elementClass);
-			assert(nativeSize == monoSize);
+		UINT8* getRawPtr(UINT32 size, UINT32 idx = 0)
+		{
+#if BS_DEBUG_MODE
+			assert(size == elementSize());
 #endif
 
-			return (T*)mono_array_addr(mInternal, T, offset);
+			return (UINT8*)mono_array_addr_with_size(mInternal, size, idx);
 		}
 
 		template<class T>
@@ -103,6 +106,7 @@ namespace BansheeEngine
 		}
 
 		UINT32 size() const;
+		UINT32 elementSize() const;
 
 		MonoArray* getInternal() const { return mInternal; }
 

+ 8 - 0
BansheeMono/Source/BsMonoArray.cpp

@@ -54,6 +54,14 @@ namespace BansheeEngine
 		return (UINT32)mono_array_length(mInternal);
 	}
 
+	UINT32 ScriptArray::elementSize() const
+	{
+		::MonoClass* arrayClass = mono_object_get_class((MonoObject*)(mInternal));
+		::MonoClass* elementClass = mono_class_get_element_class(arrayClass);
+
+		return (UINT32)mono_class_array_element_size(elementClass);
+	}
+
 	template BS_MONO_EXPORT String ScriptArray::get(UINT32 idx);
 	template BS_MONO_EXPORT WString ScriptArray::get(UINT32 idx);
 

+ 114 - 0
MBansheeEditor/GUI/GUIEnumField.cs

@@ -0,0 +1,114 @@
+using System;
+using System.Runtime.CompilerServices;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Editor GUI element that displays a list box with elements of an enumeration and an optional label.
+    /// </summary>
+    public sealed class GUIEnumField : GUIElement
+    {
+        public delegate void OnSelectionChangedDelegate(int value);
+
+        /// <summary>
+        /// Triggered whenever user selects a new element in the list box. Returns the value of the enumeration entry that 
+        /// was selected.
+        /// </summary>
+        public event OnSelectionChangedDelegate OnSelectionChanged;
+
+        /// <summary>
+        /// Value of the enumeration entry currently selected.
+        /// </summary>
+        public int Value
+        {
+            get { return Internal_GetValue(mCachedPtr); }
+            set { Internal_SetValue(mCachedPtr, value); }
+        }
+
+        /// <summary>
+        /// Creates a new list box with enumeration entries as its elements and a label.
+        /// </summary>
+        /// <param name="enumType">Type of enum of whose entries to display in the list box.</param>
+        /// <param name="title">Content to display on the label.</param>
+        /// <param name="titleWidth">Width of the title label in pixels.</param>
+        /// <param name="style">Optional style to use for the element. Style controls the look of the element, as well as 
+        ///                     default layout options. Style will be retrieved from the active GUISkin. If not specified 
+        ///                     default element style is used.</param>
+        /// <param name="options">Options that allow you to control how is the element positioned and sized. This will 
+        ///                       override any similar options set by style.</param>
+        public GUIEnumField(Type enumType, GUIContent title, int titleWidth = 100, string style = "", params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, Enum.GetNames(enumType), Enum.GetValues(enumType), title, titleWidth, style, options, true);
+        }
+
+        /// <summary>
+        /// Creates a new list box with enumeration entries as its elements and a label.
+        /// </summary>
+        /// <param name="enumType">Type of enum of whose entries to display in the list box.</param>
+        /// <param name="title">Content to display on the label.</param>
+        /// <param name="titleWidth">Width of the title label in pixels.</param>
+        /// <param name="options">Options that allow you to control how is the element positioned and sized. This will 
+        ///                       override any similar options set by style.</param>
+        public GUIEnumField(Type enumType, GUIContent title, int titleWidth = 100, params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, Enum.GetNames(enumType), Enum.GetValues(enumType), title, titleWidth, "", options, true);
+        }
+
+        /// <summary>
+        /// Creates a new list box with enumeration entries as its elements and no label.
+        /// </summary>
+        /// <param name="enumType">Type of enum of whose entries to display in the list box.</param>
+        /// <param name="style">Optional style to use for the element. Style controls the look of the element, as well as 
+        ///                     default layout options. Style will be retrieved from the active GUISkin. If not specified 
+        ///                     default element style is used.</param>
+        /// <param name="options">Options that allow you to control how is the element positioned and sized. This will 
+        ///                       override any similar options set by style.</param>
+        public GUIEnumField(Type enumType, string style = "", params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, Enum.GetNames(enumType), Enum.GetValues(enumType), null, 0, style, options, false);
+        }
+
+        /// <summary>
+        /// Creates a new list box with enumeration entries as its elements and no label.
+        /// </summary>
+        /// <param name="enumType">Type of enum of whose entries to display in the list box.</param>
+        /// <param name="options">Options that allow you to control how is the element positioned and sized. This will 
+        ///                       override any similar options set by style.</param>
+        public GUIEnumField(Type enumType, params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, Enum.GetNames(enumType), Enum.GetValues(enumType), null, 0, "", options, false);
+        }
+
+        /// <summary>
+        /// Colors the element with a specific tint.
+        /// </summary>
+        /// <param name="color">Tint to apply to the element.</param>
+        public void SetTint(Color color)
+        {
+            Internal_SetTint(mCachedPtr, color);
+        }
+
+        /// <summary>
+        /// Triggered by the native interop object when a user selects an object in the list.
+        /// </summary>
+        private void DoOnSelectionChanged(int index)
+        {
+            if (OnSelectionChanged != null)
+                OnSelectionChanged(index);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(GUIEnumField instance, string[] names, Array values, 
+            GUIContent title, int titleWidth, string style, 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);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetTint(IntPtr nativeInstance, Color color);
+    }
+}

+ 132 - 0
MBansheeEditor/GUI/GUIListBoxField.cs

@@ -0,0 +1,132 @@
+using System;
+using System.Runtime.CompilerServices;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Editor GUI element that displays a list box with user-specified elements and an optional label.
+    /// </summary>
+    public sealed class GUIListBoxField : GUIElement
+    {
+        public delegate void OnSelectionChangedDelegate(int index);
+
+        /// <summary>
+        /// Triggered whenever user selects a new element in the list box. Returned index maps to the element in the
+        /// elements array that the list box was initialized with.
+        /// </summary>
+        public event OnSelectionChangedDelegate OnSelectionChanged;
+
+        /// <summary>
+        /// Index of the list box entry currently selected.
+        /// </summary>
+        public int Index
+        {
+            get { return Internal_GetValue(mCachedPtr); }
+            set { Internal_SetValue(mCachedPtr, value); }
+        }
+
+        /// <summary>
+        /// Creates a new list box with the specified elements and a label.
+        /// </summary>
+        /// <param name="elements">Array of elements to display in the list box. Elements will be displayed in the same 
+        ///                        order as in the array.</param>
+        /// <param name="title">Content to display on the label.</param>
+        /// <param name="titleWidth">Width of the title label in pixels.</param>
+        /// <param name="style">Optional style to use for the element. Style controls the look of the element, as well as 
+        ///                     default layout options. Style will be retrieved from the active GUISkin. If not specified 
+        ///                     default element style is used.</param>
+        /// <param name="options">Options that allow you to control how is the element positioned and sized. This will 
+        ///                       override any similar options set by style.</param>
+        public GUIListBoxField(LocString[] elements, GUIContent title, int titleWidth = 100, string style = "", 
+            params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, elements, title, titleWidth, style, options, true);
+        }
+
+        /// <summary>
+        /// Creates a new list box with the specified elements and a label.
+        /// </summary>
+        /// <param name="elements">Array of elements to display in the list box. Elements will be displayed in the same 
+        ///                        order as in the array.</param>
+        /// <param name="title">Content to display on the label.</param>
+        /// <param name="titleWidth">Width of the title label in pixels.</param>
+        /// <param name="options">Options that allow you to control how is the element positioned and sized. This will 
+        ///                       override any similar options set by style.</param>
+        public GUIListBoxField(LocString[] elements, GUIContent title, int titleWidth = 100, params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, elements, title, titleWidth, "", options, true);
+        }
+
+        /// <summary>
+        /// Creates a new list box with the specified elements and no label.
+        /// </summary>
+        /// <param name="elements">Array of elements to display in the list box. Elements will be displayed in the same 
+        ///                        order as in the array.</param>
+        /// <param name="style">Optional style to use for the element. Style controls the look of the element, as well as 
+        ///                     default layout options. Style will be retrieved from the active GUISkin. If not specified 
+        ///                     default element style is used.</param>
+        /// <param name="options">Options that allow you to control how is the element positioned and sized. This will 
+        ///                       override any similar options set by style.</param>
+        public GUIListBoxField(LocString[] elements, string style = "", params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, elements, null, 0, style, options, false);
+        }
+
+        /// <summary>
+        /// Creates a new list box with the specified elements and no label.
+        /// </summary>
+        /// <param name="elements">Array of elements to display in the list box. Elements will be displayed in the same 
+        ///                        order as in the array.</param>
+        /// <param name="options">Options that allow you to control how is the element positioned and sized. This will 
+        ///                       override any similar options set by style.</param>
+        public GUIListBoxField(LocString[] elements, params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, elements, null, 0, "", options, false);
+        }
+
+        /// <summary>
+        /// Updates the list box with a new set of elements.
+        /// </summary>
+        /// <param name="elements">Array of elements to display in the list box. Elements will be displayed in the same 
+        ///                        order as in the array.</param>
+        public void SetElements(LocString[] elements)
+        {
+            Internal_SetElements(mCachedPtr, elements);
+        }
+
+        /// <summary>
+        /// Colors the element with a specific tint.
+        /// </summary>
+        /// <param name="color">Tint to apply to the element.</param>
+        public void SetTint(Color color)
+        {
+            Internal_SetTint(mCachedPtr, color);
+        }
+
+        /// <summary>
+        /// Triggered by the native interop object when a user selects an object in the list.
+        /// </summary>
+        private void DoOnSelectionChanged(int index)
+        {
+            if (OnSelectionChanged != null)
+                OnSelectionChanged(index);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(GUIListBoxField instance, LocString[] entries,
+            GUIContent title, int titleWidth, string style, GUIOption[] options, bool withTitle);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetElements(IntPtr nativeInstance, LocString[] elements);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int Internal_GetValue(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetValue(IntPtr nativeInstance, int value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetTint(IntPtr nativeInstance, Color color);
+    }
+}

+ 1 - 1
MBansheeEditor/Inspector/CustomInspector.cs

@@ -6,7 +6,7 @@ namespace BansheeEditor
     /// <summary>
     /// Specifies that a class or a struct uses a custom inspector for GUI display. This attribute can be placed on an 
     /// implementation of <see cref="Inspector"/> in which case the type must reference a <see cref="Component"/> or a
-    /// <see cref="ManagedResource"/>. Or it can be placed on an implementation of <see cref="InspectableField"/> in which
+    /// <see cref="Resource"/>. Or it can be placed on an implementation of <see cref="InspectableField"/> in which
     /// case they type must reference any serializable class/struct, but may also reference an attribute in which case
     /// any serializable type with that attribute applied with have a custom inspector.
     /// </summary>

+ 0 - 27
MBansheeEditor/Inspector/GenericInspector.cs

@@ -13,36 +13,9 @@ namespace BansheeEditor
     /// </summary>
     internal sealed class GenericInspector : Inspector
     {
-        private GUIPanel RootGUI;
         private bool isInitialized;
         private List<InspectableField> inspectableFields = new List<InspectableField>();
 
-        /// <inheritdoc/>
-        internal override void Initialize(InspectorWindow parentWindow, GUIPanel gui, object instance)
-        {
-            RootGUI = gui;
-
-            GUILayout contentLayoutX = gui.AddLayoutX();
-            contentLayoutX.AddSpace(5);
-            GUILayout contentLayoutY = contentLayoutX.AddLayoutY();
-            contentLayoutY.AddSpace(5);
-            GUIPanel contentPanel = contentLayoutY.AddPanel();
-            contentLayoutY.AddSpace(5);
-            contentLayoutX.AddSpace(5);
-
-            GUIPanel backgroundPanel = gui.AddPanel(START_BACKGROUND_DEPTH);
-            GUITexture inspectorContentBg = new GUITexture(null, EditorStyles.InspectorContentBg);
-            backgroundPanel.AddElement(inspectorContentBg);
-
-            base.Initialize(parentWindow, contentPanel, instance);
-        }
-
-        /// <inheritdoc/>
-        internal override void SetVisible(bool visible)
-        {
-            RootGUI.Visible = visible;
-        }
-
         /// <summary>
         /// Initializes required data the first time <see cref="Refresh"/> is called.
         /// </summary>

+ 17 - 2
MBansheeEditor/Inspector/Inspector.cs

@@ -17,6 +17,7 @@ namespace BansheeEditor
         protected GUILayoutY layout;
         protected object referencedObject;
 
+        private GUIPanel RootGUI;
         private InspectorWindow parentWindow;
 
         /// <summary>
@@ -27,7 +28,21 @@ namespace BansheeEditor
         /// <param name="instance">Instance of the object whose fields to display GUI for.</param>
         internal virtual void Initialize(InspectorWindow parentWindow, GUIPanel gui, object instance)
         {
-            GUI = gui;
+            RootGUI = gui;
+
+            GUILayout contentLayoutX = gui.AddLayoutX();
+            contentLayoutX.AddSpace(5);
+            GUILayout contentLayoutY = contentLayoutX.AddLayoutY();
+            contentLayoutY.AddSpace(5);
+            GUIPanel contentPanel = contentLayoutY.AddPanel();
+            contentLayoutY.AddSpace(5);
+            contentLayoutX.AddSpace(5);
+
+            GUIPanel backgroundPanel = gui.AddPanel(START_BACKGROUND_DEPTH);
+            GUITexture inspectorContentBg = new GUITexture(null, EditorStyles.InspectorContentBg);
+            backgroundPanel.AddElement(inspectorContentBg);
+
+            GUI = contentPanel;
             layout = GUI.AddLayoutY();
             referencedObject = instance;
             this.parentWindow = parentWindow;
@@ -39,7 +54,7 @@ namespace BansheeEditor
         /// <param name="visible">True to make the GUI elements visible.</param>
         internal virtual void SetVisible(bool visible)
         {
-            GUI.Visible = visible;
+            RootGUI.Visible = visible;
         }
 
         /// <summary>

+ 47 - 0
MBansheeEditor/Inspectors/CameraInspector.cs

@@ -0,0 +1,47 @@
+using System.Collections.Generic;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Renders an inspector for the <see cref="Camera"/> component.
+    /// </summary>
+    public class CameraInspector : Inspector
+    {
+        private bool isInitialized;
+        private List<InspectableField> inspectableFields = new List<InspectableField>();
+
+        /// <summary>
+        /// Initializes required data the first time <see cref="Refresh"/> is called.
+        /// </summary>
+        private void Initialize()
+        {
+            if (referencedObject != null)
+            {
+                Camera camera = (Camera) referencedObject;
+
+                
+            }
+
+            isInitialized = true;
+        }
+
+        /// <inheritdoc/>
+        internal override bool Refresh()
+        {
+            if (!isInitialized)
+                Initialize();
+
+            bool anythingModified = false;
+
+            int currentIndex = 0;
+            foreach (var field in inspectableFields)
+            {
+                anythingModified |= field.Refresh(currentIndex);
+                currentIndex += field.GetNumLayoutElements();
+            }
+
+            return anythingModified;
+        }
+    }
+}

+ 3 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -47,9 +47,12 @@
     <Compile Include="DragDrop.cs" />
     <Compile Include="DropDownWindow.cs" />
     <Compile Include="FolderMonitor.cs" />
+    <Compile Include="GUI\GUIEnumField.cs" />
+    <Compile Include="GUI\GUIListBoxField.cs" />
     <Compile Include="GUI\GUISceneTreeView.cs" />
     <Compile Include="GUI\TextureField.cs" />
     <Compile Include="HierarchyWindow.cs" />
+    <Compile Include="Inspectors\CameraInspector.cs" />
     <Compile Include="Inspector\InspectorUtility.cs" />
     <Compile Include="LibraryMenu.cs" />
     <Compile Include="LibraryUtility.cs" />

+ 7 - 6
MBansheeEngine/GUI/GUIListBox.cs

@@ -11,8 +11,8 @@ namespace BansheeEngine
         public delegate void OnSelectionChangedDelegate(int index);
 
         /// <summary>
-        /// Triggered whenever user selects a new element in the list box. Returned index maps to the element in the elements 
-        /// array that the list box was initialized with.
+        /// Triggered whenever user selects a new element in the list box. Returned index maps to the element in the 
+        /// elements array that the list box was initialized with.
         /// </summary>
         public event OnSelectionChangedDelegate OnSelectionChanged;
 
@@ -26,7 +26,7 @@ namespace BansheeEngine
         ///                     default element style is used.</param>
         /// <param name="options">Options that allow you to control how is the element positioned and sized. This will 
         ///                       override any similar options set by style.</param>
-        public GUIListBox(LocString[] elements, string style, params GUIOption[] options)
+        public GUIListBox(LocString[] elements, string style = "", params GUIOption[] options)
         {
             Internal_CreateInstance(this, elements, style, options);
         }
@@ -46,8 +46,8 @@ namespace BansheeEngine
         /// <summary>
         /// Updates the list box with a new set of elements.
         /// </summary>
-        /// <param name="elements">Array of elements to display in the list box. Elements will be displayed in the same order
-        /// as in the array.</param>
+        /// <param name="elements">Array of elements to display in the list box. Elements will be displayed in the same 
+        ///                        order as in the array.</param>
         public void SetElements(LocString[] elements)
         {
             Internal_SetElements(mCachedPtr, elements);
@@ -72,7 +72,8 @@ namespace BansheeEngine
         }
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstance(GUIListBox instance, LocString[] elements, string style, params GUIOption[] options);
+        private static extern void Internal_CreateInstance(GUIListBox instance, LocString[] elements, string style, 
+            GUIOption[] options);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetElements(IntPtr nativeInstance, LocString[] elements);

+ 0 - 7
SBansheeEditor/Include/BsEditorScriptManager.h

@@ -38,11 +38,6 @@ namespace BansheeEngine
 		 */
 		void loadMonoTypes();
 
-		/**
-		 * @brief	Triggers assembly refresh on next ::update.
-		 */
-		static void debug_refreshAssembly();
-
 		static const float EDITOR_UPDATE_RATE;
 
 		MonoAssembly* mEditorAssembly;
@@ -53,7 +48,5 @@ namespace BansheeEngine
 
 		HEvent mOnDomainLoadConn;
 		HEvent mOnAssemblyRefreshDoneConn;
-
-		static bool mDebugRefresh;
 	};
 }

+ 44 - 0
SBansheeEditor/Include/BsScriptGUIEnumField.h

@@ -0,0 +1,44 @@
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsScriptGUIElement.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Interop class between C++ & CLR for GUIListBoxField, with some specific functionality
+	 *			meant for displaying managed enumeration values.
+	 */
+	class BS_SCR_BED_EXPORT ScriptGUIEnumField : public TScriptGUIElement<ScriptGUIEnumField>
+	{
+	public:
+		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "GUIEnumField")
+
+	private:
+		/**
+		 * @brief	Triggered when the value in the native list box selection changes.
+		 *
+		 * @param	instance	Managed GUIEnumField instance.
+		 * @param	newIndex	New selection index.
+		 */
+		static void onSelectionChanged(MonoObject* instance, UINT32 newIndex);
+
+		ScriptGUIEnumField(MonoObject* instance, GUIListBoxField* listBoxField, const Vector<UINT32>& values);
+
+		Vector<UINT32> mValues;
+
+		/************************************************************************/
+		/* 								CLR HOOKS						   		*/
+		/************************************************************************/
+		static void internal_createInstance(MonoObject* instance, MonoArray* names, MonoArray* values, MonoObject* title, 
+			UINT32 titleWidth, MonoString* style, MonoArray* guiOptions, bool withTitle);
+
+		static UINT32 internal_getValue(ScriptGUIEnumField* nativeInstance);
+		static void internal_setValue(ScriptGUIEnumField* nativeInstance, UINT32 value);
+		static void internal_setTint(ScriptGUIEnumField* nativeInstance, Color color);
+
+		typedef void(__stdcall *OnSelectionChangedThunkDef) (MonoObject*, UINT32, MonoException**);
+
+		static OnSelectionChangedThunkDef onSelectionChangedThunk;
+	};
+}

+ 42 - 0
SBansheeEditor/Include/BsScriptGUIListBoxField.h

@@ -0,0 +1,42 @@
+#pragma once
+
+#include "BsScriptEditorPrerequisites.h"
+#include "BsScriptGUIElement.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Interop class between C++ & CLR for GUIListBoxField.
+	 */
+	class BS_SCR_BED_EXPORT ScriptGUIListBoxField : public TScriptGUIElement<ScriptGUIListBoxField>
+	{
+	public:
+		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "GUIListBoxField")
+
+	private:
+		/**
+		 * @brief	Triggered when the value in the native list box selection changes.
+		 *
+		 * @param	instance	Managed GUIListBoxField instance.
+		 * @param	newIndex	New selection index.
+		 */
+		static void onSelectionChanged(MonoObject* instance, UINT32 newIndex);
+
+		ScriptGUIListBoxField(MonoObject* instance, GUIListBoxField* listBoxField);
+
+		/************************************************************************/
+		/* 								CLR HOOKS						   		*/
+		/************************************************************************/
+		static void internal_createInstance(MonoObject* instance, MonoArray* elements, MonoObject* title, UINT32 titleWidth,
+			MonoString* style, MonoArray* guiOptions, bool withTitle);
+
+		static void internal_setElements(ScriptGUIListBoxField* nativeInstance, MonoArray* elements);
+		static UINT32 internal_getValue(ScriptGUIListBoxField* nativeInstance);
+		static void internal_setValue(ScriptGUIListBoxField* nativeInstance, UINT32 value);
+		static void internal_setTint(ScriptGUIListBoxField* nativeInstance, Color color);
+
+		typedef void(__stdcall *OnSelectionChangedThunkDef) (MonoObject*, UINT32, MonoException**);
+
+		static OnSelectionChangedThunkDef onSelectionChangedThunk;
+	};
+}

+ 4 - 0
SBansheeEditor/SBansheeEditor.vcxproj

@@ -246,6 +246,8 @@
     <ClInclude Include="Include\BsScriptDropDownWindow.h" />
     <ClInclude Include="Include\BsScriptEditorTestSuite.h" />
     <ClInclude Include="Include\BsScriptFolderMonitor.h" />
+    <ClInclude Include="Include\BsScriptGUIEnumField.h" />
+    <ClInclude Include="Include\BsScriptGUIListBoxField.h" />
     <ClInclude Include="Include\BsScriptGUISceneTreeView.h" />
     <ClInclude Include="Include\BsScriptGUITextureField.h" />
     <ClInclude Include="Include\BsScriptInspectorUtility.h" />
@@ -301,6 +303,8 @@
     <ClCompile Include="Source\BsScriptDropDownWindow.cpp" />
     <ClCompile Include="Source\BsScriptEditorTestSuite.cpp" />
     <ClCompile Include="Source\BsScriptFolderMonitor.cpp" />
+    <ClCompile Include="Source\BsScriptGUIEnumField.cpp" />
+    <ClCompile Include="Source\BsScriptGUIListBoxField.cpp" />
     <ClCompile Include="Source\BsScriptGUISceneTreeView.cpp" />
     <ClCompile Include="Source\BsScriptGUITextureField.cpp" />
     <ClCompile Include="Source\BsScriptInspectorUtility.cpp" />

+ 12 - 0
SBansheeEditor/SBansheeEditor.vcxproj.filters

@@ -174,6 +174,12 @@
     <ClInclude Include="Include\BsScriptInspectorUtility.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptGUIListBoxField.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptGUIEnumField.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptEditorPlugin.cpp">
@@ -335,5 +341,11 @@
     <ClCompile Include="Source\BsScriptInspectorUtility.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptGUIListBoxField.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsScriptGUIEnumField.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 0 - 16
SBansheeEditor/Source/BsEditorScriptManager.cpp

@@ -26,7 +26,6 @@
 namespace BansheeEngine
 {
 	const float EditorScriptManager::EDITOR_UPDATE_RATE = 1.0f/60.0f; // Seconds
-	bool EditorScriptManager::mDebugRefresh = false;
 
 	EditorScriptManager::EditorScriptManager()
 		:mEditorAssembly(nullptr), mProgramEdClass(nullptr), mUpdateMethod(nullptr)
@@ -96,23 +95,12 @@ namespace BansheeEngine
 			mLastUpdateTime += numUpdates * EDITOR_UPDATE_RATE;
 		}
 
-		if (mDebugRefresh)
-		{
-			ScriptManager::instance().reload();
-			mDebugRefresh = false;
-		}
-
 		ScriptGizmoManager::instance().update();
 		ScriptDragDropManager::instance().update();
 		ScriptFolderMonitorManager::instance().update();
 		ScriptEditorApplication::update();
 	}
 
-	void EditorScriptManager::debug_refreshAssembly()
-	{
-		mDebugRefresh = true;
-	}
-
 	void EditorScriptManager::triggerOnInitialize()
 	{
 		const String ASSEMBLY_ENTRY_POINT = "Program::OnInitialize";
@@ -134,9 +122,5 @@ namespace BansheeEngine
 
 		ScriptEditorWindow::clearRegisteredEditorWindow();
 		ScriptEditorWindow::registerManagedEditorWindows();
-
-		// DEBUG ONLY
-		MonoClass* debugWindowClass = mEditorAssembly->getClass("BansheeEditor", "DebugWindow");
-		debugWindowClass->addInternalCall("Internal_RefreshAssembly", &EditorScriptManager::debug_refreshAssembly);
 	}
 }

+ 127 - 0
SBansheeEditor/Source/BsScriptGUIEnumField.cpp

@@ -0,0 +1,127 @@
+#include "BsScriptGUIEnumField.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoManager.h"
+#include "BsMonoMethod.h"
+#include "BsMonoUtil.h"
+#include "BsGUIListBoxField.h"
+#include "BsGUIOptions.h"
+#include "BsGUIContent.h"
+#include "BsScriptHString.h"
+#include "BsScriptGUIContent.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	ScriptGUIEnumField::OnSelectionChangedThunkDef ScriptGUIEnumField::onSelectionChangedThunk;
+
+	ScriptGUIEnumField::ScriptGUIEnumField(MonoObject* instance, GUIListBoxField* listBoxField, const Vector<UINT32>& values)
+		:TScriptGUIElement(instance, listBoxField), mValues(values)
+	{
+
+	}
+
+	void ScriptGUIEnumField::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptGUIEnumField::internal_createInstance);
+		metaData.scriptClass->addInternalCall("Internal_GetValue", &ScriptGUIEnumField::internal_getValue);
+		metaData.scriptClass->addInternalCall("Internal_SetValue", &ScriptGUIEnumField::internal_setValue);
+		metaData.scriptClass->addInternalCall("Internal_SetTint", &ScriptGUIEnumField::internal_setTint);
+
+		onSelectionChangedThunk = (OnSelectionChangedThunkDef)metaData.scriptClass->getMethod("DoOnSelectionChanged", 1)->getThunk();
+	}
+
+	void ScriptGUIEnumField::internal_createInstance(MonoObject* instance, MonoArray* names, MonoArray* values, 
+		MonoObject* title, UINT32 titleWidth, MonoString* style, 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));
+
+		String styleName = toString(MonoUtil::monoToWString(style));
+
+		ScriptArray namesArr(names);
+		Vector<HString> nativeNames;
+		for (UINT32 i = 0; i < namesArr.size(); i++)
+			nativeNames.push_back(HString(namesArr.get<WString>(i)));
+
+		GUIListBoxField* guiField = nullptr;
+		if (withTitle)
+		{
+			GUIContent nativeContent(ScriptGUIContent::getText(title), ScriptGUIContent::getImage(title), ScriptGUIContent::getTooltip(title));
+			guiField = GUIListBoxField::create(nativeNames, nativeContent, titleWidth, options, styleName);
+		}
+		else
+		{
+			guiField = GUIListBoxField::create(nativeNames, options, styleName);
+		}
+
+		guiField->onSelectionChanged.connect(std::bind(&ScriptGUIEnumField::onSelectionChanged, instance, _1));
+
+		ScriptArray valuesArr(values);
+		UINT32 elemSize = valuesArr.elementSize();
+
+		Vector<UINT32> nativeValues;
+		for (UINT32 i = 0; i < valuesArr.size(); i++)
+		{
+			// Truncate, as we don't check exact value type for enums
+			UINT32 nativeValue = 0;
+
+#if BS_ENDIAN == BS_ENDIAN_LITTLE
+			memcpy(&nativeValue, valuesArr.getRawPtr(elemSize, i), std::min(elemSize, (UINT32)sizeof(UINT32)));
+#else
+			INT32 diff = (INT32)sizeof(UINT32) - (INT32)elemSize;
+			UINT32 offsetDst = diff > 0 ? (UINT32)diff : 0;
+			UINT32 offsetSrc = diff < 0 ? (UINT32)-diff : 0;
+
+			memcpy(((UINT8*)&nativeValue) + offsetDst, valuesArr.getRawPtr(elemSize, i) + offsetSrc, 
+				std::min(elemSize, (UINT32)sizeof(UINT32)));
+#endif
+		}
+			
+
+		ScriptGUIEnumField* nativeInstance = new (bs_alloc<ScriptGUIEnumField>()) ScriptGUIEnumField(instance, guiField, nativeValues);
+	}
+
+	UINT32 ScriptGUIEnumField::internal_getValue(ScriptGUIEnumField* nativeInstance)
+	{
+		GUIListBoxField* field = static_cast<GUIListBoxField*>(nativeInstance->getGUIElement());
+		UINT32 idx = field->getIndex();
+
+		const Vector<UINT32>& values = nativeInstance->mValues;
+		if (idx < (UINT32)values.size())
+			return values[idx];
+
+		return 0;
+	}
+
+	void ScriptGUIEnumField::internal_setValue(ScriptGUIEnumField* nativeInstance, UINT32 value)
+	{
+		GUIListBoxField* field = static_cast<GUIListBoxField*>(nativeInstance->getGUIElement());
+
+		const Vector<UINT32>& values = nativeInstance->mValues;
+		for (UINT32 i = 0; i < (UINT32)values.size(); i++)
+		{
+			if (values[i] == value)
+			{
+				field->setIndex(i);
+				break;
+			}
+		}
+	}
+
+	void ScriptGUIEnumField::internal_setTint(ScriptGUIEnumField* nativeInstance, Color color)
+	{
+		GUIListBoxField* field = (GUIListBoxField*)nativeInstance->getGUIElement();
+		field->setTint(color);
+	}
+
+	void ScriptGUIEnumField::onSelectionChanged(MonoObject* instance, UINT32 newIndex)
+	{
+		MonoUtil::invokeThunk(onSelectionChangedThunk, instance, newIndex);
+	}
+}

+ 122 - 0
SBansheeEditor/Source/BsScriptGUIListBoxField.cpp

@@ -0,0 +1,122 @@
+#include "BsScriptGUIListBoxField.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoManager.h"
+#include "BsMonoMethod.h"
+#include "BsMonoUtil.h"
+#include "BsGUIListBoxField.h"
+#include "BsGUIOptions.h"
+#include "BsGUIContent.h"
+#include "BsScriptHString.h"
+#include "BsScriptGUIContent.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	ScriptGUIListBoxField::OnSelectionChangedThunkDef ScriptGUIListBoxField::onSelectionChangedThunk;
+
+	ScriptGUIListBoxField::ScriptGUIListBoxField(MonoObject* instance, GUIListBoxField* listBoxField)
+		:TScriptGUIElement(instance, listBoxField)
+	{
+
+	}
+
+	void ScriptGUIListBoxField::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptGUIListBoxField::internal_createInstance);
+		metaData.scriptClass->addInternalCall("Internal_SetElements", &ScriptGUIListBoxField::internal_setElements);
+		metaData.scriptClass->addInternalCall("Internal_GetValue", &ScriptGUIListBoxField::internal_getValue);
+		metaData.scriptClass->addInternalCall("Internal_SetValue", &ScriptGUIListBoxField::internal_setValue);
+		metaData.scriptClass->addInternalCall("Internal_SetTint", &ScriptGUIListBoxField::internal_setTint);
+
+		onSelectionChangedThunk = (OnSelectionChangedThunkDef)metaData.scriptClass->getMethod("DoOnSelectionChanged", 1)->getThunk();
+	}
+
+	void ScriptGUIListBoxField::internal_createInstance(MonoObject* instance, MonoArray* elements, MonoObject* title, 
+		UINT32 titleWidth, MonoString* style, 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));
+
+		String styleName = toString(MonoUtil::monoToWString(style));
+
+		UINT32 elementsArrayLen = (UINT32)mono_array_length(elements);
+		Vector<HString> nativeElements;
+		for (UINT32 i = 0; i < elementsArrayLen; i++)
+		{
+			MonoObject* stringManaged = (MonoObject*)mono_array_get(elements, MonoObject*, i);
+
+			if (stringManaged == nullptr)
+				nativeElements.push_back(HString::dummy());
+			else
+			{
+				ScriptHString* textScript = ScriptHString::toNative(stringManaged);
+				nativeElements.push_back(textScript->getInternalValue());
+			}
+		}
+
+		GUIListBoxField* guiField = nullptr;
+		if (withTitle)
+		{
+			GUIContent nativeContent(ScriptGUIContent::getText(title), ScriptGUIContent::getImage(title), ScriptGUIContent::getTooltip(title));
+			guiField = GUIListBoxField::create(nativeElements, nativeContent, titleWidth, options, styleName);
+		}
+		else
+		{
+			guiField = GUIListBoxField::create(nativeElements, options, styleName);
+		}
+
+		guiField->onSelectionChanged.connect(std::bind(&ScriptGUIListBoxField::onSelectionChanged, instance, _1));
+
+		ScriptGUIListBoxField* nativeInstance = new (bs_alloc<ScriptGUIListBoxField>()) ScriptGUIListBoxField(instance, guiField);
+	}
+
+	UINT32 ScriptGUIListBoxField::internal_getValue(ScriptGUIListBoxField* nativeInstance)
+	{
+		GUIListBoxField* field = static_cast<GUIListBoxField*>(nativeInstance->getGUIElement());
+		return field->getIndex();
+	}
+
+	void ScriptGUIListBoxField::internal_setValue(ScriptGUIListBoxField* nativeInstance, UINT32 index)
+	{
+		GUIListBoxField* field = static_cast<GUIListBoxField*>(nativeInstance->getGUIElement());
+		return field->setIndex(index);
+	}
+
+	void ScriptGUIListBoxField::internal_setElements(ScriptGUIListBoxField* nativeInstance, MonoArray* elements)
+	{
+		UINT32 elementsArrayLen = (UINT32)mono_array_length(elements);
+		Vector<HString> nativeElements;
+		for (UINT32 i = 0; i < elementsArrayLen; i++)
+		{
+			MonoObject* stringManaged = (MonoObject*)mono_array_get(elements, MonoObject*, i);
+
+			if (stringManaged == nullptr)
+				nativeElements.push_back(HString::dummy());
+			else
+			{
+				ScriptHString* textScript = ScriptHString::toNative(stringManaged);
+				nativeElements.push_back(textScript->getInternalValue());
+			}
+		}
+
+		GUIListBoxField* field = static_cast<GUIListBoxField*>(nativeInstance->getGUIElement());
+		field->setElements(nativeElements);
+	}
+
+	void ScriptGUIListBoxField::internal_setTint(ScriptGUIListBoxField* nativeInstance, Color color)
+	{
+		GUIListBoxField* field = (GUIListBoxField*)nativeInstance->getGUIElement();
+		field->setTint(color);
+	}
+
+	void ScriptGUIListBoxField::onSelectionChanged(MonoObject* instance, UINT32 newIndex)
+	{
+		MonoUtil::invokeThunk(onSelectionChangedThunk, instance, newIndex);
+	}
+}

+ 1 - 0
TODO.txt

@@ -66,6 +66,7 @@ Other polish:
    - Also create helper objects: Cube, Sphere, Plane, Quad, Capsule, Cylinder
   - Help - About, API Reference (link to site)
  - Add temporary icon textures too all icon buttons currently containing only text so that Ribek can modify them
+  - Also add dummy icons to toolbar (New Project, Open Project, Save Scene, Undo, Redo, Basic shapes, Camera, Renderable, Lights)
  - When I expand inspector elements and them come back to that object it should remember the previous state
    - Add a chaching mechanism to inspector (likely based on instance ID & property names)
    - This has to work not only when I come back to the object, but whenever inspector rebuilds (e.g. after removing element from array)