BearishSun 10 лет назад
Родитель
Сommit
28390eb39b

+ 493 - 493
BansheeEditor/Include/BsBuiltinEditorResources.h

@@ -1,494 +1,494 @@
-#pragma once
-
-#include "BsEditorPrerequisites.h"
-#include "BsGUISkin.h"
-#include "BsModule.h"
-#include "BsGUIContent.h"
-#include "BsApplication.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Types of valid icons used when viewing the project library.
-	 */
-	enum class ProjectIcon
-	{
-		Folder, Mesh, Font, Texture, PlainText, ScriptCode, SpriteTexture, Shader, ShaderInclude, Material, Prefab, GUISkin
-	};
-
-	/**
-	 * @brief	Types of icons that may be displayed on the tool bar.
-	 */
-	enum class ToolbarIcon
-	{
-		NewCamera, NewRenderable, NewPointLight, NewDirLight, NewSpotLight, NewSceneObject, NewCube, NewSphere, NewCone, 
-		NewQuad, NewMat, NewCSScript, NewShader, NewSpriteTex, Pause, Play, Step, Undo, Redo, OpenProject, SaveProject, 
-		SaveScene
-	};
-
-	/**
-	 * @brief	Types of icons that may be displayed in the scene window.
-	 */
-	enum class SceneWindowIcon
-	{
-		View, Move, Rotate, Scale, Pivot, Center, Local, World, MoveSnap, RotateSnap
-	};
-
-	/**
-	 * @brief	Types of icons that may be displayed in the inspector window.
-	 */
-	enum class InspectorWindowIcon
-	{
-		Create, Clone, Clear, Resize, Delete, MoveUp, MoveDown, Edit, Apply, Add, Cancel
-	};
-
-	/**
-	 * @brief	Types of icons that may be displayed in the library window.
-	 */
-	enum class LibraryWindowIcon
-	{
-		Home, Up, Clear, Options
-	};
-
-	/**
-	 * @brief	Types of icons used in various areas throughout the editor.
-	 */
-	enum class EditorIcon
-	{
-		XBtn
-	};
-
-	/**
-	 * @brief	Types of icons to be used along with log messages depending on their severity.
-	 */
-	enum class LogMessageIcon
-	{
-		Info, Warning, Error
-	};
-
-	/**
-	 * @brief	Contains a set of built-in resources used by the editor.
-	 */
-	class BS_ED_EXPORT BuiltinEditorResources : public BansheeEngine::Module<BuiltinEditorResources>
-	{
-	public:
-		BuiltinEditorResources();
-		~BuiltinEditorResources();
-
-		/**
-		 * @brief	Returns the default editor GUI skin.
-		 */
-		const HGUISkin& getSkin() const { return mSkin; }
-
-		/**
-		 * @brief	Creates a material used for docking drop overlay used by the editor.
-		 */
-		HMaterial createDockDropOverlayMaterial() const;
-
-		/**
-		 * @brief	Creates a material used for rendering the scene grid.
-		 */
-		HMaterial createSceneGridMaterial() const;
-
-		/**
-		 * @brief	Creates a material used for picking non-transparent objects in scene view.
-		 */
-		HMaterial createPicking(CullingMode cullMode) const;
-
-		/**
-		 * @brief	Creates a material used for picking transparent objects in scene view.
-		 */
-		HMaterial createPickingAlpha(CullingMode cullMode) const;
-
-		/**
-		 * @brief	Creates a material used for rendering wireframe gizmos.
-		 */
-		HMaterial createWireGizmoMat() const;
-
-		/**
-		 * @brief	Creates a material used for rendering solid gizmos.
-		 */
-		HMaterial createSolidGizmoMat() const;
-
-		/**
-		 * @brief	Creates a material used for rendering icon gizmos.
-		 */
-		HMaterial createIconGizmoMat() const;
-
-		/**
-		 * @brief	Creates a material used for picking non-transparent gizmos.
-		 */
-		HMaterial createGizmoPickingMat() const;
-
-		/**
-		 * @brief	Creates a material used for picking transparent gizmos.
-		 */
-		HMaterial createAlphaGizmoPickingMat() const;
-
-		/**
-		 * @brief	Creates a material used for rendering wireframe handles.
-		 */
-		HMaterial createWireHandleMat() const;
-
-		/**
-		 * @brief	Creates a material used for rendering solid handles.
-		 */
-		HMaterial createSolidHandleMat() const;
-
-		/**
-		 * @brief	Creates a material used for displaying selected objects.
-		 */
-		HMaterial createSelectionMat() const;
-
-		/**
-		 * @brief	Retrieves an icon that represents a specific resource type
-		 *			that may be displayed when viewing the project library.
-		 */
-		HSpriteTexture getLibraryIcon(ProjectIcon icon, int size) const;
-
-		/**
-		 * @brief	Retrieves an icon that may be displayed on the main window's toolbar.
-		 */
-		HSpriteTexture getToolbarIcon(ToolbarIcon icon) const;
-
-		/**
-		 * @brief	Retrieves an icon that may be displayed on the scene window.
-		 */
-		GUIContentImages getSceneWindowIcon(SceneWindowIcon icon) const;
-
-		/**
-		 * @brief	Retrieves an icon that may be displayed on the library window.
-		 */
-		HSpriteTexture getLibraryWindowIcon(LibraryWindowIcon icon) const;
-
-		/**
-		 * @brief	Retrieves an icon that may be displayed on the inspector window.
-		 */
-		HSpriteTexture getInspectorWindowIcon(InspectorWindowIcon icon) const;
-
-		/**
-		 * @brief	Retrieves an icon that represents a specific generic editor icon.
-		 */
-		HSpriteTexture getIcon(EditorIcon icon) const;
-
-		/**
-		 * @brief	Retrieves an icon that represents a specific log message type.
-		 */
-		HSpriteTexture getLogMessageIcon(LogMessageIcon icon, UINT32 size, bool dark) const;
-
-		/**
-		 * @brief	Returns text contained in the default "empty" shader.
-		 */
-		WString getEmptyShaderCode() const;
-
-		/**
-		 * @brief	Returns text contained in the default "empty" C# script.
-		 */
-		WString getEmptyCSScriptCode() const;
-
-		/**
-		 * @brief	Returns path to the builtin shader include folder, relative to the working directory.
-		 */
-		static Path getShaderIncludeFolder();
-
-		/**
-		 * @brief	Returns path to the default widget layout file, relative to the working directory.
-		 */
-		static Path getDefaultWidgetLayoutPath();
-
-		static const String ObjectFieldStyleName;
-		static const String ObjectFieldLabelStyleName;
-		static const String ObjectFieldDropBtnStyleName;
-		static const String ObjectFieldClearBtnStyleName;
-
-		static const String TextureFieldStyleName;
-		static const String TextureFieldLabelStyleName;
-		static const String TextureFieldDropStyleName;
-		static const String TextureFieldClearBtnStyleName;
-
-	private:
-		/**
-		 * @brief	Imports all necessary resources and converts them to engine-ready format.
-		 *
-		 * @note	Normally you only want to use this during development phase and then ship
-		 *			with engine-ready format only.
-		 */
-		void preprocess();
-
-		/**
-		 * @brief	Generates the default editor skin and all GUI element styles.
-		 */
-		GUISkinPtr generateGUISkin();
-
-		/**
-		 * @brief	Generates different sizes of resource icons. Expects maximum sizes of the icons to already be present.
-		 * 			Resulting textures will be saved to the same directory the maximum size textures are in.
-		 */
-		void generateResourceIcons(const Path& inputFolder, const ResourceManifestPtr& resourceManifest);
-
-		/**
-		 * @brief	Loads a GUI skin texture with the specified filename.
-		 */
-		HSpriteTexture getGUITexture(const WString& name) const;
-
-		/**
-		 * @brief	Loads a GUI icon with the specified filename.
-		 */
-		HSpriteTexture getGUIIcon(const WString& name) const;
-
-		/**
-		 * @brief	Loads a shader with the specified filename
-		 */
-		HShader getShader(const WString& name) const;
-
-		HShader mShaderDockOverlay;
-		HShader mShaderSceneGrid;
-		HShader mShaderPicking[3];
-		HShader mShaderPickingAlpha[3];
-		HShader mShaderGizmoSolid;
-		HShader mShaderGizmoWire;
-		HShader mShaderGizmoIcon;
-		HShader mShaderGizmoPicking;
-		HShader mShaderGizmoAlphaPicking;
-		HShader mShaderHandleSolid;
-		HShader mShaderHandleWire;
-		HShader mShaderSelection;
-
-		HGUISkin mSkin;
-
-		ResourceManifestPtr mResourceManifest;
-
-		static const char* ShaderFolder;
-		static const char* SkinFolder;
-		static const char* IconFolder;
-		static const char* ShaderIncludeFolder;
-
-		Path BuiltinDataFolder;
-		Path EditorSkinFolder;
-		Path EditorIconFolder;
-		Path EditorShaderFolder;
-		Path EditorShaderIncludeFolder;
-
-		Path BuiltinRawDataFolder;
-		Path EditorRawSkinFolder;
-		Path EditorRawShaderIncludeFolder;
-		Path EditorRawShaderFolder;
-
-		Path ResourceManifestPath;
-
-		static const WString DefaultFontFilename;
-		static const WString DefaultAAFontFilename;
-		static const UINT32 DefaultFontSize;
-		static const UINT32 TitleFontSize;
-
-		static const Color TextNormalColor;
-		static const Color TextActiveColor;
-
-		static const WString GUISkinFile;
-
-		static const WString FolderIconTex;
-		static const WString MeshIconTex;
-		static const WString TextureIconTex;
-		static const WString FontIconTex;
-		static const WString PlainTextIconTex;
-		static const WString ScriptCodeIconTex;
-		static const WString ShaderIconTex;
-		static const WString ShaderIncludeIconTex;
-		static const WString MaterialIconTex;
-		static const WString SpriteTextureIconTex;
-		static const WString PrefabIconTex;
-		static const WString GUISkinIconTex;
-
-		static const WString WindowBackgroundTex;
-
-		static const WString WindowFrameNormal;
-		static const WString WindowFrameFocused;
-
-		static const WString TabBarBackgroundTex;
-		static const WString TitleBarBackgroundTex;
-
-		static const WString CloseButtonNormalTex;
-		static const WString CloseButtonHoverTex;
-		static const WString CloseButtonActiveTex;
-
-		static const WString MinButtonNormalTex;
-		static const WString MinButtonHoverTex;
-		static const WString MinButtonActiveTex;
-
-		static const WString MaxButtonNormalTex;
-		static const WString MaxButtonHoverTex;
-		static const WString MaxButtonActiveTex;
-
-		static const WString TabButtonNormalTex;
-		static const WString TabButtonFocusedTex;
-
-		static const WString ButtonNormalTex;
-		static const WString ButtonHoverTex;
-		static const WString ButtonActiveTex;
-
-		static const WString ButtonLeftNormalTex;
-		static const WString ButtonLeftHoverTex;
-		static const WString ButtonLeftActiveTex;
-
-		static const WString ButtonRightNormalTex;
-		static const WString ButtonRightHoverTex;
-		static const WString ButtonRightActiveTex;
-
-		static const WString ToggleNormalTex;
-		static const WString ToggleHoverTex;
-		static const WString ToggleNormalOnTex;
-		static const WString ToggleHoverOnTex;
-
-		static const WString ObjectDropBtnNormalTex;
-		static const WString ObjectDropBtnNormalOnTex;
-		static const WString ObjectClearBtnNormalTex;
-		static const WString ObjectClearBtnHoverTex;
-		static const WString ObjectClearBtnActiveTex;
-
-		static const WString SliderHBackgroundTex;
-		static const WString SliderHFillTex;
-		static const WString SliderVBackgroundTex;
-		static const WString SliderVFillTex;
-		static const WString SliderHandleNormalTex;
-		static const WString SliderHandleHoverTex;
-		static const WString SliderHandleActiveTex;
-
-		static const WString FoldoutOpenNormalTex;
-		static const WString FoldoutOpenHoverTex;
-		static const WString FoldoutOpenActiveTex;
-		static const WString FoldoutClosedNormalTex;
-		static const WString FoldoutClosedHoverTex;
-		static const WString FoldoutClosedActiveTex;
-
-		static const WString InputBoxNormalTex;
-		static const WString InputBoxHoverTex;
-		static const WString InputBoxFocusedTex;
-
-		static const WString ScrollBarUpNormalTex;
-		static const WString ScrollBarUpHoverTex;
-		static const WString ScrollBarUpActiveTex;
-
-		static const WString ScrollBarDownNormalTex;
-		static const WString ScrollBarDownHoverTex;
-		static const WString ScrollBarDownActiveTex;
-
-		static const WString ScrollBarLeftNormalTex;
-		static const WString ScrollBarLeftHoverTex;
-		static const WString ScrollBarLeftActiveTex;
-
-		static const WString ScrollBarRightNormalTex;
-		static const WString ScrollBarRightHoverTex;
-		static const WString ScrollBarRightActiveTex;
-
-		static const WString ScrollBarHandleHorzNormalTex;
-		static const WString ScrollBarHandleHorzHoverTex;
-		static const WString ScrollBarHandleHorzActiveTex;
-
-		static const WString ScrollBarHandleVertNormalTex;
-		static const WString ScrollBarHandleVertHoverTex;
-		static const WString ScrollBarHandleVertActiveTex;
-
-		static const WString ScrollBarHBgTex;
-		static const WString ScrollBarVBgTex;
-
-		static const WString DropDownBtnNormalTex;
-		static const WString DropDownBtnHoverTex;
-		static const WString DropDownBtnActiveTex;
-
-		static const WString DropDownBoxBgTex;
-		static const WString DropDownBoxSideBgTex;
-		static const WString DropDownBoxHandleTex;
-
-		static const WString DropDownBoxEntryNormalTex;
-		static const WString DropDownBoxEntryHoverTex;
-
-		static const WString DropDownBoxEntryToggleNormalTex;
-		static const WString DropDownBoxEntryToggleHoverTex;
-		static const WString DropDownBoxEntryToggleNormalOnTex;
-		static const WString DropDownBoxEntryToggleHoverOnTex;
-
-		static const WString DropDownBoxBtnUpNormalTex;
-		static const WString DropDownBoxBtnUpHoverTex;
-
-		static const WString DropDownBoxBtnDownNormalTex;
-		static const WString DropDownBoxBtnDownHoverTex;
-
-		static const WString DropDownBoxEntryExpNormalTex;
-		static const WString DropDownBoxEntryExpHoverTex;
-
-		static const WString DropDownSeparatorTex;
-
-		static const WString MenuBarBgTex;
-		static const WString MenuBarBansheeLogoTex;
-
-		static const WString MenuBarBtnNormalTex;
-		static const WString MenuBarBtnHoverTex;
-		static const WString MenuBarBtnActiveTex;
-
-		static const WString MenuBarLineNormalTex;
-		static const WString MenuBarLineActiveTex;
-
-		static const WString ToolBarBtnNormalTex;
-		static const WString ToolBarBtnHoverTex;
-		static const WString ToolBarBtnActiveTex;
-
-		static const WString ToolBarSeparatorTex;
-
-		static const WString DockSliderNormalTex;
-
-		static const WString TreeViewExpandButtonOffNormal;
-		static const WString TreeViewExpandButtonOffHover;
-		static const WString TreeViewExpandButtonOnNormal;
-		static const WString TreeViewExpandButtonOnHover;
-
-		static const WString TreeViewHighlightBackground;
-		static const WString TreeViewEditBox;
-
-		static const WString TreeViewElementHighlight;
-		static const WString TreeViewElementSepHighlight;
-
-		static const WString ColorPickerSliderHorzHandleTex;
-		static const WString ColorPickerSliderVertHandleTex;
-		static const WString ColorPickerSlider2DHandleTex;
-
-		static const WString ProgressBarFillTex;
-		static const WString ProgressBarBgTex;
-
-		static const WString SelectionAreaTex;
-		static const WString SelectionBgTex;
-
-		static const WString TextureDropTex;
-		static const WString TextureDropOnTex;
-
-		static const WString XButtonNormalTex;
-		static const WString XButtonHoverTex;
-		static const WString XButtonActiveTex;
-
-		static const WString StatusBarBgTex;
-		static const WString ScrollAreaBgTex;
-
-		static const WString InspectorTitleBgTex;
-		static const WString InspectorContentBgTex;
-		static const WString InspectorContentBgAlternateTex;
-
-		static const WString ShaderDockOverlayFile;
-		static const WString ShaderSceneGridFile;
-		static const WString ShaderPickingCullNoneFile;
-		static const WString ShaderPickingCullCWFile;
-		static const WString ShaderPickingCullCCWFile;
-		static const WString ShaderPickingAlphaCullNoneFile;
-		static const WString ShaderPickingAlphaCullCWFile;
-		static const WString ShaderPickingAlphaCullCCWFile;
-		static const WString ShaderWireGizmoFile;
-		static const WString ShaderSolidGizmoFile;
-		static const WString ShaderWireHandleFile;
-		static const WString ShaderSolidHandleFile;
-		static const WString ShaderIconGizmoFile;
-		static const WString ShaderGizmoPickingFile;
-		static const WString ShaderGizmoPickingAlphaFile;
-		static const WString ShaderSelectionFile;
-
-		static const WString EmptyShaderCodeFile;
-		static const WString EmptyCSScriptCodeFile;
-	};
+#pragma once
+
+#include "BsEditorPrerequisites.h"
+#include "BsGUISkin.h"
+#include "BsModule.h"
+#include "BsGUIContent.h"
+#include "BsApplication.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Types of valid icons used when viewing the project library.
+	 */
+	enum class ProjectIcon
+	{
+		Folder, Mesh, Font, Texture, PlainText, ScriptCode, SpriteTexture, Shader, ShaderInclude, Material, Prefab, GUISkin
+	};
+
+	/**
+	 * @brief	Types of icons that may be displayed on the tool bar.
+	 */
+	enum class ToolbarIcon
+	{
+		NewCamera, NewRenderable, NewPointLight, NewDirLight, NewSpotLight, NewSceneObject, NewCube, NewSphere, NewCone, 
+		NewQuad, NewMat, NewCSScript, NewShader, NewSpriteTex, Pause, Play, Step, Undo, Redo, OpenProject, SaveProject, 
+		SaveScene
+	};
+
+	/**
+	 * @brief	Types of icons that may be displayed in the scene window.
+	 */
+	enum class SceneWindowIcon
+	{
+		View, Move, Rotate, Scale, Pivot, Center, Local, World, MoveSnap, RotateSnap
+	};
+
+	/**
+	 * @brief	Types of icons that may be displayed in the inspector window.
+	 */
+	enum class InspectorWindowIcon
+	{
+		Create, Clone, Clear, Resize, Delete, MoveUp, MoveDown, Edit, Apply, Add, Cancel
+	};
+
+	/**
+	 * @brief	Types of icons that may be displayed in the library window.
+	 */
+	enum class LibraryWindowIcon
+	{
+		Home, Up, Clear, Options
+	};
+
+	/**
+	 * @brief	Types of icons used in various areas throughout the editor.
+	 */
+	enum class EditorIcon
+	{
+		XBtn
+	};
+
+	/**
+	 * @brief	Types of icons to be used along with log messages depending on their severity.
+	 */
+	enum class LogMessageIcon
+	{
+		Info, Warning, Error
+	};
+
+	/**
+	 * @brief	Contains a set of built-in resources used by the editor.
+	 */
+	class BS_ED_EXPORT BuiltinEditorResources : public BansheeEngine::Module<BuiltinEditorResources>
+	{
+	public:
+		BuiltinEditorResources();
+		~BuiltinEditorResources();
+
+		/**
+		 * @brief	Returns the default editor GUI skin.
+		 */
+		const HGUISkin& getSkin() const { return mSkin; }
+
+		/**
+		 * @brief	Creates a material used for docking drop overlay used by the editor.
+		 */
+		HMaterial createDockDropOverlayMaterial() const;
+
+		/**
+		 * @brief	Creates a material used for rendering the scene grid.
+		 */
+		HMaterial createSceneGridMaterial() const;
+
+		/**
+		 * @brief	Creates a material used for picking non-transparent objects in scene view.
+		 */
+		HMaterial createPicking(CullingMode cullMode) const;
+
+		/**
+		 * @brief	Creates a material used for picking transparent objects in scene view.
+		 */
+		HMaterial createPickingAlpha(CullingMode cullMode) const;
+
+		/**
+		 * @brief	Creates a material used for rendering wireframe gizmos.
+		 */
+		HMaterial createWireGizmoMat() const;
+
+		/**
+		 * @brief	Creates a material used for rendering solid gizmos.
+		 */
+		HMaterial createSolidGizmoMat() const;
+
+		/**
+		 * @brief	Creates a material used for rendering icon gizmos.
+		 */
+		HMaterial createIconGizmoMat() const;
+
+		/**
+		 * @brief	Creates a material used for picking non-transparent gizmos.
+		 */
+		HMaterial createGizmoPickingMat() const;
+
+		/**
+		 * @brief	Creates a material used for picking transparent gizmos.
+		 */
+		HMaterial createAlphaGizmoPickingMat() const;
+
+		/**
+		 * @brief	Creates a material used for rendering wireframe handles.
+		 */
+		HMaterial createWireHandleMat() const;
+
+		/**
+		 * @brief	Creates a material used for rendering solid handles.
+		 */
+		HMaterial createSolidHandleMat() const;
+
+		/**
+		 * @brief	Creates a material used for displaying selected objects.
+		 */
+		HMaterial createSelectionMat() const;
+
+		/**
+		 * @brief	Retrieves an icon that represents a specific resource type
+		 *			that may be displayed when viewing the project library.
+		 */
+		HSpriteTexture getLibraryIcon(ProjectIcon icon, int size) const;
+
+		/**
+		 * @brief	Retrieves an icon that may be displayed on the main window's toolbar.
+		 */
+		HSpriteTexture getToolbarIcon(ToolbarIcon icon) const;
+
+		/**
+		 * @brief	Retrieves an icon that may be displayed on the scene window.
+		 */
+		GUIContentImages getSceneWindowIcon(SceneWindowIcon icon) const;
+
+		/**
+		 * @brief	Retrieves an icon that may be displayed on the library window.
+		 */
+		HSpriteTexture getLibraryWindowIcon(LibraryWindowIcon icon) const;
+
+		/**
+		 * @brief	Retrieves an icon that may be displayed on the inspector window.
+		 */
+		HSpriteTexture getInspectorWindowIcon(InspectorWindowIcon icon) const;
+
+		/**
+		 * @brief	Retrieves an icon that represents a specific generic editor icon.
+		 */
+		HSpriteTexture getIcon(EditorIcon icon) const;
+
+		/**
+		 * @brief	Retrieves an icon that represents a specific log message type.
+		 */
+		HSpriteTexture getLogMessageIcon(LogMessageIcon icon, UINT32 size, bool dark) const;
+
+		/**
+		 * @brief	Returns text contained in the default "empty" shader.
+		 */
+		WString getEmptyShaderCode() const;
+
+		/**
+		 * @brief	Returns text contained in the default "empty" C# script.
+		 */
+		WString getEmptyCSScriptCode() const;
+
+		/**
+		 * @brief	Returns path to the builtin shader include folder, relative to the working directory.
+		 */
+		static Path getShaderIncludeFolder();
+
+		/**
+		 * @brief	Returns path to the default widget layout file, relative to the working directory.
+		 */
+		static Path getDefaultWidgetLayoutPath();
+
+		static const String ObjectFieldStyleName;
+		static const String ObjectFieldLabelStyleName;
+		static const String ObjectFieldDropBtnStyleName;
+		static const String ObjectFieldClearBtnStyleName;
+
+		static const String TextureFieldStyleName;
+		static const String TextureFieldLabelStyleName;
+		static const String TextureFieldDropStyleName;
+		static const String TextureFieldClearBtnStyleName;
+
+	private:
+		/**
+		 * @brief	Imports all necessary resources and converts them to engine-ready format.
+		 *
+		 * @note	Normally you only want to use this during development phase and then ship
+		 *			with engine-ready format only.
+		 */
+		void preprocess();
+
+		/**
+		 * @brief	Generates the default editor skin and all GUI element styles.
+		 */
+		GUISkinPtr generateGUISkin();
+
+		/**
+		 * @brief	Generates different sizes of resource icons. Expects maximum sizes of the icons to already be present.
+		 * 			Resulting textures will be saved to the same directory the maximum size textures are in.
+		 */
+		void generateResourceIcons(const Path& inputFolder, const ResourceManifestPtr& resourceManifest);
+
+		/**
+		 * @brief	Loads a GUI skin texture with the specified filename.
+		 */
+		HSpriteTexture getGUITexture(const WString& name) const;
+
+		/**
+		 * @brief	Loads a GUI icon with the specified filename.
+		 */
+		HSpriteTexture getGUIIcon(const WString& name) const;
+
+		/**
+		 * @brief	Loads a shader with the specified filename
+		 */
+		HShader getShader(const WString& name) const;
+
+		HShader mShaderDockOverlay;
+		HShader mShaderSceneGrid;
+		HShader mShaderPicking[3];
+		HShader mShaderPickingAlpha[3];
+		HShader mShaderGizmoSolid;
+		HShader mShaderGizmoWire;
+		HShader mShaderGizmoIcon;
+		HShader mShaderGizmoPicking;
+		HShader mShaderGizmoAlphaPicking;
+		HShader mShaderHandleSolid;
+		HShader mShaderHandleWire;
+		HShader mShaderSelection;
+
+		HGUISkin mSkin;
+
+		ResourceManifestPtr mResourceManifest;
+
+		static const char* ShaderFolder;
+		static const char* SkinFolder;
+		static const char* IconFolder;
+		static const char* ShaderIncludeFolder;
+
+		Path BuiltinDataFolder;
+		Path EditorSkinFolder;
+		Path EditorIconFolder;
+		Path EditorShaderFolder;
+		Path EditorShaderIncludeFolder;
+
+		Path BuiltinRawDataFolder;
+		Path EditorRawSkinFolder;
+		Path EditorRawShaderIncludeFolder;
+		Path EditorRawShaderFolder;
+
+		Path ResourceManifestPath;
+
+		static const WString DefaultFontFilename;
+		static const WString DefaultAAFontFilename;
+		static const UINT32 DefaultFontSize;
+		static const UINT32 TitleFontSize;
+
+		static const Color TextNormalColor;
+		static const Color TextActiveColor;
+
+		static const WString GUISkinFile;
+
+		static const WString FolderIconTex;
+		static const WString MeshIconTex;
+		static const WString TextureIconTex;
+		static const WString FontIconTex;
+		static const WString PlainTextIconTex;
+		static const WString ScriptCodeIconTex;
+		static const WString ShaderIconTex;
+		static const WString ShaderIncludeIconTex;
+		static const WString MaterialIconTex;
+		static const WString SpriteTextureIconTex;
+		static const WString PrefabIconTex;
+		static const WString GUISkinIconTex;
+
+		static const WString WindowBackgroundTex;
+
+		static const WString WindowFrameNormal;
+		static const WString WindowFrameFocused;
+
+		static const WString TabBarBackgroundTex;
+		static const WString TitleBarBackgroundTex;
+
+		static const WString CloseButtonNormalTex;
+		static const WString CloseButtonHoverTex;
+		static const WString CloseButtonActiveTex;
+
+		static const WString MinButtonNormalTex;
+		static const WString MinButtonHoverTex;
+		static const WString MinButtonActiveTex;
+
+		static const WString MaxButtonNormalTex;
+		static const WString MaxButtonHoverTex;
+		static const WString MaxButtonActiveTex;
+
+		static const WString TabButtonNormalTex;
+		static const WString TabButtonFocusedTex;
+
+		static const WString ButtonNormalTex;
+		static const WString ButtonHoverTex;
+		static const WString ButtonActiveTex;
+
+		static const WString ButtonLeftNormalTex;
+		static const WString ButtonLeftHoverTex;
+		static const WString ButtonLeftActiveTex;
+
+		static const WString ButtonRightNormalTex;
+		static const WString ButtonRightHoverTex;
+		static const WString ButtonRightActiveTex;
+
+		static const WString ToggleNormalTex;
+		static const WString ToggleHoverTex;
+		static const WString ToggleNormalOnTex;
+		static const WString ToggleHoverOnTex;
+
+		static const WString ObjectDropBtnNormalTex;
+		static const WString ObjectDropBtnNormalOnTex;
+		static const WString ObjectClearBtnNormalTex;
+		static const WString ObjectClearBtnHoverTex;
+		static const WString ObjectClearBtnActiveTex;
+
+		static const WString SliderHBackgroundTex;
+		static const WString SliderHFillTex;
+		static const WString SliderVBackgroundTex;
+		static const WString SliderVFillTex;
+		static const WString SliderHandleNormalTex;
+		static const WString SliderHandleHoverTex;
+		static const WString SliderHandleActiveTex;
+
+		static const WString FoldoutOpenNormalTex;
+		static const WString FoldoutOpenHoverTex;
+		static const WString FoldoutOpenActiveTex;
+		static const WString FoldoutClosedNormalTex;
+		static const WString FoldoutClosedHoverTex;
+		static const WString FoldoutClosedActiveTex;
+
+		static const WString InputBoxNormalTex;
+		static const WString InputBoxHoverTex;
+		static const WString InputBoxFocusedTex;
+
+		static const WString ScrollBarUpNormalTex;
+		static const WString ScrollBarUpHoverTex;
+		static const WString ScrollBarUpActiveTex;
+
+		static const WString ScrollBarDownNormalTex;
+		static const WString ScrollBarDownHoverTex;
+		static const WString ScrollBarDownActiveTex;
+
+		static const WString ScrollBarLeftNormalTex;
+		static const WString ScrollBarLeftHoverTex;
+		static const WString ScrollBarLeftActiveTex;
+
+		static const WString ScrollBarRightNormalTex;
+		static const WString ScrollBarRightHoverTex;
+		static const WString ScrollBarRightActiveTex;
+
+		static const WString ScrollBarHandleHorzNormalTex;
+		static const WString ScrollBarHandleHorzHoverTex;
+		static const WString ScrollBarHandleHorzActiveTex;
+
+		static const WString ScrollBarHandleVertNormalTex;
+		static const WString ScrollBarHandleVertHoverTex;
+		static const WString ScrollBarHandleVertActiveTex;
+
+		static const WString ScrollBarHBgTex;
+		static const WString ScrollBarVBgTex;
+
+		static const WString DropDownBtnNormalTex;
+		static const WString DropDownBtnHoverTex;
+		static const WString DropDownBtnActiveTex;
+
+		static const WString DropDownBoxBgTex;
+		static const WString DropDownBoxSideBgTex;
+		static const WString DropDownBoxHandleTex;
+
+		static const WString DropDownBoxEntryNormalTex;
+		static const WString DropDownBoxEntryHoverTex;
+
+		static const WString DropDownBoxEntryToggleNormalTex;
+		static const WString DropDownBoxEntryToggleHoverTex;
+		static const WString DropDownBoxEntryToggleNormalOnTex;
+		static const WString DropDownBoxEntryToggleHoverOnTex;
+
+		static const WString DropDownBoxBtnUpNormalTex;
+		static const WString DropDownBoxBtnUpHoverTex;
+
+		static const WString DropDownBoxBtnDownNormalTex;
+		static const WString DropDownBoxBtnDownHoverTex;
+
+		static const WString DropDownBoxEntryExpNormalTex;
+		static const WString DropDownBoxEntryExpHoverTex;
+
+		static const WString DropDownSeparatorTex;
+
+		static const WString MenuBarBgTex;
+		static const WString MenuBarBansheeLogoTex;
+
+		static const WString MenuBarBtnNormalTex;
+		static const WString MenuBarBtnHoverTex;
+		static const WString MenuBarBtnActiveTex;
+
+		static const WString MenuBarLineNormalTex;
+		static const WString MenuBarLineActiveTex;
+
+		static const WString ToolBarBtnNormalTex;
+		static const WString ToolBarBtnHoverTex;
+		static const WString ToolBarBtnActiveTex;
+
+		static const WString ToolBarSeparatorTex;
+
+		static const WString DockSliderNormalTex;
+
+		static const WString TreeViewExpandButtonOffNormal;
+		static const WString TreeViewExpandButtonOffHover;
+		static const WString TreeViewExpandButtonOnNormal;
+		static const WString TreeViewExpandButtonOnHover;
+
+		static const WString TreeViewHighlightBackground;
+		static const WString TreeViewEditBox;
+
+		static const WString TreeViewElementHighlight;
+		static const WString TreeViewElementSepHighlight;
+
+		static const WString ColorPickerSliderHorzHandleTex;
+		static const WString ColorPickerSliderVertHandleTex;
+		static const WString ColorPickerSlider2DHandleTex;
+
+		static const WString ProgressBarFillTex;
+		static const WString ProgressBarBgTex;
+
+		static const WString SelectionAreaTex;
+		static const WString SelectionBgTex;
+
+		static const WString TextureDropTex;
+		static const WString TextureDropOnTex;
+
+		static const WString XButtonNormalTex;
+		static const WString XButtonHoverTex;
+		static const WString XButtonActiveTex;
+
+		static const WString StatusBarBgTex;
+		static const WString ScrollAreaBgTex;
+
+		static const WString InspectorTitleBgTex;
+		static const WString InspectorContentBgTex;
+		static const WString InspectorContentBgAlternateTex;
+
+		static const WString ShaderDockOverlayFile;
+		static const WString ShaderSceneGridFile;
+		static const WString ShaderPickingCullNoneFile;
+		static const WString ShaderPickingCullCWFile;
+		static const WString ShaderPickingCullCCWFile;
+		static const WString ShaderPickingAlphaCullNoneFile;
+		static const WString ShaderPickingAlphaCullCWFile;
+		static const WString ShaderPickingAlphaCullCCWFile;
+		static const WString ShaderWireGizmoFile;
+		static const WString ShaderSolidGizmoFile;
+		static const WString ShaderWireHandleFile;
+		static const WString ShaderSolidHandleFile;
+		static const WString ShaderIconGizmoFile;
+		static const WString ShaderGizmoPickingFile;
+		static const WString ShaderGizmoPickingAlphaFile;
+		static const WString ShaderSelectionFile;
+
+		static const WString EmptyShaderCodeFile;
+		static const WString EmptyCSScriptCodeFile;
+	};
 }

+ 2291 - 2269
BansheeEditor/Source/BsBuiltinEditorResources.cpp

@@ -1,2270 +1,2292 @@
-#include "BsBuiltinEditorResources.h"
-#include "BsBuiltinResources.h"
-#include "BsGUIElementStyle.h"
-
-#include "BsGUILabel.h"
-#include "BsGUITexture.h"
-#include "BsGUIButton.h"
-#include "BsGUIInputBox.h"
-#include "BsGUIToggle.h"
-#include "BsGUIColor.h"
-#include "BsTextSprite.h"
-#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 "BsGUIListBoxField.h"
-#include "BsGUISliderField.h"
-#include "BsGUIProgressBar.h"
-#include "BsGUISlider.h"
-#include "BsGUIDropDownContent.h"
-#include "BsGUIStatusBar.h"
-#include "BsGUIMenuBar.h"
-#include "BsGUIListBox.h"
-#include "BsCoreThread.h"
-
-#include "BsFont.h"
-#include "BsFontImportOptions.h"
-#include "BsImporter.h"
-#include "BsGpuProgram.h"
-#include "BsShader.h"
-#include "BsShaderInclude.h"
-#include "BsTechnique.h"
-#include "BsPass.h"
-#include "BsMaterial.h"
-#include "BsBlendState.h"
-#include "BsDepthStencilState.h"
-#include "BsRasterizerState.h"
-#include "BsResources.h"
-#include "BsRTTIType.h"
-#include "BsFileSystem.h"
-#include "BsResourceManifest.h"
-#include "BsDataStream.h"
-
-namespace BansheeEngine
-{
-	static const Path EDITOR_DATA_FOLDER = "Editor\\";
-
-	const String BuiltinEditorResources::ObjectFieldStyleName = "GUIObjectField";
-	const String BuiltinEditorResources::ObjectFieldLabelStyleName = "EditorFieldLabel";
-	const String BuiltinEditorResources::ObjectFieldDropBtnStyleName = "DropButton";
-	const String BuiltinEditorResources::ObjectFieldClearBtnStyleName = "ObjectClearButton";
-
-	const String BuiltinEditorResources::TextureFieldStyleName = "GUITextureField";
-	const String BuiltinEditorResources::TextureFieldLabelStyleName = "TextureFieldLabel";
-	const String BuiltinEditorResources::TextureFieldDropStyleName = "TextureDrop";
-	const String BuiltinEditorResources::TextureFieldClearBtnStyleName = "TextureClearButton";
-
-	const WString BuiltinEditorResources::DefaultFontFilename = L"arial.ttf";
-	const WString BuiltinEditorResources::DefaultAAFontFilename = L"arialAA.ttf";
-	const UINT32 BuiltinEditorResources::DefaultFontSize = 8;
-	const UINT32 BuiltinEditorResources::TitleFontSize = 16;
-
-	const Color BuiltinEditorResources::TextNormalColor = Color(0.7f, 0.7f, 0.7f);
-	const Color BuiltinEditorResources::TextActiveColor = Color(0.0f, 0.0f, 0.0f);
-
-	const WString BuiltinEditorResources::GUISkinFile = L"GUISkin";
-
-	const char* BuiltinEditorResources::ShaderFolder = "Shaders\\";
-	const char* BuiltinEditorResources::SkinFolder = "Skin\\";
-	const char* BuiltinEditorResources::IconFolder = "Skin\\Icons";
-	const char* BuiltinEditorResources::ShaderIncludeFolder = "Includes\\";
-
-	const WString BuiltinEditorResources::FolderIconTex = L"FolderIcon.psd";
-	const WString BuiltinEditorResources::MeshIconTex = L"MeshIcon.psd";
-	const WString BuiltinEditorResources::TextureIconTex = L"TextureIcon.psd";
-	const WString BuiltinEditorResources::FontIconTex = L"FontIcon.psd";
-	const WString BuiltinEditorResources::PlainTextIconTex = L"TextIcon.psd";
-	const WString BuiltinEditorResources::ScriptCodeIconTex = L"CSharpIcon.psd";
-	const WString BuiltinEditorResources::ShaderIconTex = L"ShaderIcon.psd";
-	const WString BuiltinEditorResources::ShaderIncludeIconTex = L"ShaderIncludeIcon.psd";
-	const WString BuiltinEditorResources::MaterialIconTex = L"MaterialIcon.psd";
-	const WString BuiltinEditorResources::SpriteTextureIconTex = L"SpriteIcon.psd";
-	const WString BuiltinEditorResources::PrefabIconTex = L"PrefabIcon.psd";
-	const WString BuiltinEditorResources::GUISkinIconTex = L"GUISkinIcon.psd";
-
-	const WString BuiltinEditorResources::ButtonNormalTex = L"ButtonNormal.png";
-	const WString BuiltinEditorResources::ButtonHoverTex = L"ButtonHover.png";
-	const WString BuiltinEditorResources::ButtonActiveTex = L"ButtonActive.png";
-
-	const WString BuiltinEditorResources::ButtonLeftNormalTex = L"ButtonLeftNormal.png";
-	const WString BuiltinEditorResources::ButtonLeftHoverTex = L"ButtonLeftHover.png";
-	const WString BuiltinEditorResources::ButtonLeftActiveTex = L"ButtonLeftActive.png";
-
-	const WString BuiltinEditorResources::ButtonRightNormalTex = L"ButtonRightNormal.png";
-	const WString BuiltinEditorResources::ButtonRightHoverTex = L"ButtonRightHover.png";
-	const WString BuiltinEditorResources::ButtonRightActiveTex = L"ButtonRightActive.png";
-
-	const WString BuiltinEditorResources::ToggleNormalTex = L"ToggleNormal.png";
-	const WString BuiltinEditorResources::ToggleHoverTex = L"ToggleHover.png";
-	const WString BuiltinEditorResources::ToggleNormalOnTex = L"ToggleNormalOn.png";
-	const WString BuiltinEditorResources::ToggleHoverOnTex = L"ToggleHoverOn.png";
-
-	const WString BuiltinEditorResources::InputBoxNormalTex = L"InputBoxNormal.png";
-	const WString BuiltinEditorResources::InputBoxHoverTex = L"InputBoxHover.png";
-	const WString BuiltinEditorResources::InputBoxFocusedTex = L"InputBoxActive.png";
-
-	const WString BuiltinEditorResources::ObjectDropBtnNormalTex = L"ObjectDropNormal.png";
-	const WString BuiltinEditorResources::ObjectDropBtnNormalOnTex = L"ObjectDropNormalOn.png";
-	const WString BuiltinEditorResources::ObjectClearBtnNormalTex = L"ObjectDropClearNormal.png";
-	const WString BuiltinEditorResources::ObjectClearBtnHoverTex = L"ObjectDropClearHover.png";
-	const WString BuiltinEditorResources::ObjectClearBtnActiveTex = L"ObjectDropClearActive.png";
-	
-	const WString BuiltinEditorResources::DropDownBtnNormalTex = L"DropDownButtonNormal.png";
-	const WString BuiltinEditorResources::DropDownBtnHoverTex = L"DropDownButtonHover.png";
-	const WString BuiltinEditorResources::DropDownBtnActiveTex = L"DropDownButtonActive.png";
-
-	const WString BuiltinEditorResources::SliderHBackgroundTex = L"SliderHBackground.png";
-	const WString BuiltinEditorResources::SliderHFillTex = L"SliderHFill.png";
-	const WString BuiltinEditorResources::SliderVBackgroundTex = L"SliderVBackground.png";
-	const WString BuiltinEditorResources::SliderVFillTex = L"SliderVFill.png";
-	const WString BuiltinEditorResources::SliderHandleNormalTex = L"SliderHandleNormal.png";
-	const WString BuiltinEditorResources::SliderHandleHoverTex = L"SliderHandleHover.png";
-	const WString BuiltinEditorResources::SliderHandleActiveTex = L"SliderHandleActive.png";
-
-	const WString BuiltinEditorResources::FoldoutOpenNormalTex = L"FoldoutNormalOn.png";
-	const WString BuiltinEditorResources::FoldoutOpenHoverTex = L"FoldoutHoverOn.png";
-	const WString BuiltinEditorResources::FoldoutOpenActiveTex = L"FoldoutHoverOn.png";
-	const WString BuiltinEditorResources::FoldoutClosedNormalTex = L"FoldoutNormalOff.png";
-	const WString BuiltinEditorResources::FoldoutClosedHoverTex = L"FoldoutHoverOff.png";
-	const WString BuiltinEditorResources::FoldoutClosedActiveTex = L"FoldoutHoverOff.png";
-
-	const WString BuiltinEditorResources::WindowBackgroundTex = L"WindowBackground.png";
-
-	const WString BuiltinEditorResources::WindowFrameNormal = L"WindowFrameNormal.png";
-	const WString BuiltinEditorResources::WindowFrameFocused = L"WindowFrameFocused.png";
-
-	const WString BuiltinEditorResources::CloseButtonNormalTex = L"CloseButtonNormal.png";
-	const WString BuiltinEditorResources::CloseButtonHoverTex = L"CloseButtonHover.png";
-	const WString BuiltinEditorResources::CloseButtonActiveTex = L"CloseButtonActive.png";
-
-	const WString BuiltinEditorResources::MinButtonNormalTex = L"MinimizeButtonNormal.png"; 
-	const WString BuiltinEditorResources::MinButtonHoverTex = L"MinimizeButtonHover.png"; 
-	const WString BuiltinEditorResources::MinButtonActiveTex = L"MinimizeButtonActive.png";
-
-	const WString BuiltinEditorResources::MaxButtonNormalTex = L"MaximizeButtonNormal.png";
-	const WString BuiltinEditorResources::MaxButtonHoverTex = L"MaximizeButtonHover.png";
-	const WString BuiltinEditorResources::MaxButtonActiveTex = L"MaximizeButtonActive.png";
-
-	const WString BuiltinEditorResources::TabBarBackgroundTex = L"TabBarBackground.png";
-	const WString BuiltinEditorResources::TitleBarBackgroundTex = L"TitleBarBackground.png";
-
-	const WString BuiltinEditorResources::TabButtonNormalTex = L"TabButtonNormal.png";
-	const WString BuiltinEditorResources::TabButtonFocusedTex = L"TabButtonFocused.png";
-
-	const WString BuiltinEditorResources::ScrollBarUpNormalTex = L"ScrollArrowUpNormal.png";
-	const WString BuiltinEditorResources::ScrollBarUpHoverTex = L"ScrollArrowUpHover.png";
-	const WString BuiltinEditorResources::ScrollBarUpActiveTex = L"ScrollArrowUpActive.png";
-
-	const WString BuiltinEditorResources::ScrollBarDownNormalTex = L"ScrollArrowDownNormal.png";
-	const WString BuiltinEditorResources::ScrollBarDownHoverTex = L"ScrollArrowDownHover.png";
-	const WString BuiltinEditorResources::ScrollBarDownActiveTex = L"ScrollArrowDownActive.png";
-
-	const WString BuiltinEditorResources::ScrollBarLeftNormalTex = L"ScrollArrowLeftNormal.png";
-	const WString BuiltinEditorResources::ScrollBarLeftHoverTex = L"ScrollArrowLeftHover.png";
-	const WString BuiltinEditorResources::ScrollBarLeftActiveTex = L"ScrollArrowLeftActive.png";
-
-	const WString BuiltinEditorResources::ScrollBarRightNormalTex = L"ScrollArrowRightNormal.png";
-	const WString BuiltinEditorResources::ScrollBarRightHoverTex = L"ScrollArrowRightHover.png";
-	const WString BuiltinEditorResources::ScrollBarRightActiveTex = L"ScrollArrowRightActive.png";
-
-	const WString BuiltinEditorResources::ScrollBarHandleHorzNormalTex = L"ScrollBarHHandleNormal.png";
-	const WString BuiltinEditorResources::ScrollBarHandleHorzHoverTex = L"ScrollBarHHandleHover.png";
-	const WString BuiltinEditorResources::ScrollBarHandleHorzActiveTex = L"ScrollBarHHandleActive.png";
-
-	const WString BuiltinEditorResources::ScrollBarHandleVertNormalTex = L"ScrollBarVHandleNormal.png";
-	const WString BuiltinEditorResources::ScrollBarHandleVertHoverTex = L"ScrollBarVHandleHover.png";
-	const WString BuiltinEditorResources::ScrollBarHandleVertActiveTex = L"ScrollBarVHandleActive.png";
-
-	const WString BuiltinEditorResources::ScrollBarHBgTex = L"ScrollBarHBackground.png";
-	const WString BuiltinEditorResources::ScrollBarVBgTex = L"ScrollBarVBackground.png";
-
-	const WString BuiltinEditorResources::DropDownBoxBgTex = L"DropDownBoxBg.png";
-	const WString BuiltinEditorResources::DropDownBoxSideBgTex = L"DropDownBoxSideBg.png";
-	const WString BuiltinEditorResources::DropDownBoxHandleTex = L"DropDownBoxScrollHandle.png";
-
-	const WString BuiltinEditorResources::DropDownBoxEntryNormalTex = L"DropDownBoxEntryNormal.png";
-	const WString BuiltinEditorResources::DropDownBoxEntryHoverTex = L"DropDownBoxEntryHover.png";
-
-	const WString BuiltinEditorResources::DropDownBoxEntryToggleNormalTex = L"DropDownBoxEntryToggleNormal.png";
-	const WString BuiltinEditorResources::DropDownBoxEntryToggleHoverTex = L"DropDownBoxEntryToggleHover.png";
-	const WString BuiltinEditorResources::DropDownBoxEntryToggleNormalOnTex = L"DropDownBoxEntryToggleNormalOn.png";
-	const WString BuiltinEditorResources::DropDownBoxEntryToggleHoverOnTex = L"DropDownBoxEntryToggleHoverOn.png";
-
-	const WString BuiltinEditorResources::DropDownBoxBtnUpNormalTex = L"DropDownBoxArrowUpNormal.png";
-	const WString BuiltinEditorResources::DropDownBoxBtnUpHoverTex = L"DropDownBoxArrowUpHover.png";
-
-	const WString BuiltinEditorResources::DropDownBoxBtnDownNormalTex = L"DropDownBoxArrowDownNormal.png";
-	const WString BuiltinEditorResources::DropDownBoxBtnDownHoverTex = L"DropDownBoxArrowDownHover.png";
-
-	const WString BuiltinEditorResources::DropDownBoxEntryExpNormalTex = L"DropDownBoxExpandBtnNormal.png";
-	const WString BuiltinEditorResources::DropDownBoxEntryExpHoverTex = L"DropDownBoxExpandBtnHover.png";
-
-	const WString BuiltinEditorResources::DropDownSeparatorTex = L"DropDownBoxSeparator.png";
-
-	const WString BuiltinEditorResources::MenuBarBgTex = L"MenuBarBackground.png";
-	const WString BuiltinEditorResources::MenuBarBansheeLogoTex = L"MenuBarLog.png";
-
-	const WString BuiltinEditorResources::MenuBarBtnNormalTex = L"MenuBarButtonNormal.png";
-	const WString BuiltinEditorResources::MenuBarBtnActiveTex = L"MenuBarButtonActive.png";
-	const WString BuiltinEditorResources::MenuBarBtnHoverTex = L"MenuBarButtonHover.png";
-
-	const WString BuiltinEditorResources::MenuBarLineNormalTex = L"MenuBarLineNormal.png";
-	const WString BuiltinEditorResources::MenuBarLineActiveTex = L"MenuBarLineActive.png";
-
-	const WString BuiltinEditorResources::ToolBarBtnNormalTex = L"ToolBarButtonNormal.png";
-	const WString BuiltinEditorResources::ToolBarBtnHoverTex = L"ToolBarButtonHover.png";
-	const WString BuiltinEditorResources::ToolBarBtnActiveTex = L"ToolBarButtonActive.png";
-
-	const WString BuiltinEditorResources::ToolBarSeparatorTex = L"ToolBarSeparator.png";
-
-	const WString BuiltinEditorResources::DockSliderNormalTex = L"DockSliderNormal.png";
-
-	const WString BuiltinEditorResources::TreeViewExpandButtonOffNormal = L"ExpandArrowNormalOff.png";
-	const WString BuiltinEditorResources::TreeViewExpandButtonOffHover = L"ExpandArrowHoverOff.png";
-	const WString BuiltinEditorResources::TreeViewExpandButtonOnNormal = L"ExpandArrowNormalOn.png";
-	const WString BuiltinEditorResources::TreeViewExpandButtonOnHover = L"ExpandArrowHoverOn.png";
-
-	const WString BuiltinEditorResources::TreeViewHighlightBackground = L"TreeViewHighlightBackground.psd";
-	const WString BuiltinEditorResources::TreeViewEditBox = L"TreeViewEditBox.psd";
-	const WString BuiltinEditorResources::TreeViewElementHighlight = L"TreeViewElementHighlight.psd";
-	const WString BuiltinEditorResources::TreeViewElementSepHighlight = L"TreeViewElementSepHighlight.psd";
-
-	const WString BuiltinEditorResources::ColorPickerSliderHorzHandleTex = L"ColorPickerSliderHorzHandle.psd";
-	const WString BuiltinEditorResources::ColorPickerSliderVertHandleTex = L"ColorPickerSliderVertHandle.psd";
-	const WString BuiltinEditorResources::ColorPickerSlider2DHandleTex = L"ColorPicker2DHandle.psd";
-
-	const WString BuiltinEditorResources::ProgressBarFillTex = L"ProgressBarFill.png";
-	const WString BuiltinEditorResources::ProgressBarBgTex = L"ProgressBarBg.png";
-
-	const WString BuiltinEditorResources::SelectionAreaTex = L"SelectionHighlight.png";
-	const WString BuiltinEditorResources::SelectionBgTex = L"SelectionBg.psd";
-
-	const WString BuiltinEditorResources::TextureDropTex = L"TextureDrop.png";
-	const WString BuiltinEditorResources::TextureDropOnTex = L"TextureDropHover.png";
-
-	const WString BuiltinEditorResources::XButtonNormalTex = L"XBtnNormal.png";
-	const WString BuiltinEditorResources::XButtonHoverTex = L"XBtnHover.png";
-	const WString BuiltinEditorResources::XButtonActiveTex = L"XBtnActive.png";
-
-	const WString BuiltinEditorResources::StatusBarBgTex = L"StatusBarBackground.png";
-	const WString BuiltinEditorResources::ScrollAreaBgTex = L"ScrollAreaBg.png";
-
-	const WString BuiltinEditorResources::InspectorTitleBgTex = L"InspectorTitleBg.png";
-	const WString BuiltinEditorResources::InspectorContentBgTex = L"InspectorContentBg.png";
-	const WString BuiltinEditorResources::InspectorContentBgAlternateTex = L"InspectorContentBgAlternate.png";
-
-	/************************************************************************/
-	/* 									SHADERS                      		*/
-	/************************************************************************/
-
-	const WString BuiltinEditorResources::ShaderDockOverlayFile = L"DockDropOverlay.bsl";
-	const WString BuiltinEditorResources::ShaderSceneGridFile = L"SceneGrid.bsl";
-	const WString BuiltinEditorResources::ShaderPickingCullNoneFile = L"PickingCullNone.bsl";
-	const WString BuiltinEditorResources::ShaderPickingCullCWFile = L"PickingCullCW.bsl";
-	const WString BuiltinEditorResources::ShaderPickingCullCCWFile = L"PickingCullCCW.bsl";
-	const WString BuiltinEditorResources::ShaderPickingAlphaCullNoneFile = L"PickingAlphaCullNone.bsl";
-	const WString BuiltinEditorResources::ShaderPickingAlphaCullCWFile = L"PickingAlphaCullCW.bsl";
-	const WString BuiltinEditorResources::ShaderPickingAlphaCullCCWFile = L"PickingAlphaCullCCW.bsl";
-	const WString BuiltinEditorResources::ShaderWireGizmoFile = L"WireGizmo.bsl";
-	const WString BuiltinEditorResources::ShaderSolidGizmoFile = L"SolidGizmo.bsl";
-	const WString BuiltinEditorResources::ShaderWireHandleFile = L"WireHandle.bsl";
-	const WString BuiltinEditorResources::ShaderSolidHandleFile = L"SolidHandle.bsl";
-	const WString BuiltinEditorResources::ShaderIconGizmoFile = L"IconGizmo.bsl";
-	const WString BuiltinEditorResources::ShaderGizmoPickingFile = L"GizmoPicking.bsl";
-	const WString BuiltinEditorResources::ShaderGizmoPickingAlphaFile = L"GizmoPickingAlpha.bsl";
-	const WString BuiltinEditorResources::ShaderSelectionFile = L"Selection.bsl";
-
-	/************************************************************************/
-	/* 								OTHER							  		*/
-	/************************************************************************/
-	const WString BuiltinEditorResources::EmptyShaderCodeFile = L"EmptyShaderText.txt";
-	const WString BuiltinEditorResources::EmptyCSScriptCodeFile = L"EmptyCSScriptText.txt";
-
-	BuiltinEditorResources::BuiltinEditorResources()
-	{
-		// Set up paths
-		BuiltinRawDataFolder = Paths::getRuntimeDataPath() + L"Raw\\Editor\\";
-		EditorRawSkinFolder = BuiltinRawDataFolder + SkinFolder;
-		EditorRawShaderFolder = BuiltinRawDataFolder + ShaderFolder;
-		EditorRawShaderIncludeFolder = BuiltinRawDataFolder + ShaderIncludeFolder;
-
-		BuiltinDataFolder = Paths::getRuntimeDataPath() + EDITOR_DATA_FOLDER;
-		EditorSkinFolder = BuiltinDataFolder + SkinFolder;
-		EditorIconFolder = BuiltinDataFolder + IconFolder;
-		EditorShaderFolder = BuiltinDataFolder + ShaderFolder;
-		EditorShaderIncludeFolder = BuiltinDataFolder + ShaderIncludeFolder;
-
-		ResourceManifestPath = BuiltinDataFolder + "ResourceManifest.asset";
-
-		Path absoluteDataPath = FileSystem::getWorkingDirectoryPath();
-		absoluteDataPath.append(BuiltinDataFolder);
-
-		// Update from raw assets if needed
-#if BS_DEBUG_MODE
-		if (BuiltinResourcesHelper::checkForModifications(BuiltinRawDataFolder, BuiltinDataFolder + L"Timestamp.asset"))
-		{
-			mResourceManifest = ResourceManifest::create("BuiltinResources");
-			gResources().registerResourceManifest(mResourceManifest);
-
-			preprocess();
-			BuiltinResourcesHelper::writeTimestamp(BuiltinDataFolder + L"Timestamp.asset");
-
-			Path absoluteDataPath = FileSystem::getWorkingDirectoryPath();
-			absoluteDataPath.append(BuiltinDataFolder);
-
-			ResourceManifest::save(mResourceManifest, ResourceManifestPath, absoluteDataPath);
-		}
-#endif
-
-		// Load manifest
-		if (mResourceManifest == nullptr)
-		{
-			if (FileSystem::exists(ResourceManifestPath))
-				mResourceManifest = ResourceManifest::load(ResourceManifestPath, absoluteDataPath);
-
-			if (mResourceManifest == nullptr)
-				mResourceManifest = ResourceManifest::create("BuiltinResources");
-
-			gResources().registerResourceManifest(mResourceManifest);
-		}
-
-		// Load basic resources
-		mShaderDockOverlay = getShader(ShaderDockOverlayFile);
-		mShaderSceneGrid = getShader(ShaderSceneGridFile);
-		mShaderPicking[(int)CULL_NONE] = getShader(ShaderPickingCullNoneFile);
-		mShaderPicking[(int)CULL_CLOCKWISE] = getShader(ShaderPickingCullCWFile);
-		mShaderPicking[(int)CULL_COUNTERCLOCKWISE] = getShader(ShaderPickingCullCCWFile);
-		mShaderPickingAlpha[(int)CULL_NONE] = getShader(ShaderPickingAlphaCullNoneFile);
-		mShaderPickingAlpha[(int)CULL_CLOCKWISE] = getShader(ShaderPickingAlphaCullCWFile);
-		mShaderPickingAlpha[(int)CULL_COUNTERCLOCKWISE] = getShader(ShaderPickingAlphaCullCCWFile);
-		mShaderGizmoSolid = getShader(ShaderSolidGizmoFile);
-		mShaderGizmoWire = getShader(ShaderWireGizmoFile);
-		mShaderGizmoIcon = getShader(ShaderIconGizmoFile);
-		mShaderGizmoPicking = getShader(ShaderGizmoPickingFile);
-		mShaderGizmoAlphaPicking = getShader(ShaderGizmoPickingAlphaFile);
-		mShaderHandleSolid = getShader(ShaderSolidHandleFile);
-		mShaderHandleWire = getShader(ShaderWireHandleFile);
-		mShaderSelection = getShader(ShaderSelectionFile);
-
-		mSkin = gResources().load<GUISkin>(BuiltinDataFolder + (GUISkinFile + L".asset"));
-	}
-
-	BuiltinEditorResources::~BuiltinEditorResources()
-	{ }
-
-	void BuiltinEditorResources::preprocess()
-	{
-		BuiltinResourcesHelper::importAssets(EditorRawShaderIncludeFolder, EditorShaderIncludeFolder, mResourceManifest); // Hidden dependency: Includes must be imported before shaders
-		BuiltinResourcesHelper::importAssets(EditorRawShaderFolder, EditorShaderFolder, mResourceManifest);
-		BuiltinResourcesHelper::importAssets(EditorRawSkinFolder, EditorSkinFolder, mResourceManifest);
-
-		// Generate different sizes of resource icons
-		generateResourceIcons(EditorIconFolder, mResourceManifest);
-
-		// Import fonts
-		BuiltinResourcesHelper::importFont(BuiltinRawDataFolder + DefaultFontFilename, DefaultFontFilename, 
-			BuiltinDataFolder, { DefaultFontSize }, true, mResourceManifest);
-
-		BuiltinResourcesHelper::importFont(BuiltinRawDataFolder + DefaultFontFilename, DefaultAAFontFilename, 
-			BuiltinDataFolder, { TitleFontSize }, true, mResourceManifest);
-
-		// Generate & save GUI sprite textures
-		BuiltinResourcesHelper::generateSpriteTextures(EditorSkinFolder, mResourceManifest);
-
-		// Generate & save GUI skin
-		{
-			GUISkinPtr skin = generateGUISkin();
-			Path outputPath = FileSystem::getWorkingDirectoryPath() + BuiltinDataFolder + (GUISkinFile + L".asset");
-
-			HResource skinResource;
-			if (FileSystem::exists(outputPath))
-				skinResource = gResources().load(outputPath);
-
-			if (skinResource.isLoaded())
-				gResources().update(skinResource, skin);
-			else
-				skinResource = gResources()._createResourceHandle(skin);
-
-			gResources().save(skinResource, outputPath, true);
-			mResourceManifest->registerResource(skinResource.getUUID(), outputPath);
-		}
-
-		Resources::instance().unloadAllUnused();
-	}
-
-	void BuiltinEditorResources::generateResourceIcons(const Path& inputFolder, const ResourceManifestPtr& manifest)
-	{
-		if (!FileSystem::exists(inputFolder))
-			return;
-
-		WString iconsToProcess[] = { FolderIconTex, FontIconTex, MeshIconTex, TextureIconTex, PlainTextIconTex, 
-			ScriptCodeIconTex, ShaderIconTex, ShaderIncludeIconTex, MaterialIconTex, SpriteTextureIconTex, PrefabIconTex,
-			GUISkinIconTex };
-
-		PixelDataPtr srcData[sizeof(iconsToProcess)];
-
-		UINT32 idx = 0;
-		for (auto& iconName : iconsToProcess)
-		{
-			Path path = inputFolder + (iconName + L".asset");
-
-			HTexture source = gResources().load<Texture>(path);
-			if (source != nullptr)
-			{
-				srcData[idx] = source->getProperties().allocateSubresourceBuffer(0);
-				source->readSubresource(gCoreAccessor(), 0, srcData[idx]);
-			}
-
-			idx++;
-		}
-
-		gCoreAccessor().submitToCoreThread(true);
-
-		idx = 0;
-		for (auto& iconName : iconsToProcess)
-		{
-			PixelDataPtr src = srcData[idx];
-
-			PixelDataPtr scaled48 = PixelData::create(48, 48, 1, src->getFormat());
-			PixelUtil::scale(*src, *scaled48);
-
-			PixelDataPtr scaled32 = PixelData::create(32, 32, 1, src->getFormat());
-			PixelUtil::scale(*scaled48, *scaled32);
-
-			PixelDataPtr scaled16 = PixelData::create(16, 16, 1, src->getFormat());
-			PixelUtil::scale(*scaled32, *scaled16);
-
-			HTexture tex48 = Texture::create(scaled48);
-			HTexture tex32 = Texture::create(scaled32);
-			HTexture tex16 = Texture::create(scaled16);
-
-			Path outputPath48 = FileSystem::getWorkingDirectoryPath() + inputFolder + (iconName + L"48.asset");
-			Resources::instance().save(tex48, outputPath48, true);
-			manifest->registerResource(tex48.getUUID(), outputPath48);
-
-			Path outputPath32 = FileSystem::getWorkingDirectoryPath() + inputFolder + (iconName + L"32.asset");
-			Resources::instance().save(tex32, outputPath32, true);
-			manifest->registerResource(tex32.getUUID(), outputPath32);
-
-			Path outputPath16 = FileSystem::getWorkingDirectoryPath() + inputFolder + (iconName + L"16.asset");
-			Resources::instance().save(tex16, outputPath16, true);
-			manifest->registerResource(tex16.getUUID(), outputPath16);
-
-			idx++;
-		}
-	}
-
-	GUISkinPtr BuiltinEditorResources::generateGUISkin()
-	{
-		GUISkinPtr skin = GUISkin::_createPtr();
-
-		Path defaultFontPath = FileSystem::getWorkingDirectoryPath();
-		defaultFontPath.append(BuiltinDataFolder);
-		defaultFontPath.append(DefaultFontFilename + L".asset");
-
-		HFont defaultFont = gResources().load<Font>(defaultFontPath);
-
-		Path defaultAAFontPath = FileSystem::getWorkingDirectoryPath();
-		defaultAAFontPath.append(BuiltinDataFolder);
-		defaultAAFontPath.append(DefaultAAFontFilename + L".asset");
-
-		HFont defaultAAFont = gResources().load<Font>(defaultAAFontPath);
-
-		// Blank entry
-		GUIElementStyle blankStyle;
-
-		skin->setStyle("Blank", blankStyle);
-		skin->setStyle(GUITexture::getGUITypeName(), blankStyle);
-
-		// Label
-		GUIElementStyle labelStyle;
-		labelStyle.font = defaultFont;
-		labelStyle.fontSize = DefaultFontSize;
-		labelStyle.fixedWidth = false;
-		labelStyle.fixedHeight = true;
-		labelStyle.height = 14;
-		labelStyle.minWidth = 10;
-		labelStyle.normal.textColor = TextNormalColor;
-
-		skin->setStyle(GUILabel::getGUITypeName(), labelStyle);
-
-		// Window frame
-		GUIElementStyle windowFrameStyle;
-		windowFrameStyle.normal.texture = getGUITexture(WindowFrameNormal);
-		windowFrameStyle.focused.texture = getGUITexture(WindowFrameFocused);
-		windowFrameStyle.border.left = 1;
-		windowFrameStyle.border.right = 1;
-		windowFrameStyle.border.top = 1;
-		windowFrameStyle.border.bottom = 1;
-
-		skin->setStyle("WindowFrame", windowFrameStyle);
-
-		// Button
-		GUIElementStyle buttonStyle;
-		buttonStyle.normal.texture = getGUITexture(ButtonNormalTex);
-		buttonStyle.hover.texture = getGUITexture(ButtonHoverTex);
-		buttonStyle.active.texture = getGUITexture(ButtonActiveTex);
-		buttonStyle.normalOn.texture = getGUITexture(ButtonActiveTex);
-		buttonStyle.hoverOn.texture = getGUITexture(ButtonActiveTex);
-		buttonStyle.activeOn.texture = getGUITexture(ButtonActiveTex);
-		buttonStyle.normal.textColor = TextNormalColor;
-		buttonStyle.hover.textColor = TextNormalColor;
-		buttonStyle.active.textColor = TextActiveColor;
-		buttonStyle.normalOn.textColor = TextActiveColor;
-		buttonStyle.hoverOn.textColor = TextActiveColor;
-		buttonStyle.activeOn.textColor = TextActiveColor;
-		buttonStyle.border.left = 2;
-		buttonStyle.border.right = 2;
-		buttonStyle.border.top = 2;
-		buttonStyle.border.bottom = 4;
-		buttonStyle.contentOffset.top = 2;
-		buttonStyle.contentOffset.left = 3;
-		buttonStyle.contentOffset.right = 3;
-		buttonStyle.margins.bottom = 2;
-		buttonStyle.fixedHeight = true;
-		buttonStyle.height = 21;
-		buttonStyle.minWidth = 20;
-		buttonStyle.font = defaultFont;
-		buttonStyle.fontSize = DefaultFontSize;
-		buttonStyle.textHorzAlign = THA_Center;
-		buttonStyle.textVertAlign = TVA_Center;
-
-		skin->setStyle(GUIButton::getGUITypeName(), buttonStyle);
-
-		// Left edge button
-		GUIElementStyle leftButtonStyle;
-		leftButtonStyle.normal.texture = getGUITexture(ButtonLeftNormalTex);
-		leftButtonStyle.hover.texture = getGUITexture(ButtonLeftHoverTex);
-		leftButtonStyle.active.texture = getGUITexture(ButtonLeftActiveTex);
-		leftButtonStyle.normalOn.texture = getGUITexture(ButtonLeftActiveTex);
-		leftButtonStyle.hoverOn.texture = getGUITexture(ButtonLeftActiveTex);
-		leftButtonStyle.activeOn.texture = getGUITexture(ButtonLeftActiveTex);
-		leftButtonStyle.normal.textColor = TextNormalColor;
-		leftButtonStyle.hover.textColor = TextNormalColor;
-		leftButtonStyle.active.textColor = TextActiveColor;
-		leftButtonStyle.normalOn.textColor = TextActiveColor;
-		leftButtonStyle.hoverOn.textColor = TextActiveColor;
-		leftButtonStyle.activeOn.textColor = TextActiveColor;
-		leftButtonStyle.border.left = 7;
-		leftButtonStyle.border.right = 2;
-		leftButtonStyle.border.top = 2;
-		leftButtonStyle.border.bottom = 4;
-		leftButtonStyle.contentOffset.top = 2;
-		leftButtonStyle.contentOffset.left = 7;
-		leftButtonStyle.contentOffset.right = 3;
-		leftButtonStyle.margins.bottom = 2;
-		leftButtonStyle.fixedHeight = true;
-		leftButtonStyle.height = 21;
-		leftButtonStyle.minWidth = 20;
-		leftButtonStyle.font = defaultFont;
-		leftButtonStyle.fontSize = DefaultFontSize;
-		leftButtonStyle.textHorzAlign = THA_Center;
-		leftButtonStyle.textVertAlign = TVA_Center;
-
-		skin->setStyle("ButtonLeft", leftButtonStyle);
-
-		// Right edge button
-		GUIElementStyle rightButtonStyle;
-		rightButtonStyle.normal.texture = getGUITexture(ButtonRightNormalTex);
-		rightButtonStyle.hover.texture = getGUITexture(ButtonRightHoverTex);
-		rightButtonStyle.active.texture = getGUITexture(ButtonRightActiveTex);
-		rightButtonStyle.normalOn.texture = getGUITexture(ButtonRightActiveTex);
-		rightButtonStyle.hoverOn.texture = getGUITexture(ButtonRightActiveTex);
-		rightButtonStyle.activeOn.texture = getGUITexture(ButtonRightActiveTex);
-		rightButtonStyle.normal.textColor = TextNormalColor;
-		rightButtonStyle.hover.textColor = TextNormalColor;
-		rightButtonStyle.active.textColor = TextActiveColor;
-		rightButtonStyle.normalOn.textColor = TextActiveColor;
-		rightButtonStyle.hoverOn.textColor = TextActiveColor;
-		rightButtonStyle.activeOn.textColor = TextActiveColor;
-		rightButtonStyle.border.left = 2;
-		rightButtonStyle.border.right = 7;
-		rightButtonStyle.border.top = 2;
-		rightButtonStyle.border.bottom = 4;
-		rightButtonStyle.contentOffset.top = 2;
-		rightButtonStyle.contentOffset.left = 3;
-		rightButtonStyle.contentOffset.right = 7;
-		rightButtonStyle.margins.bottom = 2;
-		rightButtonStyle.fixedHeight = true;
-		rightButtonStyle.height = 21;
-		rightButtonStyle.minWidth = 20;
-		rightButtonStyle.font = defaultFont;
-		rightButtonStyle.fontSize = DefaultFontSize;
-		rightButtonStyle.textHorzAlign = THA_Center;
-		rightButtonStyle.textVertAlign = TVA_Center;
-
-		skin->setStyle("ButtonRight", rightButtonStyle);
-
-		// Toggle
-		GUIElementStyle toggleStyle;
-		toggleStyle.normal.texture = getGUITexture(ToggleNormalTex);
-		toggleStyle.hover.texture = getGUITexture(ToggleHoverTex);
-		toggleStyle.active.texture = toggleStyle.hover.texture;
-		toggleStyle.normalOn.texture = getGUITexture(ToggleNormalOnTex);
-		toggleStyle.hoverOn.texture = getGUITexture(ToggleHoverOnTex);
-		toggleStyle.activeOn.texture = toggleStyle.hoverOn.texture;
-		toggleStyle.fixedHeight = true;
-		toggleStyle.fixedWidth = true;
-		toggleStyle.margins.bottom = 2;
-		toggleStyle.height = 15;
-		toggleStyle.width = 13;
-
-		skin->setStyle(GUIToggle::getGUITypeName(), toggleStyle);
-
-		// Color
-		GUIElementStyle colorStyle;
-		colorStyle.margins.left = 2;
-		colorStyle.margins.right = 2;
-		colorStyle.margins.top = 2;
-		colorStyle.margins.bottom = 2;
-		colorStyle.fixedHeight = true;
-		colorStyle.height = 15;
-		colorStyle.minWidth = 10;
-
-		skin->setStyle(GUIColor::getGUITypeName(), colorStyle);
-
-		// Window background texture
-		GUIElementStyle windowBgStyle;
-		windowBgStyle.normal.texture = getGUITexture(WindowBackgroundTex);
-
-		skin->setStyle("WindowBackground", windowBgStyle);
-
-		// Window tab bar background
-		GUIElementStyle tabBarBgStyle;
-		tabBarBgStyle.normal.texture = getGUITexture(TabBarBackgroundTex);
-		tabBarBgStyle.fixedHeight = true;
-		tabBarBgStyle.height = 16;
-
-		skin->setStyle("TabBarBackground", tabBarBgStyle);
-
-		// Tabbed title bar tab button
-		GUIElementStyle tabbedBarButton;
-		tabbedBarButton.normal.texture = getGUITexture(TabButtonNormalTex);
-		tabbedBarButton.hover.texture = tabbedBarButton.normal.texture;
-		tabbedBarButton.active.texture = getGUITexture(TabButtonFocusedTex);
-		tabbedBarButton.normalOn.texture = tabbedBarButton.active.texture;
-		tabbedBarButton.hoverOn.texture = tabbedBarButton.active.texture;
-		tabbedBarButton.activeOn.texture = tabbedBarButton.active.texture;
-		tabbedBarButton.normal.textColor = TextNormalColor;
-		tabbedBarButton.hover.textColor = TextNormalColor;
-		tabbedBarButton.active.textColor = TextActiveColor;
-		tabbedBarButton.normalOn.textColor = TextActiveColor;
-		tabbedBarButton.hoverOn.textColor = TextActiveColor;
-		tabbedBarButton.activeOn.textColor = TextActiveColor;
-		tabbedBarButton.border.left = 12;
-		tabbedBarButton.border.right = 12;
-		tabbedBarButton.margins.left = 5;
-		tabbedBarButton.margins.right = 5;
-		tabbedBarButton.contentOffset.top = 3;
-		tabbedBarButton.contentOffset.left = 6;
-		tabbedBarButton.contentOffset.right = 6;
-		tabbedBarButton.fixedHeight = true;
-		tabbedBarButton.height = 15;
-		tabbedBarButton.minWidth = 24;
-		tabbedBarButton.maxWidth = 110;
-		tabbedBarButton.font = defaultFont;
-		tabbedBarButton.fontSize = DefaultFontSize;
-		tabbedBarButton.textHorzAlign = THA_Center;
-		tabbedBarButton.textVertAlign = TVA_Center;
-
-		skin->setStyle("TabbedBarBtn", tabbedBarButton);
-
-		// Tabbed title bar drag/drop button
-		GUIElementStyle tabbedBarDropButton;
-		tabbedBarDropButton.fixedHeight = true;
-		tabbedBarDropButton.fixedWidth = true;
-		tabbedBarDropButton.height = 13;
-		tabbedBarDropButton.width = 6;
-
-		skin->setStyle("TabbedBarDropArea", tabbedBarDropButton);
-
-		// Window title bar background
-		GUIElementStyle titleBarBgStyle;
-		titleBarBgStyle.normal.texture = getGUITexture(TitleBarBackgroundTex);
-		titleBarBgStyle.fixedHeight = true;
-		titleBarBgStyle.height = 17;
-
-		skin->setStyle("TitleBarBackground", titleBarBgStyle);
-
-		// Window minimize button
-		GUIElementStyle winMinButtonStyle;
-		winMinButtonStyle.normal.texture = getGUITexture(MinButtonNormalTex);
-		winMinButtonStyle.hover.texture = getGUITexture(MinButtonHoverTex);
-		winMinButtonStyle.active.texture = getGUITexture(MinButtonActiveTex);
-		winMinButtonStyle.fixedHeight = true;
-		winMinButtonStyle.fixedWidth = true;
-		winMinButtonStyle.height = 14;
-		winMinButtonStyle.width = 14;
-
-		skin->setStyle("WinMinimizeBtn", winMinButtonStyle);
-
-		// Window maximize button
-		GUIElementStyle winMaxButtonStyle;
-		winMaxButtonStyle.normal.texture = getGUITexture(MaxButtonNormalTex);
-		winMaxButtonStyle.hover.texture = getGUITexture(MaxButtonHoverTex);
-		winMaxButtonStyle.active.texture = getGUITexture(MaxButtonActiveTex);
-		winMaxButtonStyle.fixedHeight = true;
-		winMaxButtonStyle.fixedWidth = true;
-		winMaxButtonStyle.height = 14;
-		winMaxButtonStyle.width = 14;
-
-		skin->setStyle("WinMaximizeBtn", winMaxButtonStyle);
-
-		// Window close button
-		GUIElementStyle winCloseButtonStyle;
-		winCloseButtonStyle.normal.texture = getGUITexture(CloseButtonNormalTex);
-		winCloseButtonStyle.hover.texture = getGUITexture(CloseButtonHoverTex);
-		winCloseButtonStyle.active.texture = getGUITexture(CloseButtonActiveTex);
-		winCloseButtonStyle.fixedHeight = true;
-		winCloseButtonStyle.fixedWidth = true;
-		winCloseButtonStyle.height = 14;
-		winCloseButtonStyle.width = 14;
-
-		skin->setStyle("WinCloseBtn", winCloseButtonStyle);
-
-		// Input box
-		GUIElementStyle inputBoxStyle;
-		inputBoxStyle.normal.texture = getGUITexture(InputBoxNormalTex);
-		inputBoxStyle.hover.texture = getGUITexture(InputBoxHoverTex);
-		inputBoxStyle.focused.texture = getGUITexture(InputBoxFocusedTex);
-		inputBoxStyle.active.texture = inputBoxStyle.normal.texture;
-		inputBoxStyle.normal.textColor = TextNormalColor;
-		inputBoxStyle.hover.textColor = TextNormalColor;
-		inputBoxStyle.focused.textColor = TextNormalColor;
-		inputBoxStyle.active.textColor = TextNormalColor;
-		inputBoxStyle.border.left = 4;
-		inputBoxStyle.border.right = 4;
-		inputBoxStyle.border.top = 4;
-		inputBoxStyle.border.bottom = 6;
-		inputBoxStyle.contentOffset.left = 4;
-		inputBoxStyle.contentOffset.right = 4;
-		inputBoxStyle.contentOffset.top = 4;
-		inputBoxStyle.contentOffset.bottom = 4;
-		inputBoxStyle.margins.bottom = 2;
-		inputBoxStyle.fixedHeight = true;
-		inputBoxStyle.height = 21;
-		inputBoxStyle.minWidth = 10;
-		inputBoxStyle.font = defaultFont;
-		inputBoxStyle.fontSize = DefaultFontSize;
-		inputBoxStyle.textHorzAlign = THA_Left;
-		inputBoxStyle.textVertAlign = TVA_Top;
-
-		skin->setStyle(GUIInputBox::getGUITypeName(), inputBoxStyle);
-
-		/************************************************************************/
-		/* 								SCROLL BAR                      		*/
-		/************************************************************************/
-
-		// Up button
-		GUIElementStyle scrollUpBtnStyle;
-		scrollUpBtnStyle.normal.texture = getGUITexture(ScrollBarUpNormalTex);
-		scrollUpBtnStyle.hover.texture = getGUITexture(ScrollBarUpHoverTex);
-		scrollUpBtnStyle.active.texture = getGUITexture(ScrollBarUpActiveTex);
-		scrollUpBtnStyle.fixedHeight = true;
-		scrollUpBtnStyle.fixedWidth = true;
-		scrollUpBtnStyle.height = 11;
-		scrollUpBtnStyle.width = 13;
-
-		skin->setStyle("ScrollUpBtn", scrollUpBtnStyle);
-
-		// Down button
-		GUIElementStyle scrollDownBtnStyle;
-		scrollDownBtnStyle.normal.texture = getGUITexture(ScrollBarDownNormalTex);
-		scrollDownBtnStyle.hover.texture = getGUITexture(ScrollBarDownHoverTex);
-		scrollDownBtnStyle.active.texture = getGUITexture(ScrollBarDownActiveTex);
-		scrollDownBtnStyle.fixedHeight = true;
-		scrollDownBtnStyle.fixedWidth = true;
-		scrollDownBtnStyle.height = 11;
-		scrollDownBtnStyle.width = 13;
-
-		skin->setStyle("ScrollDownBtn", scrollDownBtnStyle);
-
-		// Left button
-		GUIElementStyle scrollLeftBtnStyle;
-		scrollLeftBtnStyle.normal.texture = getGUITexture(ScrollBarLeftNormalTex);
-		scrollLeftBtnStyle.hover.texture = getGUITexture(ScrollBarLeftHoverTex);
-		scrollLeftBtnStyle.active.texture = getGUITexture(ScrollBarLeftActiveTex);
-		scrollLeftBtnStyle.fixedHeight = true;
-		scrollLeftBtnStyle.fixedWidth = true;
-		scrollLeftBtnStyle.height = 13;
-		scrollLeftBtnStyle.width = 11;
-
-		skin->setStyle("ScrollLeftBtn", scrollLeftBtnStyle);
-
-		// Right button
-		GUIElementStyle scrollRightBtnStyle;
-		scrollRightBtnStyle.normal.texture = getGUITexture(ScrollBarRightNormalTex);
-		scrollRightBtnStyle.hover.texture = getGUITexture(ScrollBarRightHoverTex);
-		scrollRightBtnStyle.active.texture = getGUITexture(ScrollBarRightActiveTex);
-		scrollRightBtnStyle.fixedHeight = true;
-		scrollRightBtnStyle.fixedWidth = true;
-		scrollRightBtnStyle.height = 13;
-		scrollRightBtnStyle.width = 11;
-
-		skin->setStyle("ScrollRightBtn", scrollRightBtnStyle);
-
-		// Horizontal handle
-		GUIElementStyle scrollBarHorzBtnStyle;
-		scrollBarHorzBtnStyle.normal.texture = getGUITexture(ScrollBarHandleHorzNormalTex);
-		scrollBarHorzBtnStyle.hover.texture = getGUITexture(ScrollBarHandleHorzHoverTex);
-		scrollBarHorzBtnStyle.active.texture = getGUITexture(ScrollBarHandleHorzActiveTex);
-		scrollBarHorzBtnStyle.fixedHeight = true;
-		scrollBarHorzBtnStyle.fixedWidth = false;
-		scrollBarHorzBtnStyle.width = 10;
-		scrollBarHorzBtnStyle.height = 13;
-		scrollBarHorzBtnStyle.border.left = 4;
-		scrollBarHorzBtnStyle.border.right = 4;
-
-		skin->setStyle("ScrollBarHorzBtn", scrollBarHorzBtnStyle);
-
-		// Vertical handle
-		GUIElementStyle scrollBarVertBtnStyle;
-		scrollBarVertBtnStyle.normal.texture = getGUITexture(ScrollBarHandleVertNormalTex);
-		scrollBarVertBtnStyle.hover.texture = getGUITexture(ScrollBarHandleVertHoverTex);
-		scrollBarVertBtnStyle.active.texture = getGUITexture(ScrollBarHandleVertActiveTex);
-		scrollBarVertBtnStyle.fixedHeight = false;
-		scrollBarVertBtnStyle.fixedWidth = true;
-		scrollBarVertBtnStyle.width = 13;
-		scrollBarVertBtnStyle.height = 10;
-		scrollBarVertBtnStyle.border.top = 4;
-		scrollBarVertBtnStyle.border.bottom = 4;
-
-		skin->setStyle("ScrollBarVertBtn", scrollBarVertBtnStyle);
-
-		// Vertical scroll bar
-		GUIElementStyle vertScrollBarStyle;
-		vertScrollBarStyle.normal.texture = getGUITexture(ScrollBarVBgTex);
-		vertScrollBarStyle.hover.texture = vertScrollBarStyle.normal.texture;
-		vertScrollBarStyle.active.texture = vertScrollBarStyle.normal.texture;
-		vertScrollBarStyle.fixedHeight = false;
-		vertScrollBarStyle.fixedWidth = true;
-		vertScrollBarStyle.minHeight = 8;
-		vertScrollBarStyle.width = 16;
-
-		skin->setStyle("ScrollBarVert", vertScrollBarStyle);
-
-		// Horizontal scroll bar
-		GUIElementStyle horzScrollBarStyle;
-		horzScrollBarStyle.normal.texture = getGUITexture(ScrollBarHBgTex);
-		horzScrollBarStyle.hover.texture = horzScrollBarStyle.normal.texture;
-		horzScrollBarStyle.active.texture = horzScrollBarStyle.normal.texture;
-		horzScrollBarStyle.fixedHeight = true;
-		horzScrollBarStyle.fixedWidth = false;
-		horzScrollBarStyle.minWidth = 8;
-		horzScrollBarStyle.height = 16;
-
-		skin->setStyle("ScrollBarHorz", horzScrollBarStyle);
-
-		/************************************************************************/
-		/* 								DROP DOWN BOX                      		*/
-		/************************************************************************/
-
-		// ListBox button
-		GUIElementStyle dropDownListStyle;
-		dropDownListStyle.normal.texture = getGUITexture(DropDownBtnNormalTex);
-		dropDownListStyle.hover.texture = getGUITexture(DropDownBtnHoverTex);
-		dropDownListStyle.active.texture = getGUITexture(DropDownBtnActiveTex);
-		dropDownListStyle.normalOn.texture = dropDownListStyle.active.texture;
-		dropDownListStyle.hoverOn.texture = dropDownListStyle.active.texture;
-		dropDownListStyle.activeOn.texture = dropDownListStyle.active.texture;
-		dropDownListStyle.normal.textColor = TextNormalColor;
-		dropDownListStyle.hover.textColor = TextNormalColor;
-		dropDownListStyle.active.textColor = TextNormalColor;
-		dropDownListStyle.normalOn.textColor = TextNormalColor;
-		dropDownListStyle.hoverOn.textColor = TextNormalColor;
-		dropDownListStyle.activeOn.textColor = TextNormalColor;
-		dropDownListStyle.fixedHeight = true;
-		dropDownListStyle.fixedWidth = false;
-		dropDownListStyle.height = 21;
-		dropDownListStyle.minWidth = 20;
-		dropDownListStyle.contentOffset.left = 3;
-		dropDownListStyle.contentOffset.right = 18;
-		dropDownListStyle.contentOffset.top = 2;
-		dropDownListStyle.contentOffset.bottom = 2;
-		dropDownListStyle.border.left = 2;
-		dropDownListStyle.border.right = 16;
-		dropDownListStyle.border.top = 2;
-		dropDownListStyle.border.bottom = 4;
-		dropDownListStyle.margins.bottom = 2;
-		dropDownListStyle.font = defaultFont;
-		dropDownListStyle.fontSize = DefaultFontSize;
-		dropDownListStyle.textHorzAlign = THA_Left;
-		dropDownListStyle.textVertAlign = TVA_Center;
-
-		skin->setStyle(GUIListBox::getGUITypeName(), dropDownListStyle);
-
-		// DropDown scroll up button
-		GUIElementStyle dropDownScrollUpBtnStyle;
-		dropDownScrollUpBtnStyle.normal.texture = getGUITexture(DropDownBoxBtnUpNormalTex);
-		dropDownScrollUpBtnStyle.hover.texture = getGUITexture(DropDownBoxBtnUpHoverTex);
-		dropDownScrollUpBtnStyle.active.texture = dropDownScrollUpBtnStyle.hover.texture;
-		dropDownScrollUpBtnStyle.fixedHeight = true;
-		dropDownScrollUpBtnStyle.fixedWidth = true;
-		dropDownScrollUpBtnStyle.width = 8;
-		dropDownScrollUpBtnStyle.height = 12;
-
-		skin->setStyle("ListBoxScrollUpBtn", dropDownScrollUpBtnStyle);
-		skin->setStyle("MenuBarScrollUpBtn", dropDownScrollUpBtnStyle);
-		skin->setStyle("ContextMenuScrollUpBtn", dropDownScrollUpBtnStyle);
-
-		// DropDown scroll down button
-		GUIElementStyle dropDownScrollDownBtnStyle;
-		dropDownScrollDownBtnStyle.normal.texture = getGUITexture(DropDownBoxBtnDownNormalTex);
-		dropDownScrollDownBtnStyle.hover.texture = getGUITexture(DropDownBoxBtnDownHoverTex);
-		dropDownScrollDownBtnStyle.active.texture = dropDownScrollDownBtnStyle.hover.texture;
-		dropDownScrollDownBtnStyle.fixedHeight = true;
-		dropDownScrollDownBtnStyle.fixedWidth = true;
-		dropDownScrollDownBtnStyle.width = 8;
-		dropDownScrollDownBtnStyle.height = 12;
-
-		skin->setStyle("ListBoxScrollDownBtn", dropDownScrollDownBtnStyle);
-		skin->setStyle("MenuBarScrollDownBtn", dropDownScrollDownBtnStyle);
-		skin->setStyle("ContextMenuScrollDownBtn", dropDownScrollDownBtnStyle);
-
-		// DropDown handle
-		GUIElementStyle dropDownScrollHandleStyle;
-		dropDownScrollHandleStyle.normal.texture = getGUITexture(DropDownBoxHandleTex);
-		dropDownScrollHandleStyle.fixedHeight = false;
-		dropDownScrollHandleStyle.fixedWidth = true;
-		dropDownScrollHandleStyle.height = 8;
-		dropDownScrollHandleStyle.width = 8;
-
-		skin->setStyle("ListBoxHandle", dropDownScrollHandleStyle);
-		skin->setStyle("MenuBarHandle", dropDownScrollHandleStyle);
-		skin->setStyle("ContextMenuHandle", dropDownScrollHandleStyle);
-
-		// DropDown sidebar background
-		GUIElementStyle dropDownSidebarBg;
-		dropDownSidebarBg.normal.texture = getGUITexture(DropDownBoxSideBgTex);
-		dropDownSidebarBg.fixedHeight = false;
-		dropDownSidebarBg.fixedWidth = true;
-		dropDownSidebarBg.height = 8;
-		dropDownSidebarBg.width = 9;
-		dropDownSidebarBg.border.left = 1;
-		dropDownSidebarBg.border.top = 1;
-		dropDownSidebarBg.border.bottom = 1;
-
-		skin->setStyle("ListBoxSidebarBg", dropDownSidebarBg);
-		skin->setStyle("MenuBarSidebarBg", dropDownSidebarBg);
-		skin->setStyle("ContextMenuSidebarBg", dropDownSidebarBg);
-
-		// DropDown entry button
-		GUIElementStyle dropDownEntryBtnStyle;
-		dropDownEntryBtnStyle.normal.texture = getGUITexture(DropDownBoxEntryNormalTex);
-		dropDownEntryBtnStyle.hover.texture = getGUITexture(DropDownBoxEntryHoverTex);
-		dropDownEntryBtnStyle.active.texture = dropDownEntryBtnStyle.hover.texture;
-		dropDownEntryBtnStyle.normalOn.texture = dropDownEntryBtnStyle.hover.texture;
-		dropDownEntryBtnStyle.hoverOn.texture = dropDownEntryBtnStyle.hover.texture;
-		dropDownEntryBtnStyle.activeOn.texture = dropDownEntryBtnStyle.hover.texture;
-		dropDownEntryBtnStyle.normal.textColor = TextNormalColor;
-		dropDownEntryBtnStyle.hover.textColor = TextNormalColor;
-		dropDownEntryBtnStyle.active.textColor = TextNormalColor;
-		dropDownEntryBtnStyle.normalOn.textColor = TextNormalColor;
-		dropDownEntryBtnStyle.hoverOn.textColor = TextNormalColor;
-		dropDownEntryBtnStyle.activeOn.textColor = TextNormalColor;
-		dropDownEntryBtnStyle.fixedHeight = true;
-		dropDownEntryBtnStyle.fixedWidth = false;
-		dropDownEntryBtnStyle.height = 16;
-		dropDownEntryBtnStyle.width = 30;
-		dropDownEntryBtnStyle.font = defaultFont;
-		dropDownEntryBtnStyle.fontSize = DefaultFontSize;
-		dropDownEntryBtnStyle.textHorzAlign = THA_Left;
-		dropDownEntryBtnStyle.textVertAlign = TVA_Center;
-
-		skin->setStyle(GUIDropDownContent::ENTRY_STYLE_TYPE, dropDownEntryBtnStyle);
-
-		// DropDown toggle entry button
-		GUIElementStyle dropDownToggleEntryBtnStyle;
-		dropDownToggleEntryBtnStyle.normal.texture = getGUITexture(DropDownBoxEntryToggleNormalTex);
-		dropDownToggleEntryBtnStyle.hover.texture = getGUITexture(DropDownBoxEntryToggleHoverTex);
-		dropDownToggleEntryBtnStyle.active.texture = dropDownToggleEntryBtnStyle.hover.texture;
-		dropDownToggleEntryBtnStyle.normalOn.texture = getGUITexture(DropDownBoxEntryToggleNormalOnTex);
-		dropDownToggleEntryBtnStyle.hoverOn.texture = getGUITexture(DropDownBoxEntryToggleHoverOnTex);
-		dropDownToggleEntryBtnStyle.activeOn.texture = dropDownToggleEntryBtnStyle.hoverOn.texture;
-		dropDownToggleEntryBtnStyle.normal.textColor = TextNormalColor;
-		dropDownToggleEntryBtnStyle.hover.textColor = TextNormalColor;
-		dropDownToggleEntryBtnStyle.active.textColor = TextNormalColor;
-		dropDownToggleEntryBtnStyle.normalOn.textColor = TextNormalColor;
-		dropDownToggleEntryBtnStyle.hoverOn.textColor = TextNormalColor;
-		dropDownToggleEntryBtnStyle.activeOn.textColor = TextNormalColor;
-		dropDownToggleEntryBtnStyle.fixedHeight = true;
-		dropDownToggleEntryBtnStyle.fixedWidth = false;
-		dropDownToggleEntryBtnStyle.height = 18;
-		dropDownToggleEntryBtnStyle.width = 30;
-		dropDownToggleEntryBtnStyle.border.left = 17;
-		dropDownToggleEntryBtnStyle.contentOffset.left = 17;
-		dropDownToggleEntryBtnStyle.font = defaultFont;
-		dropDownToggleEntryBtnStyle.fontSize = DefaultFontSize;
-		dropDownToggleEntryBtnStyle.textHorzAlign = THA_Left;
-		dropDownToggleEntryBtnStyle.textVertAlign = TVA_Center;
-
-		skin->setStyle(GUIDropDownContent::ENTRY_TOGGLE_STYLE_TYPE, dropDownToggleEntryBtnStyle);
-
-		// DropDown entry button with expand
-		GUIElementStyle dropDownEntryExpBtnStyle;
-		dropDownEntryExpBtnStyle.normal.texture = getGUITexture(DropDownBoxEntryExpNormalTex);
-		dropDownEntryExpBtnStyle.hover.texture = getGUITexture(DropDownBoxEntryExpHoverTex);
-		dropDownEntryExpBtnStyle.active.texture = dropDownEntryExpBtnStyle.hover.texture;
-		dropDownEntryExpBtnStyle.normalOn.texture = dropDownEntryExpBtnStyle.hover.texture;
-		dropDownEntryExpBtnStyle.hoverOn.texture = dropDownEntryExpBtnStyle.hover.texture;
-		dropDownEntryExpBtnStyle.activeOn.texture = dropDownEntryExpBtnStyle.hover.texture;
-		dropDownEntryExpBtnStyle.normal.textColor = TextNormalColor;
-		dropDownEntryExpBtnStyle.hover.textColor = TextNormalColor;
-		dropDownEntryExpBtnStyle.active.textColor = TextNormalColor;
-		dropDownEntryExpBtnStyle.normalOn.textColor = TextNormalColor;
-		dropDownEntryExpBtnStyle.hoverOn.textColor = TextNormalColor;
-		dropDownEntryExpBtnStyle.activeOn.textColor = TextNormalColor;
-		dropDownEntryExpBtnStyle.fixedHeight = true;
-		dropDownEntryExpBtnStyle.fixedWidth = false;
-		dropDownEntryExpBtnStyle.height = 16;
-		dropDownEntryExpBtnStyle.width = 30;
-		dropDownEntryExpBtnStyle.border.right = 13;
-		dropDownEntryExpBtnStyle.font = defaultFont;
-		dropDownEntryExpBtnStyle.fontSize = DefaultFontSize;
-		dropDownEntryExpBtnStyle.textHorzAlign = THA_Left;
-		dropDownEntryExpBtnStyle.textVertAlign = TVA_Center;
-
-		skin->setStyle(GUIDropDownContent::ENTRY_EXP_STYLE_TYPE, dropDownEntryExpBtnStyle);
-
-		// Drop down separator
-		GUIElementStyle dropDownSeparatorStyle;
-		dropDownSeparatorStyle.normal.texture = getGUITexture(DropDownSeparatorTex);
-		dropDownSeparatorStyle.fixedHeight = true;
-		dropDownSeparatorStyle.fixedWidth = false;
-		dropDownSeparatorStyle.height = 3;
-		dropDownSeparatorStyle.width = 30;
-
-		skin->setStyle(GUIDropDownContent::SEPARATOR_STYLE_TYPE, dropDownSeparatorStyle);
-
-		// Drop down content
-		GUIElementStyle dropDownContentStyle;
-		dropDownContentStyle.minWidth = 50;
-		dropDownContentStyle.minHeight = 20;
-		dropDownContentStyle.subStyles[GUIDropDownContent::ENTRY_TOGGLE_STYLE_TYPE] = GUIDropDownContent::ENTRY_TOGGLE_STYLE_TYPE;
-		dropDownContentStyle.subStyles[GUIDropDownContent::ENTRY_STYLE_TYPE] = GUIDropDownContent::ENTRY_STYLE_TYPE;
-		dropDownContentStyle.subStyles[GUIDropDownContent::ENTRY_EXP_STYLE_TYPE] = GUIDropDownContent::ENTRY_EXP_STYLE_TYPE;
-		dropDownContentStyle.subStyles[GUIDropDownContent::SEPARATOR_STYLE_TYPE] = GUIDropDownContent::SEPARATOR_STYLE_TYPE;
-
-		skin->setStyle("ListBoxContent", dropDownContentStyle);
-		skin->setStyle("MenuBarContent", dropDownContentStyle);
-		skin->setStyle("ContextMenuContent", dropDownContentStyle);
-
-		// DropDown box frame
-		GUIElementStyle dropDownBoxStyle;
-		dropDownBoxStyle.normal.texture = getGUITexture(DropDownBoxBgTex);
-		dropDownBoxStyle.hover.texture = dropDownBoxStyle.normal.texture;
-		dropDownBoxStyle.active.texture = dropDownBoxStyle.hover.texture;
-		dropDownBoxStyle.fixedHeight = false;
-		dropDownBoxStyle.fixedWidth = false;
-		dropDownBoxStyle.border.left = 2;
-		dropDownBoxStyle.border.right = 2;
-		dropDownBoxStyle.border.top = 2;
-		dropDownBoxStyle.border.bottom = 4;
-		dropDownBoxStyle.margins.left = 6;
-		dropDownBoxStyle.margins.right = 6;
-		dropDownBoxStyle.margins.top = 4;
-		dropDownBoxStyle.margins.bottom = 6;
-
-		skin->setStyle("ListBoxFrame", dropDownBoxStyle);
-		skin->setStyle("MenuBarFrame", dropDownBoxStyle);
-		skin->setStyle("ContextMenuFrame", dropDownBoxStyle);
-
-		/************************************************************************/
-		/* 								MENU BAR	                     		*/
-		/************************************************************************/
-
-		// MenuBar background
-		GUIElementStyle menuBarBgStyle;
-		menuBarBgStyle.normal.texture = getGUITexture(MenuBarBgTex);
-		menuBarBgStyle.height = 14;
-		menuBarBgStyle.width = 2;
-		menuBarBgStyle.border.bottom = 2;
-
-		skin->setStyle(GUIMenuBar::getBackgroundStyleType(), menuBarBgStyle);
-
-		// MenuBar separator line
-		GUIElementStyle menuBarLineStyle;
-		menuBarLineStyle.normal.texture = getGUITexture(MenuBarLineNormalTex);
-		menuBarLineStyle.normalOn.texture = getGUITexture(MenuBarLineActiveTex);
-		menuBarLineStyle.fixedHeight = true;
-		menuBarLineStyle.height = 1;
-
-		skin->setStyle(GUIMenuBar::getLineStyleType(), menuBarLineStyle);
-
-		// MenuBar Banshee logo
-		GUIElementStyle menuBarBansheeLogoStyle;
-		menuBarBansheeLogoStyle.normal.texture = getGUITexture(MenuBarBansheeLogoTex);
-		menuBarBansheeLogoStyle.fixedHeight = true;
-		menuBarBansheeLogoStyle.fixedWidth = true;
-		menuBarBansheeLogoStyle.height = 46;
-		menuBarBansheeLogoStyle.width = 46;
-
-		skin->setStyle(GUIMenuBar::getLogoStyleType(), menuBarBansheeLogoStyle);
-
-		// MenuBar button
-		GUIElementStyle menuBarBtnStyle;
-		menuBarBtnStyle.normal.texture = getGUITexture(MenuBarBtnNormalTex);
-		menuBarBtnStyle.hover.texture = getGUITexture(MenuBarBtnHoverTex);
-		menuBarBtnStyle.active.texture = getGUITexture(MenuBarBtnActiveTex);
-		menuBarBtnStyle.normalOn.texture = menuBarBtnStyle.active.texture;
-		menuBarBtnStyle.hoverOn.texture = menuBarBtnStyle.active.texture;
-		menuBarBtnStyle.activeOn.texture = menuBarBtnStyle.active.texture;
-		menuBarBtnStyle.normal.textColor = TextNormalColor;
-		menuBarBtnStyle.hover.textColor = TextNormalColor;
-		menuBarBtnStyle.active.textColor = TextActiveColor;
-		menuBarBtnStyle.normalOn.textColor = TextActiveColor;
-		menuBarBtnStyle.hoverOn.textColor = TextActiveColor;
-		menuBarBtnStyle.activeOn.textColor = TextActiveColor;
-		menuBarBtnStyle.fixedHeight = true;
-		menuBarBtnStyle.fixedWidth = false;
-		menuBarBtnStyle.height = 14;
-		menuBarBtnStyle.width = 4;
-		menuBarBtnStyle.margins.left = 2;
-		menuBarBtnStyle.margins.right = 2;
-		menuBarBtnStyle.margins.top = 2;
-		menuBarBtnStyle.margins.bottom = 2;
-		menuBarBtnStyle.font = defaultFont;
-		menuBarBtnStyle.fontSize = DefaultFontSize;
-		menuBarBtnStyle.textHorzAlign = THA_Left;
-		menuBarBtnStyle.textVertAlign = TVA_Top;
-
-		skin->setStyle(GUIMenuBar::getMenuItemButtonStyleType(), menuBarBtnStyle);
-
-		// ToolBar separator
-		GUIElementStyle toolBarSeparator;
-		toolBarSeparator.normal.texture = getGUITexture(ToolBarSeparatorTex);
-		toolBarSeparator.fixedWidth = true;
-		toolBarSeparator.width = 3;
-		toolBarSeparator.height = 32;
-
-		skin->setStyle(GUIMenuBar::getToolBarSeparatorStyleType(), toolBarSeparator);
-
-		// ToolBar button
-		GUIElementStyle toolBarBtnStyle;
-		toolBarBtnStyle.normal.texture = getGUITexture(ToolBarBtnNormalTex);
-		toolBarBtnStyle.hover.texture = getGUITexture(ToolBarBtnHoverTex);
-		toolBarBtnStyle.active.texture = getGUITexture(ToolBarBtnActiveTex);
-		toolBarBtnStyle.normalOn.texture = getGUITexture(ToolBarBtnActiveTex);
-		toolBarBtnStyle.hoverOn.texture = getGUITexture(ToolBarBtnActiveTex);
-		toolBarBtnStyle.activeOn.texture = getGUITexture(ToolBarBtnActiveTex);
-		toolBarBtnStyle.normal.textColor = TextNormalColor;
-		toolBarBtnStyle.hover.textColor = TextNormalColor;
-		toolBarBtnStyle.active.textColor = TextActiveColor;
-		toolBarBtnStyle.normalOn.textColor = TextNormalColor;
-		toolBarBtnStyle.hoverOn.textColor = TextNormalColor;
-		toolBarBtnStyle.activeOn.textColor = TextActiveColor;
-		toolBarBtnStyle.fixedHeight = true;
-		toolBarBtnStyle.fixedWidth = true;
-		toolBarBtnStyle.height = 32;
-		toolBarBtnStyle.width = 32;
-
-		skin->setStyle(GUIMenuBar::getToolBarButtonStyleType(), toolBarBtnStyle);
-
-		/************************************************************************/
-		/* 								DOCK SLIDER	                     		*/
-		/************************************************************************/
-
-		GUIElementStyle dockSliderBtnStyle;
-		dockSliderBtnStyle.normal.texture = getGUITexture(DockSliderNormalTex);
-		dockSliderBtnStyle.hover.texture = dockSliderBtnStyle.normal.texture;
-		dockSliderBtnStyle.active.texture = dockSliderBtnStyle.normal.texture;
-		dockSliderBtnStyle.fixedHeight = false;
-		dockSliderBtnStyle.fixedWidth = false;
-		dockSliderBtnStyle.height = 2;
-		dockSliderBtnStyle.width = 2;
-
-		skin->setStyle("DockSliderBtn", dockSliderBtnStyle);
-
-		/************************************************************************/
-		/* 								TREE VIEW	                     		*/
-		/************************************************************************/
-
-		// Expand button
-		GUIElementStyle treeViewExpandButtonStyle;
-		treeViewExpandButtonStyle.normal.texture = getGUITexture(TreeViewExpandButtonOffNormal);
-		treeViewExpandButtonStyle.hover.texture = getGUITexture(TreeViewExpandButtonOffHover);
-		treeViewExpandButtonStyle.active.texture = treeViewExpandButtonStyle.hover.texture;
-		treeViewExpandButtonStyle.normalOn.texture = getGUITexture(TreeViewExpandButtonOnNormal);
-		treeViewExpandButtonStyle.hoverOn.texture = getGUITexture(TreeViewExpandButtonOnHover);
-		treeViewExpandButtonStyle.activeOn.texture = treeViewExpandButtonStyle.hoverOn.texture;
-		treeViewExpandButtonStyle.fixedHeight = true;
-		treeViewExpandButtonStyle.fixedWidth = true;
-		treeViewExpandButtonStyle.height = 10;
-		treeViewExpandButtonStyle.width = 10;
-
-		skin->setStyle("TreeViewFoldoutBtn", treeViewExpandButtonStyle);
-
-		// Entry
-		GUIElementStyle treeViewEntryStyle;
-		treeViewEntryStyle.font = defaultFont;
-		treeViewEntryStyle.fontSize = DefaultFontSize;
-		treeViewEntryStyle.fixedWidth = false;
-		treeViewEntryStyle.fixedHeight = true;
-		treeViewEntryStyle.height = 16;
-		treeViewEntryStyle.minWidth = 10;
-		treeViewEntryStyle.normal.textColor = TextNormalColor;
-
-		skin->setStyle("TreeViewElementBtn", treeViewEntryStyle);
-
-		// Background
-		GUIElementStyle treeViewBackgroundStyle;
-
-		skin->setStyle("TreeViewBackground", treeViewBackgroundStyle);
-
-		// Selection background
-		GUIElementStyle treeViewSelBackgroundStyle;
-		treeViewSelBackgroundStyle.normal.texture = getGUITexture(SelectionBgTex);
-		treeViewSelBackgroundStyle.fixedHeight = false;
-		treeViewSelBackgroundStyle.fixedWidth = false;
-		treeViewSelBackgroundStyle.height = 2;
-		treeViewSelBackgroundStyle.width = 2;
-
-		skin->setStyle("TreeViewSelectionBackground", treeViewSelBackgroundStyle);
-
-		// Highlight background
-		GUIElementStyle treeViewHLBackgroundStyle;
-		treeViewHLBackgroundStyle.normal.texture = getGUITexture(TreeViewHighlightBackground);
-		treeViewHLBackgroundStyle.fixedHeight = false;
-		treeViewHLBackgroundStyle.fixedWidth = false;
-		treeViewHLBackgroundStyle.height = 2;
-		treeViewHLBackgroundStyle.width = 2;
-
-		skin->setStyle("TreeViewHighlightBackground", treeViewHLBackgroundStyle);
-
-		// Edit box
-		GUIElementStyle treeViewEditBox;
-		treeViewEditBox.normal.texture = getGUITexture(TreeViewEditBox);
-		treeViewEditBox.hover.texture = treeViewEditBox.normal.texture;
-		treeViewEditBox.focused.texture = treeViewEditBox.normal.texture;
-		treeViewEditBox.active.texture = treeViewEditBox.normal.texture;
-		treeViewEditBox.normal.textColor = TextNormalColor;
-		treeViewEditBox.hover.textColor = TextNormalColor;
-		treeViewEditBox.focused.textColor = TextNormalColor;
-		treeViewEditBox.active.textColor = TextNormalColor;
-		treeViewEditBox.border.left = 1;
-		treeViewEditBox.border.right = 1;
-		treeViewEditBox.border.top = 1;
-		treeViewEditBox.border.bottom = 1;
-		treeViewEditBox.margins.left = 1;
-		treeViewEditBox.margins.right = 1;
-		treeViewEditBox.margins.top = 1;
-		treeViewEditBox.margins.bottom = 1;
-		treeViewEditBox.fixedHeight = true;
-		treeViewEditBox.height = 13;
-		treeViewEditBox.minWidth = 10;
-		treeViewEditBox.font = defaultFont;
-		treeViewEditBox.fontSize = DefaultFontSize;
-		treeViewEditBox.textHorzAlign = THA_Left;
-		treeViewEditBox.textVertAlign = TVA_Top;
-
-		skin->setStyle(GUITreeViewEditBox::getGUITypeName(), treeViewEditBox);
-
-		// Element highlight
-		GUIElementStyle treeViewElementHighlight;
-		treeViewElementHighlight.normal.texture = getGUITexture(TreeViewElementHighlight);
-		treeViewElementHighlight.border.left = 1;
-		treeViewElementHighlight.border.right = 1;
-		treeViewElementHighlight.border.top = 1;
-		treeViewElementHighlight.border.bottom = 1;
-
-		skin->setStyle("TreeViewElementHighlight", treeViewElementHighlight);
-
-		// Element separator highlight
-		GUIElementStyle treeViewElementSepHighlight;
-		treeViewElementSepHighlight.normal.texture = getGUITexture(TreeViewElementSepHighlight);
-		treeViewElementSepHighlight.border.left = 1;
-		treeViewElementSepHighlight.border.right = 1;
-		treeViewElementSepHighlight.border.top = 1;
-		treeViewElementSepHighlight.border.bottom = 1;
-
-		skin->setStyle("TreeViewElementSepHighlight", treeViewElementSepHighlight);
-
-		/************************************************************************/
-		/* 							OBJECT DROP FIELD                      		*/
-		/************************************************************************/
-		GUIElementStyle objectDropStyle;
-		objectDropStyle.normal.texture = getGUITexture(ObjectDropBtnNormalTex);
-		objectDropStyle.normalOn.texture = getGUITexture(ObjectDropBtnNormalOnTex);
-		objectDropStyle.hover.texture = objectDropStyle.normal.texture;
-		objectDropStyle.hoverOn.texture = objectDropStyle.normalOn.texture;
-		objectDropStyle.active.texture = objectDropStyle.normal.texture;
-		objectDropStyle.activeOn.texture = objectDropStyle.normalOn.texture;
-		objectDropStyle.normal.textColor = TextNormalColor;
-		objectDropStyle.hover.textColor = TextNormalColor;
-		objectDropStyle.active.textColor = TextNormalColor;
-		objectDropStyle.normalOn.textColor = TextNormalColor;
-		objectDropStyle.hoverOn.textColor = TextNormalColor;
-		objectDropStyle.activeOn.textColor = TextNormalColor;
-		objectDropStyle.border.left = 2;
-		objectDropStyle.border.top = 2;
-		objectDropStyle.border.bottom = 4;
-		objectDropStyle.contentOffset.left = 3;
-		objectDropStyle.contentOffset.right = 1;
-		objectDropStyle.margins.bottom = 2;
-		objectDropStyle.fixedHeight = true;
-		objectDropStyle.height = 21;
-		objectDropStyle.minWidth = 20;
-		objectDropStyle.font = defaultFont;
-		objectDropStyle.fontSize = DefaultFontSize;
-		objectDropStyle.textHorzAlign = THA_Center;
-		objectDropStyle.textVertAlign = TVA_Center;
-
-		skin->setStyle(ObjectFieldDropBtnStyleName, objectDropStyle);
-
-		GUIElementStyle objectClearBtnStyle;
-		objectClearBtnStyle.normal.texture = getGUITexture(ObjectClearBtnNormalTex);
-		objectClearBtnStyle.hover.texture = getGUITexture(ObjectClearBtnHoverTex);
-		objectClearBtnStyle.active.texture = getGUITexture(ObjectClearBtnActiveTex);
-		objectClearBtnStyle.fixedHeight = true;
-		objectClearBtnStyle.fixedWidth = true;
-		objectClearBtnStyle.height = 21;
-		objectClearBtnStyle.width = 16;
-		objectClearBtnStyle.margins.bottom = 2;
-
-		skin->setStyle(ObjectFieldClearBtnStyleName, objectClearBtnStyle);
-
-		GUIElementStyle editorObjectFieldStyle;
-		editorObjectFieldStyle.fixedHeight = true;
-		editorObjectFieldStyle.height = 21;
-		editorObjectFieldStyle.minWidth = 30;
-		editorObjectFieldStyle.subStyles[ObjectFieldLabelStyleName] = GUITextField::getLabelStyleType();
-		editorObjectFieldStyle.subStyles[ObjectFieldDropBtnStyleName] = ObjectFieldDropBtnStyleName;
-		editorObjectFieldStyle.subStyles[ObjectFieldClearBtnStyleName] = ObjectFieldClearBtnStyleName;
-
-		skin->setStyle(ObjectFieldStyleName, editorObjectFieldStyle);
-
-		/************************************************************************/
-		/* 						TEXTURE DROP FIELD                      		*/
-		/************************************************************************/
-		GUIElementStyle textureFieldStyle;
-		textureFieldStyle.minHeight = 15;
-		textureFieldStyle.minWidth = 15;
-		textureFieldStyle.subStyles[TextureFieldDropStyleName] = TextureFieldDropStyleName;
-		textureFieldStyle.subStyles[TextureFieldClearBtnStyleName] = TextureFieldClearBtnStyleName;
-		textureFieldStyle.subStyles[TextureFieldLabelStyleName] = GUITextField::getLabelStyleType();
-
-		skin->setStyle(TextureFieldStyleName, textureFieldStyle);
-
-		GUIElementStyle textureDropStyle;
-		textureDropStyle.font = defaultFont;
-		textureDropStyle.fontSize = DefaultFontSize;
-		textureDropStyle.textHorzAlign = THA_Center;
-		textureDropStyle.textVertAlign = TVA_Center;
-		textureDropStyle.normal.textColor = Color(95 / 255.0f, 95 / 255.0f, 95 / 255.0f, 1.0f);
-		textureDropStyle.normal.texture = getGUITexture(TextureDropTex);
-		textureDropStyle.hover.textColor = textureDropStyle.normal.textColor;
-		textureDropStyle.hover.texture = textureDropStyle.normal.texture;
-		textureDropStyle.active.textColor = textureDropStyle.normal.textColor;
-		textureDropStyle.active.texture = textureDropStyle.normal.texture;
-		textureDropStyle.normalOn.textColor = Color(95 / 255.0f, 95 / 255.0f, 95 / 255.0f, 1.0f);
-		textureDropStyle.normalOn.texture = getGUITexture(TextureDropOnTex);
-		textureDropStyle.hoverOn.textColor = textureDropStyle.normalOn.textColor;
-		textureDropStyle.hoverOn.texture = textureDropStyle.normalOn.texture;
-		textureDropStyle.activeOn.textColor = textureDropStyle.normalOn.textColor;
-		textureDropStyle.activeOn.texture = textureDropStyle.normalOn.texture;
-		textureDropStyle.height = 84;
-		textureDropStyle.width = 82;
-		textureDropStyle.fixedHeight = true;
-		textureDropStyle.fixedWidth = true;
-		textureDropStyle.border.left = 2;
-		textureDropStyle.border.right = 2;
-		textureDropStyle.border.top = 2;
-		textureDropStyle.border.bottom = 4;
-		textureDropStyle.contentOffset.left = 4;
-		textureDropStyle.contentOffset.right = 4;
-		textureDropStyle.contentOffset.top = 4;
-		textureDropStyle.contentOffset.bottom = 4;
-
-		skin->setStyle(TextureFieldDropStyleName, textureDropStyle);
-		
-		GUIElementStyle textureDropClearStyle;
-		textureDropClearStyle.normal.texture = getGUITexture(XButtonNormalTex);
-		textureDropClearStyle.hover.texture = getGUITexture(XButtonHoverTex);
-		textureDropClearStyle.active.texture = getGUITexture(XButtonActiveTex);
-		textureDropClearStyle.fixedWidth = true;
-		textureDropClearStyle.fixedHeight = true;
-		textureDropClearStyle.height = 10;
-		textureDropClearStyle.width = 10;
-
-		skin->setStyle(TextureFieldClearBtnStyleName, textureDropClearStyle);
-
-		/************************************************************************/
-		/* 								EDITOR FIELDS                      		*/
-		/************************************************************************/
-
-		GUIElementStyle editorFieldLabelStyle;
-		editorFieldLabelStyle.font = defaultFont;
-		editorFieldLabelStyle.fontSize = DefaultFontSize;
-		editorFieldLabelStyle.normal.textColor = TextNormalColor;
-		editorFieldLabelStyle.fixedWidth = false;
-		editorFieldLabelStyle.fixedHeight = true;
-		editorFieldLabelStyle.height = 14;
-		editorFieldLabelStyle.minWidth = 10;
-		editorFieldLabelStyle.textHorzAlign = THA_Left;
-
-		skin->setStyle(GUITextField::getLabelStyleType(), editorFieldLabelStyle);
-
-		GUIElementStyle editorIntFieldStyle;
-		editorIntFieldStyle.fixedHeight = true;
-		editorIntFieldStyle.height = 21;
-		editorIntFieldStyle.minWidth = 30;
-		editorIntFieldStyle.subStyles[GUIIntField::getLabelStyleType()] = GUITextField::getLabelStyleType();
-		editorIntFieldStyle.subStyles[GUIIntField::getInputStyleType()] = GUIInputBox::getGUITypeName();
-
-		skin->setStyle(GUIIntField::getGUITypeName(), editorIntFieldStyle);
-
-		GUIElementStyle editorFloatFieldStyle;
-		editorFloatFieldStyle.fixedHeight = true;
-		editorFloatFieldStyle.height = 21;
-		editorFloatFieldStyle.minWidth = 30;
-		editorFloatFieldStyle.subStyles[GUIFloatField::getLabelStyleType()] = GUITextField::getLabelStyleType();
-		editorFloatFieldStyle.subStyles[GUIFloatField::getInputStyleType()] = GUIInputBox::getGUITypeName();
-
-		skin->setStyle(GUIFloatField::getGUITypeName(), editorFloatFieldStyle);
-
-		GUIElementStyle editorTextFieldStyle;
-		editorTextFieldStyle.fixedHeight = true;
-		editorTextFieldStyle.height = 21;
-		editorTextFieldStyle.minWidth = 30;
-		editorTextFieldStyle.subStyles[GUITextField::getLabelStyleType()] = GUITextField::getLabelStyleType();
-		editorTextFieldStyle.subStyles[GUITextField::getInputStyleType()] = GUIInputBox::getGUITypeName();
-
-		skin->setStyle(GUITextField::getGUITypeName(), editorTextFieldStyle);
-
-		GUIElementStyle editorColorFieldStyle;
-		editorColorFieldStyle.fixedHeight = true;
-		editorColorFieldStyle.height = 21;
-		editorColorFieldStyle.minWidth = 30;
-		editorColorFieldStyle.subStyles[GUIColorField::getLabelStyleType()] = GUITextField::getLabelStyleType();
-		editorColorFieldStyle.subStyles[GUIColorField::getColorInputStyleType()] = GUIColor::getGUITypeName();
-
-		skin->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();
-
-		skin->setStyle(GUIToggleField::getGUITypeName(), editorToggleFieldStyle);
-
-		GUIElementStyle editorVector2FieldStyle;
-		editorVector2FieldStyle.fixedHeight = true;
-		editorVector2FieldStyle.height = 35;
-		editorVector2FieldStyle.minWidth = 30;
-		editorVector2FieldStyle.subStyles[GUIVector2Field::getLabelStyleType()] = GUITextField::getLabelStyleType();
-		editorVector2FieldStyle.subStyles[GUIVector2Field::getFloatFieldStyleType()] = GUIFloatField::getGUITypeName();
-
-		skin->setStyle(GUIVector2Field::getGUITypeName(), editorVector2FieldStyle);
-
-		GUIElementStyle editorVector3FieldStyle;
-		editorVector3FieldStyle.fixedHeight = true;
-		editorVector3FieldStyle.height = 35;
-		editorVector3FieldStyle.minWidth = 30;
-		editorVector3FieldStyle.subStyles[GUIVector3Field::getLabelStyleType()] = GUITextField::getLabelStyleType();
-		editorVector3FieldStyle.subStyles[GUIVector3Field::getFloatFieldStyleType()] = GUIFloatField::getGUITypeName();
-
-		skin->setStyle(GUIVector3Field::getGUITypeName(), editorVector3FieldStyle);
-
-		GUIElementStyle editorVector4FieldStyle;
-		editorVector4FieldStyle.fixedHeight = true;
-		editorVector4FieldStyle.height = 35;
-		editorVector4FieldStyle.minWidth = 30;
-		editorVector4FieldStyle.subStyles[GUIVector4Field::getLabelStyleType()] = GUITextField::getLabelStyleType();
-		editorVector4FieldStyle.subStyles[GUIVector4Field::getFloatFieldStyleType()] = GUIFloatField::getGUITypeName();
-
-		skin->setStyle(GUIVector4Field::getGUITypeName(), editorVector4FieldStyle);
-
-		GUIElementStyle editorListBoxFieldStyle;
-		editorListBoxFieldStyle.fixedHeight = true;
-		editorListBoxFieldStyle.height = 21;
-		editorListBoxFieldStyle.minWidth = 30;
-		editorListBoxFieldStyle.subStyles[GUIListBoxField::getLabelStyleType()] = GUIListBoxField::getLabelStyleType();
-		editorListBoxFieldStyle.subStyles[GUIListBoxField::getListBoxStyleType()] = GUIListBox::getGUITypeName();
-
-		skin->setStyle(GUIListBoxField::getGUITypeName(), editorListBoxFieldStyle);
-
-		GUIElementStyle editorSliderFieldStyle;
-		editorSliderFieldStyle.fixedHeight = true;
-		editorSliderFieldStyle.height = 21;
-		editorSliderFieldStyle.minWidth = 30;
-		editorSliderFieldStyle.subStyles[GUISliderField::getLabelStyleType()] = GUISliderField::getLabelStyleType();
-		editorSliderFieldStyle.subStyles[GUISliderField::getInputStyleType()] = GUIInputBox::getGUITypeName();
-		editorSliderFieldStyle.subStyles[GUISliderField::getSliderStyleType()] = GUISliderHorz::getGUITypeName();
-
-		skin->setStyle(GUISliderField::getGUITypeName(), editorSliderFieldStyle);
-
-		/************************************************************************/
-		/* 							     FOLDOUT                      		    */
-		/************************************************************************/
-
-		GUIElementStyle foldoutStyle;
-		foldoutStyle.normal.texture = getGUITexture(FoldoutClosedNormalTex);
-		foldoutStyle.hover.texture = getGUITexture(FoldoutClosedHoverTex);
-		foldoutStyle.active.texture = getGUITexture(FoldoutOpenActiveTex);
-		foldoutStyle.normalOn.texture = getGUITexture(FoldoutOpenNormalTex);
-		foldoutStyle.hoverOn.texture = getGUITexture(FoldoutOpenHoverTex);
-		foldoutStyle.activeOn.texture = getGUITexture(FoldoutOpenActiveTex);
-		foldoutStyle.normal.textColor = TextNormalColor;
-		foldoutStyle.hover.textColor = TextNormalColor;
-		foldoutStyle.active.textColor = TextNormalColor;
-		foldoutStyle.normalOn.textColor = TextNormalColor;
-		foldoutStyle.hoverOn.textColor = TextNormalColor;
-		foldoutStyle.activeOn.textColor = TextNormalColor;
-		foldoutStyle.fixedHeight = true;
-		foldoutStyle.fixedWidth = false;
-		foldoutStyle.height = 21;
-		foldoutStyle.minWidth = 17;
-		foldoutStyle.font = defaultFont;
-		foldoutStyle.fontSize = DefaultFontSize;
-		foldoutStyle.textHorzAlign = THA_Left;
-		foldoutStyle.textVertAlign = TVA_Center;
-		foldoutStyle.contentOffset = RectOffset(16, 0, 0, 0);
-		foldoutStyle.border.left = 15;
-		foldoutStyle.border.right = 2;
-		foldoutStyle.border.top = 2;
-		foldoutStyle.border.bottom = 4;
-
-		skin->setStyle("Foldout", foldoutStyle);
-
-		/************************************************************************/
-		/* 								PROGRESS BAR                      		*/
-		/************************************************************************/
-		GUIElementStyle progressBarBgStyle;
-		progressBarBgStyle.fixedHeight = true;
-		progressBarBgStyle.height = 17;
-		progressBarBgStyle.normal.texture = getGUITexture(ProgressBarBgTex);
-		progressBarBgStyle.border.left = 8;
-		progressBarBgStyle.border.right = 8;
-
-		skin->setStyle(GUIProgressBar::getBackgroundStyleType(), progressBarBgStyle);
-
-		GUIElementStyle progressBarFillStyle;
-		progressBarFillStyle.fixedHeight = true;
-		progressBarFillStyle.height = 16;
-		progressBarFillStyle.normal.texture = getGUITexture(ProgressBarFillTex);
-		progressBarFillStyle.border.left = 9;
-		progressBarFillStyle.border.right = 10;
-
-		skin->setStyle(GUIProgressBar::getBarStyleType(), progressBarFillStyle);
-
-		GUIElementStyle progressBarStyle;
-		progressBarStyle.fixedHeight = true;
-		progressBarStyle.height = 17;
-		progressBarStyle.minWidth = 100;
-
-		progressBarStyle.subStyles[GUIProgressBar::getBarStyleType()] = GUIProgressBar::getBarStyleType();
-		progressBarStyle.subStyles[GUIProgressBar::getBackgroundStyleType()] = GUIProgressBar::getBackgroundStyleType();
-
-		skin->setStyle(GUIProgressBar::getGUITypeName(), progressBarStyle);
-
-		/************************************************************************/
-		/* 								SLIDER                      			*/
-		/************************************************************************/
-
-		GUIElementStyle sliderHandleStyle;
-		sliderHandleStyle.fixedHeight = true;
-		sliderHandleStyle.fixedWidth = true;
-		sliderHandleStyle.width = 12;
-		sliderHandleStyle.height = 13;
-		sliderHandleStyle.normal.texture = getGUITexture(SliderHandleNormalTex);
-		sliderHandleStyle.hover.texture = getGUITexture(SliderHandleHoverTex);
-		sliderHandleStyle.active.texture = getGUITexture(SliderHandleActiveTex);
-
-		skin->setStyle(GUISlider::getHandleStyleType(), sliderHandleStyle);
-
-		GUIElementStyle sliderHorizontalBgStyle;
-		sliderHorizontalBgStyle.fixedHeight = true;
-		sliderHorizontalBgStyle.height = 10;
-		sliderHorizontalBgStyle.normal.texture = getGUITexture(SliderHBackgroundTex);
-		sliderHorizontalBgStyle.border.left = 4;
-		sliderHorizontalBgStyle.border.right = 4;
-
-		skin->setStyle("SliderHorzBg", sliderHorizontalBgStyle);
-
-		GUIElementStyle sliderHorizontalFillStyle;
-		sliderHorizontalFillStyle.fixedHeight = true;
-		sliderHorizontalFillStyle.height = 10;
-		sliderHorizontalFillStyle.normal.texture = getGUITexture(SliderHFillTex);
-		sliderHorizontalFillStyle.border.left = 6;
-		sliderHorizontalFillStyle.border.right = 4;
-
-		skin->setStyle("SliderHorzFill", sliderHorizontalFillStyle);
-
-		GUIElementStyle sliderHorizontalStyle;
-		sliderHorizontalStyle.fixedHeight = true;
-		sliderHorizontalStyle.height = 13;
-		sliderHorizontalStyle.width = 150;
-		sliderHorizontalStyle.minWidth = 10;
-		sliderHorizontalStyle.subStyles[GUISlider::getHandleStyleType()] = GUISlider::getHandleStyleType();
-		sliderHorizontalStyle.subStyles[GUISlider::getBackgroundStyleType()] = "SliderHorzBg";
-		sliderHorizontalStyle.subStyles[GUISlider::getFillStyleType()] = "SliderHorzFill";
-
-		skin->setStyle(GUISliderHorz::getGUITypeName(), sliderHorizontalStyle);
-
-		GUIElementStyle sliderVerticalBgStyle;
-		sliderVerticalBgStyle.fixedWidth = true;
-		sliderVerticalBgStyle.width = 10;
-		sliderVerticalBgStyle.normal.texture = getGUITexture(SliderVBackgroundTex);
-		sliderVerticalBgStyle.border.top = 4;
-		sliderVerticalBgStyle.border.bottom = 4;
-
-		skin->setStyle("SliderVertBg", sliderVerticalBgStyle);
-
-		GUIElementStyle sliderVerticalFillStyle;
-		sliderVerticalFillStyle.fixedWidth = true;
-		sliderVerticalFillStyle.width = 10;
-		sliderVerticalFillStyle.normal.texture = getGUITexture(SliderVFillTex);
-		sliderVerticalFillStyle.border.top = 6;
-		sliderVerticalFillStyle.border.bottom = 4;
-
-		skin->setStyle("SliderVertFill", sliderVerticalFillStyle);
-
-		GUIElementStyle sliderVerticalStyle;
-		sliderVerticalStyle.fixedWidth = true;
-		sliderVerticalStyle.width = 13;
-		sliderVerticalStyle.height = 150;
-		sliderVerticalStyle.minHeight = 10;
-		sliderVerticalStyle.subStyles[GUISlider::getHandleStyleType()] = GUISlider::getHandleStyleType();
-		sliderVerticalStyle.subStyles[GUISlider::getBackgroundStyleType()] = "SliderVertBg";
-		sliderVerticalStyle.subStyles[GUISlider::getFillStyleType()] = "SliderVertFill";
-
-		skin->setStyle(GUISliderVert::getGUITypeName(), sliderVerticalStyle);
-
-		/************************************************************************/
-		/* 							COLOR PICKER SLIDER                      	*/
-		/************************************************************************/
-
-		GUIElementStyle colorPickerSliderHorzHandleStyle;
-		colorPickerSliderHorzHandleStyle.fixedHeight = true;
-		colorPickerSliderHorzHandleStyle.fixedWidth = true;
-		colorPickerSliderHorzHandleStyle.height = 20;
-		colorPickerSliderHorzHandleStyle.width = 7;
-		colorPickerSliderHorzHandleStyle.normal.texture = getGUITexture(ColorPickerSliderHorzHandleTex);
-		colorPickerSliderHorzHandleStyle.hover.texture = colorPickerSliderHorzHandleStyle.normal.texture;
-		colorPickerSliderHorzHandleStyle.active.texture = colorPickerSliderHorzHandleStyle.normal.texture;
-
-		skin->setStyle("ColorSliderHorzHandle", colorPickerSliderHorzHandleStyle);
-
-		GUIElementStyle colorPickerSliderHorzStyle;
-		colorPickerSliderHorzStyle.fixedHeight = true;
-		colorPickerSliderHorzStyle.height = 32;
-		colorPickerSliderHorzStyle.minWidth = 20;
-		colorPickerSliderHorzStyle.subStyles[GUISlider::getHandleStyleType()] = "ColorSliderHorzHandle";
-
-		skin->setStyle("ColorSliderHorz", colorPickerSliderHorzStyle);
-
-		GUIElementStyle colorPickerSliderVertHandleStyle;
-		colorPickerSliderVertHandleStyle.fixedHeight = true;
-		colorPickerSliderVertHandleStyle.fixedWidth = true;
-		colorPickerSliderVertHandleStyle.height = 7;
-		colorPickerSliderVertHandleStyle.width = 45;
-		colorPickerSliderVertHandleStyle.normal.texture = getGUITexture(ColorPickerSliderVertHandleTex);
-		colorPickerSliderVertHandleStyle.hover.texture = colorPickerSliderVertHandleStyle.normal.texture;
-		colorPickerSliderVertHandleStyle.active.texture = colorPickerSliderVertHandleStyle.normal.texture;
-
-		skin->setStyle("ColorSliderVertHandle", colorPickerSliderVertHandleStyle);
-
-		GUIElementStyle colorPickerSliderVertStyle;
-		colorPickerSliderVertStyle.fixedWidth = true;
-		colorPickerSliderVertStyle.width = 30;
-		colorPickerSliderVertStyle.minHeight = 20;
-		colorPickerSliderVertStyle.subStyles[GUISlider::getHandleStyleType()] = "ColorSliderVertHandle";
-
-		skin->setStyle("ColorSliderVert", colorPickerSliderVertStyle);
-
-		GUIElementStyle colorPickerSlider2DHandleStyle;
-		colorPickerSlider2DHandleStyle.fixedHeight = true;
-		colorPickerSlider2DHandleStyle.fixedWidth = true;
-		colorPickerSlider2DHandleStyle.height = 7;
-		colorPickerSlider2DHandleStyle.width = 7;
-		colorPickerSlider2DHandleStyle.normal.texture = getGUITexture(ColorPickerSlider2DHandleTex);
-		colorPickerSlider2DHandleStyle.hover.texture = colorPickerSlider2DHandleStyle.normal.texture;
-		colorPickerSlider2DHandleStyle.active.texture = colorPickerSlider2DHandleStyle.normal.texture;
-
-		skin->setStyle("ColorSlider2DHandle", colorPickerSlider2DHandleStyle);
-
-		/************************************************************************/
-		/* 								STATUS BAR                      		*/
-		/************************************************************************/
-		GUIElementStyle statusBarBgStyle;
-		statusBarBgStyle.height = 16;
-		statusBarBgStyle.border.top = 2;
-		statusBarBgStyle.normal.texture = getGUITexture(StatusBarBgTex);
-
-		skin->setStyle(GUIStatusBar::getGUIBackgroundTypeName(), statusBarBgStyle);
-
-		GUIElementStyle statusBarMessageBtnStyle;
-		statusBarMessageBtnStyle.font = defaultFont;
-		statusBarMessageBtnStyle.fontSize = DefaultFontSize;
-		statusBarMessageBtnStyle.fixedHeight = true;
-		statusBarMessageBtnStyle.height = 16;
-		statusBarMessageBtnStyle.minWidth = 10;
-		statusBarMessageBtnStyle.textHorzAlign = THA_Left;
-		statusBarMessageBtnStyle.textVertAlign = TVA_Center;
-		statusBarMessageBtnStyle.imagePosition = GUIImagePosition::Left;
-
-		skin->setStyle(GUIStatusBar::getGUIMessageTypeName(), statusBarMessageBtnStyle);
-
-		GUIElementStyle statusBarStyle;
-		statusBarStyle.height = 16;
-
-		statusBarStyle.subStyles[GUIStatusBar::getGUIBackgroundTypeName()] = GUIStatusBar::getGUIBackgroundTypeName();
-		statusBarStyle.subStyles[GUIStatusBar::getGUIMessageTypeName()] = GUIStatusBar::getGUIMessageTypeName();
-
-		skin->setStyle(GUIStatusBar::getGUITypeName(), statusBarStyle);
-
-		/************************************************************************/
-		/* 									OTHER                      			*/
-		/************************************************************************/
-
-		// Centered label
-		GUIElementStyle centeredLabelStyle;
-		centeredLabelStyle.font = defaultFont;
-		centeredLabelStyle.fontSize = DefaultFontSize;
-		centeredLabelStyle.fixedWidth = false;
-		centeredLabelStyle.fixedHeight = true;
-		centeredLabelStyle.height = 11;
-		centeredLabelStyle.minWidth = 10;
-		centeredLabelStyle.textHorzAlign = THA_Center;
-		centeredLabelStyle.normal.textColor = TextNormalColor;
-
-		skin->setStyle("LabelCentered", centeredLabelStyle);
-
-		// Right-aligned label
-		GUIElementStyle rightAlignedLabelStyle;
-		rightAlignedLabelStyle.font = defaultFont;
-		rightAlignedLabelStyle.fontSize = DefaultFontSize;
-		rightAlignedLabelStyle.fixedWidth = false;
-		rightAlignedLabelStyle.fixedHeight = true;
-		rightAlignedLabelStyle.height = 11;
-		rightAlignedLabelStyle.minWidth = 10;
-		rightAlignedLabelStyle.textHorzAlign = THA_Right;
-		rightAlignedLabelStyle.normal.textColor = TextNormalColor;
-
-		skin->setStyle("RightAlignedLabel", rightAlignedLabelStyle);
-
-		// Multi-line label
-		GUIElementStyle multiLinelabelStyle;
-		multiLinelabelStyle.font = defaultFont;
-		multiLinelabelStyle.fontSize = DefaultFontSize;
-		multiLinelabelStyle.fixedWidth = false;
-		multiLinelabelStyle.fixedHeight = true;
-		multiLinelabelStyle.height = 11;
-		multiLinelabelStyle.minWidth = 10;
-		multiLinelabelStyle.wordWrap = true;
-		multiLinelabelStyle.normal.textColor = TextNormalColor;
-
-		skin->setStyle("MultiLineLabel", multiLinelabelStyle);
-
-		// Multi-line centered label
-		GUIElementStyle multiLineCenteredLabelStyle;
-		multiLineCenteredLabelStyle.font = defaultFont;
-		multiLineCenteredLabelStyle.fontSize = DefaultFontSize;
-		multiLineCenteredLabelStyle.fixedWidth = false;
-		multiLineCenteredLabelStyle.fixedHeight = true;
-		multiLineCenteredLabelStyle.height = 11;
-		multiLineCenteredLabelStyle.minWidth = 10;
-		multiLineCenteredLabelStyle.wordWrap = true;
-		multiLineCenteredLabelStyle.textHorzAlign = THA_Center;
-		multiLineCenteredLabelStyle.normal.textColor = TextNormalColor;
-
-		skin->setStyle("MultiLineLabelCentered", multiLineCenteredLabelStyle);
-
-		// Title label
-		GUIElementStyle titleLabel;
-		titleLabel.font = defaultAAFont;
-		titleLabel.fontSize = TitleFontSize;
-		titleLabel.fixedWidth = false;
-		titleLabel.fixedHeight = true;
-		titleLabel.height = 20;
-		titleLabel.minWidth = 10;
-		titleLabel.wordWrap = true;
-		titleLabel.textHorzAlign = THA_Center;
-		titleLabel.normal.textColor = TextNormalColor;
-
-		skin->setStyle("TitleLabel", titleLabel);
-
-		// Selection area
-		GUIElementStyle selectionAreaStyle;
-		selectionAreaStyle.normal.texture = getGUITexture(SelectionAreaTex);
-		selectionAreaStyle.border.left = 1;
-		selectionAreaStyle.border.right = 1;
-		selectionAreaStyle.border.top = 1;
-		selectionAreaStyle.border.bottom = 1;
-
-		skin->setStyle("SelectionArea", selectionAreaStyle);
-
-		// Selectable label
-		GUIElementStyle selectableLabelStyle;
-		selectableLabelStyle.normalOn.texture = getGUITexture(SelectionBgTex);
-		selectableLabelStyle.hoverOn.texture = selectableLabelStyle.normalOn.texture;
-		selectableLabelStyle.activeOn.texture = selectableLabelStyle.normalOn.texture;
-		selectableLabelStyle.fixedHeight = true;
-		selectableLabelStyle.height = 11;
-		selectableLabelStyle.minWidth = 10;
-		selectableLabelStyle.font = defaultFont;
-		selectableLabelStyle.fontSize = DefaultFontSize;
-		selectableLabelStyle.textHorzAlign = THA_Left;
-		selectableLabelStyle.normal.textColor = TextNormalColor;
-
-		skin->setStyle("SelectableLabel", selectableLabelStyle);
-
-		// Scroll area background
-		GUIElementStyle scrollAreaBg;
-		scrollAreaBg.normal.texture = getGUITexture(ScrollAreaBgTex);
-		scrollAreaBg.minHeight = 6;
-		scrollAreaBg.minWidth = 4;
-		scrollAreaBg.border.left = 2;
-		scrollAreaBg.border.right = 2;
-		scrollAreaBg.border.top = 2;
-		scrollAreaBg.border.bottom = 4;
-		
-		skin->setStyle("ScrollAreaBg", scrollAreaBg);
-
-		// Inspector title area background
-		GUIElementStyle inspectorTitleBg;
-		inspectorTitleBg.normal.texture = getGUITexture(InspectorTitleBgTex);
-		inspectorTitleBg.minHeight = 4;
-		inspectorTitleBg.border.bottom = 2;
-
-		skin->setStyle("InspectorTitleBg", inspectorTitleBg);
-
-		// Inspector content background
-		GUIElementStyle inspectorContentBg;
-		inspectorContentBg.normal.texture = getGUITexture(InspectorContentBgTex);
-		inspectorContentBg.minWidth = 4;
-		inspectorContentBg.minHeight = 6;
-		inspectorContentBg.border.left = 2;
-		inspectorContentBg.border.right = 2;
-		inspectorContentBg.border.top = 2;
-		inspectorContentBg.border.bottom = 4;
-
-		skin->setStyle("InspectorContentBg", inspectorContentBg);
-
-		// Inspector content alternate background
-		GUIElementStyle inspectorContentBgAlternate;
-		inspectorContentBgAlternate.normal.texture = getGUITexture(InspectorContentBgAlternateTex);
-		inspectorContentBgAlternate.minWidth = 4;
-		inspectorContentBgAlternate.minHeight = 6;
-		inspectorContentBgAlternate.border.left = 2;
-		inspectorContentBgAlternate.border.right = 2;
-		inspectorContentBgAlternate.border.top = 2;
-		inspectorContentBgAlternate.border.bottom = 4;
-
-		skin->setStyle("InspectorContentBgAlternate", inspectorContentBgAlternate);
-
-		return skin;
-	}
-
-	HSpriteTexture BuiltinEditorResources::getGUITexture(const WString& name) const
-	{
-		Path texturePath = FileSystem::getWorkingDirectoryPath();
-		texturePath.append(EditorSkinFolder);
-		texturePath.append(L"sprite_" + name + L".asset");
-
-		return gResources().load<SpriteTexture>(texturePath);
-	}
-
-	HSpriteTexture BuiltinEditorResources::getGUIIcon(const WString& name) const
-	{
-		Path texturePath = FileSystem::getWorkingDirectoryPath();
-		texturePath.append(EditorIconFolder);
-		texturePath.append(L"sprite_" + name + L".asset");
-
-		return gResources().load<SpriteTexture>(texturePath);
-	}
-
-	HShader BuiltinEditorResources::getShader(const WString& name) const
-	{
-		Path programPath = EditorShaderFolder;
-		programPath.append(name + L".asset");
-
-		return gResources().load<Shader>(programPath);
-	}
-
-	HMaterial BuiltinEditorResources::createDockDropOverlayMaterial() const
-	{
-		return Material::create(mShaderDockOverlay);
-	}
-
-	HMaterial BuiltinEditorResources::createSceneGridMaterial() const
-	{
-		return Material::create(mShaderSceneGrid);
-	}
-
-	HMaterial BuiltinEditorResources::createPicking(CullingMode cullMode) const
-	{
-		UINT32 modeIdx = (UINT32)cullMode;
-
-		return Material::create(mShaderPicking[modeIdx]);
-	}
-
-	HMaterial BuiltinEditorResources::createPickingAlpha(CullingMode cullMode) const
-	{
-		UINT32 modeIdx = (UINT32)cullMode;
-
-		return Material::create(mShaderPickingAlpha[modeIdx]);
-	}
-
-	HMaterial BuiltinEditorResources::createWireGizmoMat() const
-	{
-		return Material::create(mShaderGizmoWire);
-	}
-
-	HMaterial BuiltinEditorResources::createSolidGizmoMat() const
-	{
-		return Material::create(mShaderGizmoSolid);
-	}
-
-	HMaterial BuiltinEditorResources::createIconGizmoMat() const
-	{
-		return Material::create(mShaderGizmoIcon);
-	}
-
-	HMaterial BuiltinEditorResources::createGizmoPickingMat() const
-	{
-		return Material::create(mShaderGizmoPicking);
-	}
-
-	HMaterial BuiltinEditorResources::createAlphaGizmoPickingMat() const
-	{
-		return Material::create(mShaderGizmoAlphaPicking);
-	}
-
-	HMaterial BuiltinEditorResources::createWireHandleMat() const
-	{
-		return Material::create(mShaderHandleWire);
-	}
-
-	HMaterial BuiltinEditorResources::createSolidHandleMat() const
-	{
-		return Material::create(mShaderHandleSolid);
-	}
-
-	HMaterial BuiltinEditorResources::createSelectionMat() const
-	{
-		return Material::create(mShaderSelection);
-	}
-
-	HSpriteTexture BuiltinEditorResources::getLibraryIcon(ProjectIcon icon, int size) const
-	{
-		WString iconName;
-
-		switch (icon)
-		{
-		case ProjectIcon::Folder:
-			iconName = FolderIconTex;
-			break;
-		case ProjectIcon::Font:
-			iconName = FontIconTex;
-			break;
-		case ProjectIcon::Mesh:
-			iconName = MeshIconTex;
-			break;
-		case ProjectIcon::Texture:
-			iconName = TextureIconTex;
-			break;
-		case ProjectIcon::PlainText:
-			iconName = PlainTextIconTex;
-			break;
-		case ProjectIcon::ScriptCode:
-			iconName = ScriptCodeIconTex;
-			break;
-		case ProjectIcon::Shader:
-			iconName = ShaderIconTex;
-			break;
-		case ProjectIcon::ShaderInclude:
-			iconName = ShaderIncludeIconTex;
-			break;
-		case ProjectIcon::Material:
-			iconName = MaterialIconTex;
-			break;
-		case ProjectIcon::SpriteTexture:
-			iconName = SpriteTextureIconTex;
-			break;
-		case ProjectIcon::Prefab:
-			iconName = PrefabIconTex;
-			break;
-		case ProjectIcon::GUISkin:
-			iconName = GUISkinIconTex;
-			break;
-		}
-
-		if (iconName.empty())
-			return HSpriteTexture();
-
-		if (size <= 16)
-			iconName += L"16";
-		else if (size <= 32)
-			iconName += L"32";
-		else if (size <= 48)
-			iconName += L"48";
-
-		return getGUIIcon(iconName);
-	}
-
-	HSpriteTexture BuiltinEditorResources::getToolbarIcon(ToolbarIcon icon) const
-	{
-		switch (icon)
-		{
-		case ToolbarIcon::NewCamera:
-			return getGUIIcon(L"ToolbarNewCameraIcon.png");
-		case ToolbarIcon::NewRenderable:
-			return getGUIIcon(L"ToolbarNewRenderableIcon.png");
-		case ToolbarIcon::NewPointLight:
-			return getGUIIcon(L"ToolbarNewPointLightIcon.png");
-		case ToolbarIcon::NewDirLight:
-			return getGUIIcon(L"ToolbarNewDirectionalLightIcon.png");
-		case ToolbarIcon::NewSpotLight:
-			return getGUIIcon(L"ToolbarNewSpotLightIcon.png");
-		case ToolbarIcon::NewSceneObject:
-			return getGUIIcon(L"ToolbarNewSceneObjectIcon.png");
-		case ToolbarIcon::NewCube:
-			return getGUIIcon(L"ToolbarNewCubeIcon.png");
-		case ToolbarIcon::NewSphere:
-			return getGUIIcon(L"ToolbarNewSphereIcon.png");
-		case ToolbarIcon::NewCone:
-			return getGUIIcon(L"ToolbarNewConeIcon.png");
-		case ToolbarIcon::NewQuad:
-			return getGUIIcon(L"ToolbarNewQuadIcon.png");
-		case ToolbarIcon::NewMat:
-			return getGUIIcon(L"ToolbarNewMaterialIcon.png");
-		case ToolbarIcon::NewCSScript:
-			return getGUIIcon(L"ToolbarNewCSScriptIcon.png");
-		case ToolbarIcon::NewShader:
-			return getGUIIcon(L"ToolbarNewShaderIcon.png");
-		case ToolbarIcon::NewSpriteTex:
-			return getGUIIcon(L"ToolbarNewSpriteTextureIcon.png");
-		case ToolbarIcon::Pause:
-			return getGUIIcon(L"ToolbarPauseIcon.png");
-		case ToolbarIcon::Play:
-			return getGUIIcon(L"ToolbarPlayIcon.png");
-		case ToolbarIcon::Step:
-			return getGUIIcon(L"ToolbarStepIcon.png");
-		case ToolbarIcon::Undo:
-			return getGUIIcon(L"ToolbarUndoIcon.png");
-		case ToolbarIcon::Redo:
-			return getGUIIcon(L"ToolbarRedoIcon.png");
-		case ToolbarIcon::OpenProject:
-			return getGUIIcon(L"ToolbarOpenProjectIcon.png");
-		case ToolbarIcon::SaveProject:
-			return getGUIIcon(L"ToolbarSaveProjectIcon.png");
-		case ToolbarIcon::SaveScene:
-			return getGUIIcon(L"ToolbarSaveSceneIcon.png");
-		}
-
-		return HSpriteTexture();
-	}
-
-	GUIContentImages BuiltinEditorResources::getSceneWindowIcon(SceneWindowIcon icon) const
-	{
-		HSpriteTexture off;
-		HSpriteTexture on;
-
-		switch (icon)
-		{
-		case SceneWindowIcon::View:
-			off = getGUIIcon(L"SceneViewIcon.png");
-			on = getGUIIcon(L"SceneViewIconOn.png");
-			break;
-		case SceneWindowIcon::Move:
-			off = getGUIIcon(L"SceneMoveIcon.png");
-			on = getGUIIcon(L"SceneMoveIconOn.png");
-			break;
-		case SceneWindowIcon::Rotate:
-			off = getGUIIcon(L"SceneRotateIcon.png");
-			on = getGUIIcon(L"SceneRotateIconOn.png");
-			break;
-		case SceneWindowIcon::Scale:
-			off = getGUIIcon(L"SceneScaleIcon.png");
-			on = getGUIIcon(L"SceneScaleIconOn.png");
-			break;
-		case SceneWindowIcon::Pivot:
-			off = getGUIIcon(L"ScenePivotIcon.png");
-			on = getGUIIcon(L"ScenePivotIconOn.png");
-			break;
-		case SceneWindowIcon::Center:
-			off = getGUIIcon(L"SceneCenterIcon.png");
-			on = getGUIIcon(L"SceneCenterIconOn.png");
-			break;
-		case SceneWindowIcon::Local:
-			off = getGUIIcon(L"SceneLocalIcon.png");
-			on = getGUIIcon(L"SceneLocalIconOn.png");
-			break;
-		case SceneWindowIcon::World:
-			off = getGUIIcon(L"SceneWorldIcon.png");
-			on = getGUIIcon(L"SceneWorldIconOn.png");
-			break;
-		case SceneWindowIcon::MoveSnap:
-			off = getGUIIcon(L"SceneMoveSnapIcon.png");
-			on = getGUIIcon(L"SceneMoveSnapIconOn.png");
-			break;
-		case SceneWindowIcon::RotateSnap:
-			off = getGUIIcon(L"SceneRotateSnapIcon.png");
-			on = getGUIIcon(L"SceneRotateSnapIconOn.png");
-			break;
-		}
-
-		GUIContentImages output;
-		output.normal = off;
-		output.hover = off;
-		output.active = on;
-		output.focused = off;
-		output.normalOn = on;
-		output.hoverOn = on;
-		output.activeOn = on;
-		output.focusedOn = on;
-
-		return output;
-	}
-
-	HSpriteTexture BuiltinEditorResources::getLibraryWindowIcon(LibraryWindowIcon icon) const
-	{
-		switch (icon)
-		{
-		case LibraryWindowIcon::Home:
-			return getGUIIcon(L"LibraryHomeIcon.png");
-		case LibraryWindowIcon::Up:
-			return getGUIIcon(L"LibraryUpIcon.png");
-		case LibraryWindowIcon::Clear:
-			return getGUIIcon(L"LibraryClearSearchIcon.png");
-		case LibraryWindowIcon::Options:
-			return getGUIIcon(L"LibraryOptionsIcon.png");
-		}
-
-		return HSpriteTexture();
-	}
-
-	HSpriteTexture BuiltinEditorResources::getInspectorWindowIcon(InspectorWindowIcon icon) const
-	{
-		switch (icon)
-		{
-		case InspectorWindowIcon::Create:
-			return getGUIIcon(L"InspectorCreateIcon.png");
-		case InspectorWindowIcon::Clone:
-			return getGUIIcon(L"InspectorCloneIcon.png");
-		case InspectorWindowIcon::Clear:
-			return getGUIIcon(L"InspectorClearIcon.png");
-		case InspectorWindowIcon::Resize:
-			return getGUIIcon(L"InspectorResizeIcon.png");
-		case InspectorWindowIcon::Delete:
-			return getGUIIcon(L"InspectorDeleteIcon.png");
-		case InspectorWindowIcon::MoveUp:
-			return getGUIIcon(L"InspectorMoveUpIcon.png");
-		case InspectorWindowIcon::MoveDown:
-			return getGUIIcon(L"InspectorMoveDownIcon.png");
-		case InspectorWindowIcon::Edit:
-			return getGUIIcon(L"InspectorEditIcon.png");
-		case InspectorWindowIcon::Apply:
-			return getGUIIcon(L"InspectorApplyIcon.png");
-		case InspectorWindowIcon::Add:
-			return getGUIIcon(L"InspectorAddIcon.png");
-		case InspectorWindowIcon::Cancel:
-			return getGUIIcon(L"InspectorCancelIcon.png");
-		}
-
-		return HSpriteTexture();
-	}
-
-	HSpriteTexture BuiltinEditorResources::getIcon(EditorIcon icon) const
-	{
-		switch (icon)
-		{
-		case EditorIcon::XBtn:
-			return getGUIIcon(XButtonNormalTex);
-		}
-
-		return HSpriteTexture();
-	}
-
-	HSpriteTexture BuiltinEditorResources::getLogMessageIcon(LogMessageIcon icon, UINT32 size, bool dark) const
-	{
-		if (size < 24) // Round to 16
-		{
-			if (dark)
-			{
-				switch (icon)
-				{
-				case LogMessageIcon::Info:
-					return getGUIIcon(L"IconInfoDark.png");
-				case LogMessageIcon::Warning:
-					return getGUIIcon(L"IconWarningDark.png");
-				case LogMessageIcon::Error:
-					return getGUIIcon(L"IconErrorDark.png");
-				}
-			}
-			else
-			{
-				switch (icon)
-				{
-				case LogMessageIcon::Info:
-					return getGUIIcon(L"IconInfo.png");
-				case LogMessageIcon::Warning:
-					return getGUIIcon(L"IconWarning.png");
-				case LogMessageIcon::Error:
-					return getGUIIcon(L"IconError.png");
-				}
-			}
-		}
-		else // Round to 32
-		{
-			switch (icon)
-			{
-			case LogMessageIcon::Info:
-				return getGUIIcon(L"IconInfo32.png");
-			case LogMessageIcon::Warning:
-				return getGUIIcon(L"IconWarning32.png");
-			case LogMessageIcon::Error:
-				return getGUIIcon(L"IconError32.png");
-			}
-		}
-
-		return HSpriteTexture();
-	}
-
-	WString BuiltinEditorResources::getEmptyShaderCode() const
-	{
-		Path filePath = FileSystem::getWorkingDirectoryPath();
-		filePath.append(BuiltinDataFolder);
-		filePath.append(EmptyShaderCodeFile);
-
-		DataStreamPtr fileStream = FileSystem::openFile(filePath);
-		if (fileStream != nullptr)
-			return fileStream->getAsWString();
-
-		return StringUtil::WBLANK;
-	}
-
-	WString BuiltinEditorResources::getEmptyCSScriptCode() const
-	{
-		Path filePath = FileSystem::getWorkingDirectoryPath();
-		filePath.append(BuiltinDataFolder);
-		filePath.append(EmptyCSScriptCodeFile);
-
-		DataStreamPtr fileStream = FileSystem::openFile(filePath);
-		if (fileStream != nullptr)
-			return fileStream->getAsWString();
-
-		return StringUtil::WBLANK;
-	}
-
-	Path BuiltinEditorResources::getShaderIncludeFolder()
-	{
-		return Paths::getRuntimeDataPath() + EDITOR_DATA_FOLDER + ShaderIncludeFolder;
-	}
-
-	Path BuiltinEditorResources::getDefaultWidgetLayoutPath()
-	{
-		return Paths::getRuntimeDataPath() + EDITOR_DATA_FOLDER + "Layout.asset";
-	}
+#include "BsBuiltinEditorResources.h"
+#include "BsBuiltinResources.h"
+#include "BsGUIElementStyle.h"
+
+#include "BsGUILabel.h"
+#include "BsGUITexture.h"
+#include "BsGUIButton.h"
+#include "BsGUIInputBox.h"
+#include "BsGUIToggle.h"
+#include "BsGUIColor.h"
+#include "BsTextSprite.h"
+#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 "BsGUIListBoxField.h"
+#include "BsGUISliderField.h"
+#include "BsGUIProgressBar.h"
+#include "BsGUISlider.h"
+#include "BsGUIDropDownContent.h"
+#include "BsGUIStatusBar.h"
+#include "BsGUIMenuBar.h"
+#include "BsGUIListBox.h"
+#include "BsCoreThread.h"
+
+#include "BsFont.h"
+#include "BsFontImportOptions.h"
+#include "BsImporter.h"
+#include "BsGpuProgram.h"
+#include "BsShader.h"
+#include "BsShaderInclude.h"
+#include "BsTechnique.h"
+#include "BsPass.h"
+#include "BsMaterial.h"
+#include "BsBlendState.h"
+#include "BsDepthStencilState.h"
+#include "BsRasterizerState.h"
+#include "BsResources.h"
+#include "BsRTTIType.h"
+#include "BsFileSystem.h"
+#include "BsResourceManifest.h"
+#include "BsDataStream.h"
+#include "BsGUITooltip.h"
+
+namespace BansheeEngine
+{
+	static const Path EDITOR_DATA_FOLDER = "Editor\\";
+
+	const String BuiltinEditorResources::ObjectFieldStyleName = "GUIObjectField";
+	const String BuiltinEditorResources::ObjectFieldLabelStyleName = "EditorFieldLabel";
+	const String BuiltinEditorResources::ObjectFieldDropBtnStyleName = "DropButton";
+	const String BuiltinEditorResources::ObjectFieldClearBtnStyleName = "ObjectClearButton";
+
+	const String BuiltinEditorResources::TextureFieldStyleName = "GUITextureField";
+	const String BuiltinEditorResources::TextureFieldLabelStyleName = "TextureFieldLabel";
+	const String BuiltinEditorResources::TextureFieldDropStyleName = "TextureDrop";
+	const String BuiltinEditorResources::TextureFieldClearBtnStyleName = "TextureClearButton";
+
+	const WString BuiltinEditorResources::DefaultFontFilename = L"arial.ttf";
+	const WString BuiltinEditorResources::DefaultAAFontFilename = L"arialAA.ttf";
+	const UINT32 BuiltinEditorResources::DefaultFontSize = 8;
+	const UINT32 BuiltinEditorResources::TitleFontSize = 16;
+
+	const Color BuiltinEditorResources::TextNormalColor = Color(0.7f, 0.7f, 0.7f);
+	const Color BuiltinEditorResources::TextActiveColor = Color(0.0f, 0.0f, 0.0f);
+
+	const WString BuiltinEditorResources::GUISkinFile = L"GUISkin";
+
+	const char* BuiltinEditorResources::ShaderFolder = "Shaders\\";
+	const char* BuiltinEditorResources::SkinFolder = "Skin\\";
+	const char* BuiltinEditorResources::IconFolder = "Skin\\Icons";
+	const char* BuiltinEditorResources::ShaderIncludeFolder = "Includes\\";
+
+	const WString BuiltinEditorResources::FolderIconTex = L"FolderIcon.psd";
+	const WString BuiltinEditorResources::MeshIconTex = L"MeshIcon.psd";
+	const WString BuiltinEditorResources::TextureIconTex = L"TextureIcon.psd";
+	const WString BuiltinEditorResources::FontIconTex = L"FontIcon.psd";
+	const WString BuiltinEditorResources::PlainTextIconTex = L"TextIcon.psd";
+	const WString BuiltinEditorResources::ScriptCodeIconTex = L"CSharpIcon.psd";
+	const WString BuiltinEditorResources::ShaderIconTex = L"ShaderIcon.psd";
+	const WString BuiltinEditorResources::ShaderIncludeIconTex = L"ShaderIncludeIcon.psd";
+	const WString BuiltinEditorResources::MaterialIconTex = L"MaterialIcon.psd";
+	const WString BuiltinEditorResources::SpriteTextureIconTex = L"SpriteIcon.psd";
+	const WString BuiltinEditorResources::PrefabIconTex = L"PrefabIcon.psd";
+	const WString BuiltinEditorResources::GUISkinIconTex = L"GUISkinIcon.psd";
+
+	const WString BuiltinEditorResources::ButtonNormalTex = L"ButtonNormal.png";
+	const WString BuiltinEditorResources::ButtonHoverTex = L"ButtonHover.png";
+	const WString BuiltinEditorResources::ButtonActiveTex = L"ButtonActive.png";
+
+	const WString BuiltinEditorResources::ButtonLeftNormalTex = L"ButtonLeftNormal.png";
+	const WString BuiltinEditorResources::ButtonLeftHoverTex = L"ButtonLeftHover.png";
+	const WString BuiltinEditorResources::ButtonLeftActiveTex = L"ButtonLeftActive.png";
+
+	const WString BuiltinEditorResources::ButtonRightNormalTex = L"ButtonRightNormal.png";
+	const WString BuiltinEditorResources::ButtonRightHoverTex = L"ButtonRightHover.png";
+	const WString BuiltinEditorResources::ButtonRightActiveTex = L"ButtonRightActive.png";
+
+	const WString BuiltinEditorResources::ToggleNormalTex = L"ToggleNormal.png";
+	const WString BuiltinEditorResources::ToggleHoverTex = L"ToggleHover.png";
+	const WString BuiltinEditorResources::ToggleNormalOnTex = L"ToggleNormalOn.png";
+	const WString BuiltinEditorResources::ToggleHoverOnTex = L"ToggleHoverOn.png";
+
+	const WString BuiltinEditorResources::InputBoxNormalTex = L"InputBoxNormal.png";
+	const WString BuiltinEditorResources::InputBoxHoverTex = L"InputBoxHover.png";
+	const WString BuiltinEditorResources::InputBoxFocusedTex = L"InputBoxActive.png";
+
+	const WString BuiltinEditorResources::ObjectDropBtnNormalTex = L"ObjectDropNormal.png";
+	const WString BuiltinEditorResources::ObjectDropBtnNormalOnTex = L"ObjectDropNormalOn.png";
+	const WString BuiltinEditorResources::ObjectClearBtnNormalTex = L"ObjectDropClearNormal.png";
+	const WString BuiltinEditorResources::ObjectClearBtnHoverTex = L"ObjectDropClearHover.png";
+	const WString BuiltinEditorResources::ObjectClearBtnActiveTex = L"ObjectDropClearActive.png";
+	
+	const WString BuiltinEditorResources::DropDownBtnNormalTex = L"DropDownButtonNormal.png";
+	const WString BuiltinEditorResources::DropDownBtnHoverTex = L"DropDownButtonHover.png";
+	const WString BuiltinEditorResources::DropDownBtnActiveTex = L"DropDownButtonActive.png";
+
+	const WString BuiltinEditorResources::SliderHBackgroundTex = L"SliderHBackground.png";
+	const WString BuiltinEditorResources::SliderHFillTex = L"SliderHFill.png";
+	const WString BuiltinEditorResources::SliderVBackgroundTex = L"SliderVBackground.png";
+	const WString BuiltinEditorResources::SliderVFillTex = L"SliderVFill.png";
+	const WString BuiltinEditorResources::SliderHandleNormalTex = L"SliderHandleNormal.png";
+	const WString BuiltinEditorResources::SliderHandleHoverTex = L"SliderHandleHover.png";
+	const WString BuiltinEditorResources::SliderHandleActiveTex = L"SliderHandleActive.png";
+
+	const WString BuiltinEditorResources::FoldoutOpenNormalTex = L"FoldoutNormalOn.png";
+	const WString BuiltinEditorResources::FoldoutOpenHoverTex = L"FoldoutHoverOn.png";
+	const WString BuiltinEditorResources::FoldoutOpenActiveTex = L"FoldoutHoverOn.png";
+	const WString BuiltinEditorResources::FoldoutClosedNormalTex = L"FoldoutNormalOff.png";
+	const WString BuiltinEditorResources::FoldoutClosedHoverTex = L"FoldoutHoverOff.png";
+	const WString BuiltinEditorResources::FoldoutClosedActiveTex = L"FoldoutHoverOff.png";
+
+	const WString BuiltinEditorResources::WindowBackgroundTex = L"WindowBackground.png";
+
+	const WString BuiltinEditorResources::WindowFrameNormal = L"WindowFrameNormal.png";
+	const WString BuiltinEditorResources::WindowFrameFocused = L"WindowFrameFocused.png";
+
+	const WString BuiltinEditorResources::CloseButtonNormalTex = L"CloseButtonNormal.png";
+	const WString BuiltinEditorResources::CloseButtonHoverTex = L"CloseButtonHover.png";
+	const WString BuiltinEditorResources::CloseButtonActiveTex = L"CloseButtonActive.png";
+
+	const WString BuiltinEditorResources::MinButtonNormalTex = L"MinimizeButtonNormal.png"; 
+	const WString BuiltinEditorResources::MinButtonHoverTex = L"MinimizeButtonHover.png"; 
+	const WString BuiltinEditorResources::MinButtonActiveTex = L"MinimizeButtonActive.png";
+
+	const WString BuiltinEditorResources::MaxButtonNormalTex = L"MaximizeButtonNormal.png";
+	const WString BuiltinEditorResources::MaxButtonHoverTex = L"MaximizeButtonHover.png";
+	const WString BuiltinEditorResources::MaxButtonActiveTex = L"MaximizeButtonActive.png";
+
+	const WString BuiltinEditorResources::TabBarBackgroundTex = L"TabBarBackground.png";
+	const WString BuiltinEditorResources::TitleBarBackgroundTex = L"TitleBarBackground.png";
+
+	const WString BuiltinEditorResources::TabButtonNormalTex = L"TabButtonNormal.png";
+	const WString BuiltinEditorResources::TabButtonFocusedTex = L"TabButtonFocused.png";
+
+	const WString BuiltinEditorResources::ScrollBarUpNormalTex = L"ScrollArrowUpNormal.png";
+	const WString BuiltinEditorResources::ScrollBarUpHoverTex = L"ScrollArrowUpHover.png";
+	const WString BuiltinEditorResources::ScrollBarUpActiveTex = L"ScrollArrowUpActive.png";
+
+	const WString BuiltinEditorResources::ScrollBarDownNormalTex = L"ScrollArrowDownNormal.png";
+	const WString BuiltinEditorResources::ScrollBarDownHoverTex = L"ScrollArrowDownHover.png";
+	const WString BuiltinEditorResources::ScrollBarDownActiveTex = L"ScrollArrowDownActive.png";
+
+	const WString BuiltinEditorResources::ScrollBarLeftNormalTex = L"ScrollArrowLeftNormal.png";
+	const WString BuiltinEditorResources::ScrollBarLeftHoverTex = L"ScrollArrowLeftHover.png";
+	const WString BuiltinEditorResources::ScrollBarLeftActiveTex = L"ScrollArrowLeftActive.png";
+
+	const WString BuiltinEditorResources::ScrollBarRightNormalTex = L"ScrollArrowRightNormal.png";
+	const WString BuiltinEditorResources::ScrollBarRightHoverTex = L"ScrollArrowRightHover.png";
+	const WString BuiltinEditorResources::ScrollBarRightActiveTex = L"ScrollArrowRightActive.png";
+
+	const WString BuiltinEditorResources::ScrollBarHandleHorzNormalTex = L"ScrollBarHHandleNormal.png";
+	const WString BuiltinEditorResources::ScrollBarHandleHorzHoverTex = L"ScrollBarHHandleHover.png";
+	const WString BuiltinEditorResources::ScrollBarHandleHorzActiveTex = L"ScrollBarHHandleActive.png";
+
+	const WString BuiltinEditorResources::ScrollBarHandleVertNormalTex = L"ScrollBarVHandleNormal.png";
+	const WString BuiltinEditorResources::ScrollBarHandleVertHoverTex = L"ScrollBarVHandleHover.png";
+	const WString BuiltinEditorResources::ScrollBarHandleVertActiveTex = L"ScrollBarVHandleActive.png";
+
+	const WString BuiltinEditorResources::ScrollBarHBgTex = L"ScrollBarHBackground.png";
+	const WString BuiltinEditorResources::ScrollBarVBgTex = L"ScrollBarVBackground.png";
+
+	const WString BuiltinEditorResources::DropDownBoxBgTex = L"DropDownBoxBg.png";
+	const WString BuiltinEditorResources::DropDownBoxSideBgTex = L"DropDownBoxSideBg.png";
+	const WString BuiltinEditorResources::DropDownBoxHandleTex = L"DropDownBoxScrollHandle.png";
+
+	const WString BuiltinEditorResources::DropDownBoxEntryNormalTex = L"DropDownBoxEntryNormal.png";
+	const WString BuiltinEditorResources::DropDownBoxEntryHoverTex = L"DropDownBoxEntryHover.png";
+
+	const WString BuiltinEditorResources::DropDownBoxEntryToggleNormalTex = L"DropDownBoxEntryToggleNormal.png";
+	const WString BuiltinEditorResources::DropDownBoxEntryToggleHoverTex = L"DropDownBoxEntryToggleHover.png";
+	const WString BuiltinEditorResources::DropDownBoxEntryToggleNormalOnTex = L"DropDownBoxEntryToggleNormalOn.png";
+	const WString BuiltinEditorResources::DropDownBoxEntryToggleHoverOnTex = L"DropDownBoxEntryToggleHoverOn.png";
+
+	const WString BuiltinEditorResources::DropDownBoxBtnUpNormalTex = L"DropDownBoxArrowUpNormal.png";
+	const WString BuiltinEditorResources::DropDownBoxBtnUpHoverTex = L"DropDownBoxArrowUpHover.png";
+
+	const WString BuiltinEditorResources::DropDownBoxBtnDownNormalTex = L"DropDownBoxArrowDownNormal.png";
+	const WString BuiltinEditorResources::DropDownBoxBtnDownHoverTex = L"DropDownBoxArrowDownHover.png";
+
+	const WString BuiltinEditorResources::DropDownBoxEntryExpNormalTex = L"DropDownBoxExpandBtnNormal.png";
+	const WString BuiltinEditorResources::DropDownBoxEntryExpHoverTex = L"DropDownBoxExpandBtnHover.png";
+
+	const WString BuiltinEditorResources::DropDownSeparatorTex = L"DropDownBoxSeparator.png";
+
+	const WString BuiltinEditorResources::MenuBarBgTex = L"MenuBarBackground.png";
+	const WString BuiltinEditorResources::MenuBarBansheeLogoTex = L"MenuBarLog.png";
+
+	const WString BuiltinEditorResources::MenuBarBtnNormalTex = L"MenuBarButtonNormal.png";
+	const WString BuiltinEditorResources::MenuBarBtnActiveTex = L"MenuBarButtonActive.png";
+	const WString BuiltinEditorResources::MenuBarBtnHoverTex = L"MenuBarButtonHover.png";
+
+	const WString BuiltinEditorResources::MenuBarLineNormalTex = L"MenuBarLineNormal.png";
+	const WString BuiltinEditorResources::MenuBarLineActiveTex = L"MenuBarLineActive.png";
+
+	const WString BuiltinEditorResources::ToolBarBtnNormalTex = L"ToolBarButtonNormal.png";
+	const WString BuiltinEditorResources::ToolBarBtnHoverTex = L"ToolBarButtonHover.png";
+	const WString BuiltinEditorResources::ToolBarBtnActiveTex = L"ToolBarButtonActive.png";
+
+	const WString BuiltinEditorResources::ToolBarSeparatorTex = L"ToolBarSeparator.png";
+
+	const WString BuiltinEditorResources::DockSliderNormalTex = L"DockSliderNormal.png";
+
+	const WString BuiltinEditorResources::TreeViewExpandButtonOffNormal = L"ExpandArrowNormalOff.png";
+	const WString BuiltinEditorResources::TreeViewExpandButtonOffHover = L"ExpandArrowHoverOff.png";
+	const WString BuiltinEditorResources::TreeViewExpandButtonOnNormal = L"ExpandArrowNormalOn.png";
+	const WString BuiltinEditorResources::TreeViewExpandButtonOnHover = L"ExpandArrowHoverOn.png";
+
+	const WString BuiltinEditorResources::TreeViewHighlightBackground = L"TreeViewHighlightBackground.psd";
+	const WString BuiltinEditorResources::TreeViewEditBox = L"TreeViewEditBox.psd";
+	const WString BuiltinEditorResources::TreeViewElementHighlight = L"TreeViewElementHighlight.psd";
+	const WString BuiltinEditorResources::TreeViewElementSepHighlight = L"TreeViewElementSepHighlight.psd";
+
+	const WString BuiltinEditorResources::ColorPickerSliderHorzHandleTex = L"ColorPickerSliderHorzHandle.psd";
+	const WString BuiltinEditorResources::ColorPickerSliderVertHandleTex = L"ColorPickerSliderVertHandle.psd";
+	const WString BuiltinEditorResources::ColorPickerSlider2DHandleTex = L"ColorPicker2DHandle.psd";
+
+	const WString BuiltinEditorResources::ProgressBarFillTex = L"ProgressBarFill.png";
+	const WString BuiltinEditorResources::ProgressBarBgTex = L"ProgressBarBg.png";
+
+	const WString BuiltinEditorResources::SelectionAreaTex = L"SelectionHighlight.png";
+	const WString BuiltinEditorResources::SelectionBgTex = L"SelectionBg.psd";
+
+	const WString BuiltinEditorResources::TextureDropTex = L"TextureDrop.png";
+	const WString BuiltinEditorResources::TextureDropOnTex = L"TextureDropHover.png";
+
+	const WString BuiltinEditorResources::XButtonNormalTex = L"XBtnNormal.png";
+	const WString BuiltinEditorResources::XButtonHoverTex = L"XBtnHover.png";
+	const WString BuiltinEditorResources::XButtonActiveTex = L"XBtnActive.png";
+
+	const WString BuiltinEditorResources::StatusBarBgTex = L"StatusBarBackground.png";
+	const WString BuiltinEditorResources::ScrollAreaBgTex = L"ScrollAreaBg.png";
+
+	const WString BuiltinEditorResources::InspectorTitleBgTex = L"InspectorTitleBg.png";
+	const WString BuiltinEditorResources::InspectorContentBgTex = L"InspectorContentBg.png";
+	const WString BuiltinEditorResources::InspectorContentBgAlternateTex = L"InspectorContentBgAlternate.png";
+
+	/************************************************************************/
+	/* 									SHADERS                      		*/
+	/************************************************************************/
+
+	const WString BuiltinEditorResources::ShaderDockOverlayFile = L"DockDropOverlay.bsl";
+	const WString BuiltinEditorResources::ShaderSceneGridFile = L"SceneGrid.bsl";
+	const WString BuiltinEditorResources::ShaderPickingCullNoneFile = L"PickingCullNone.bsl";
+	const WString BuiltinEditorResources::ShaderPickingCullCWFile = L"PickingCullCW.bsl";
+	const WString BuiltinEditorResources::ShaderPickingCullCCWFile = L"PickingCullCCW.bsl";
+	const WString BuiltinEditorResources::ShaderPickingAlphaCullNoneFile = L"PickingAlphaCullNone.bsl";
+	const WString BuiltinEditorResources::ShaderPickingAlphaCullCWFile = L"PickingAlphaCullCW.bsl";
+	const WString BuiltinEditorResources::ShaderPickingAlphaCullCCWFile = L"PickingAlphaCullCCW.bsl";
+	const WString BuiltinEditorResources::ShaderWireGizmoFile = L"WireGizmo.bsl";
+	const WString BuiltinEditorResources::ShaderSolidGizmoFile = L"SolidGizmo.bsl";
+	const WString BuiltinEditorResources::ShaderWireHandleFile = L"WireHandle.bsl";
+	const WString BuiltinEditorResources::ShaderSolidHandleFile = L"SolidHandle.bsl";
+	const WString BuiltinEditorResources::ShaderIconGizmoFile = L"IconGizmo.bsl";
+	const WString BuiltinEditorResources::ShaderGizmoPickingFile = L"GizmoPicking.bsl";
+	const WString BuiltinEditorResources::ShaderGizmoPickingAlphaFile = L"GizmoPickingAlpha.bsl";
+	const WString BuiltinEditorResources::ShaderSelectionFile = L"Selection.bsl";
+
+	/************************************************************************/
+	/* 								OTHER							  		*/
+	/************************************************************************/
+	const WString BuiltinEditorResources::EmptyShaderCodeFile = L"EmptyShaderText.txt";
+	const WString BuiltinEditorResources::EmptyCSScriptCodeFile = L"EmptyCSScriptText.txt";
+
+	BuiltinEditorResources::BuiltinEditorResources()
+	{
+		// Set up paths
+		BuiltinRawDataFolder = Paths::getRuntimeDataPath() + L"Raw\\Editor\\";
+		EditorRawSkinFolder = BuiltinRawDataFolder + SkinFolder;
+		EditorRawShaderFolder = BuiltinRawDataFolder + ShaderFolder;
+		EditorRawShaderIncludeFolder = BuiltinRawDataFolder + ShaderIncludeFolder;
+
+		BuiltinDataFolder = Paths::getRuntimeDataPath() + EDITOR_DATA_FOLDER;
+		EditorSkinFolder = BuiltinDataFolder + SkinFolder;
+		EditorIconFolder = BuiltinDataFolder + IconFolder;
+		EditorShaderFolder = BuiltinDataFolder + ShaderFolder;
+		EditorShaderIncludeFolder = BuiltinDataFolder + ShaderIncludeFolder;
+
+		ResourceManifestPath = BuiltinDataFolder + "ResourceManifest.asset";
+
+		Path absoluteDataPath = FileSystem::getWorkingDirectoryPath();
+		absoluteDataPath.append(BuiltinDataFolder);
+
+		// Update from raw assets if needed
+#if BS_DEBUG_MODE
+		if (BuiltinResourcesHelper::checkForModifications(BuiltinRawDataFolder, BuiltinDataFolder + L"Timestamp.asset"))
+		{
+			mResourceManifest = ResourceManifest::create("BuiltinResources");
+			gResources().registerResourceManifest(mResourceManifest);
+
+			preprocess();
+			BuiltinResourcesHelper::writeTimestamp(BuiltinDataFolder + L"Timestamp.asset");
+
+			Path absoluteDataPath = FileSystem::getWorkingDirectoryPath();
+			absoluteDataPath.append(BuiltinDataFolder);
+
+			ResourceManifest::save(mResourceManifest, ResourceManifestPath, absoluteDataPath);
+		}
+#endif
+
+		// Load manifest
+		if (mResourceManifest == nullptr)
+		{
+			if (FileSystem::exists(ResourceManifestPath))
+				mResourceManifest = ResourceManifest::load(ResourceManifestPath, absoluteDataPath);
+
+			if (mResourceManifest == nullptr)
+				mResourceManifest = ResourceManifest::create("BuiltinResources");
+
+			gResources().registerResourceManifest(mResourceManifest);
+		}
+
+		// Load basic resources
+		mShaderDockOverlay = getShader(ShaderDockOverlayFile);
+		mShaderSceneGrid = getShader(ShaderSceneGridFile);
+		mShaderPicking[(int)CULL_NONE] = getShader(ShaderPickingCullNoneFile);
+		mShaderPicking[(int)CULL_CLOCKWISE] = getShader(ShaderPickingCullCWFile);
+		mShaderPicking[(int)CULL_COUNTERCLOCKWISE] = getShader(ShaderPickingCullCCWFile);
+		mShaderPickingAlpha[(int)CULL_NONE] = getShader(ShaderPickingAlphaCullNoneFile);
+		mShaderPickingAlpha[(int)CULL_CLOCKWISE] = getShader(ShaderPickingAlphaCullCWFile);
+		mShaderPickingAlpha[(int)CULL_COUNTERCLOCKWISE] = getShader(ShaderPickingAlphaCullCCWFile);
+		mShaderGizmoSolid = getShader(ShaderSolidGizmoFile);
+		mShaderGizmoWire = getShader(ShaderWireGizmoFile);
+		mShaderGizmoIcon = getShader(ShaderIconGizmoFile);
+		mShaderGizmoPicking = getShader(ShaderGizmoPickingFile);
+		mShaderGizmoAlphaPicking = getShader(ShaderGizmoPickingAlphaFile);
+		mShaderHandleSolid = getShader(ShaderSolidHandleFile);
+		mShaderHandleWire = getShader(ShaderWireHandleFile);
+		mShaderSelection = getShader(ShaderSelectionFile);
+
+		mSkin = gResources().load<GUISkin>(BuiltinDataFolder + (GUISkinFile + L".asset"));
+	}
+
+	BuiltinEditorResources::~BuiltinEditorResources()
+	{ }
+
+	void BuiltinEditorResources::preprocess()
+	{
+		BuiltinResourcesHelper::importAssets(EditorRawShaderIncludeFolder, EditorShaderIncludeFolder, mResourceManifest); // Hidden dependency: Includes must be imported before shaders
+		BuiltinResourcesHelper::importAssets(EditorRawShaderFolder, EditorShaderFolder, mResourceManifest);
+		BuiltinResourcesHelper::importAssets(EditorRawSkinFolder, EditorSkinFolder, mResourceManifest);
+
+		// Generate different sizes of resource icons
+		generateResourceIcons(EditorIconFolder, mResourceManifest);
+
+		// Import fonts
+		BuiltinResourcesHelper::importFont(BuiltinRawDataFolder + DefaultFontFilename, DefaultFontFilename, 
+			BuiltinDataFolder, { DefaultFontSize }, true, mResourceManifest);
+
+		BuiltinResourcesHelper::importFont(BuiltinRawDataFolder + DefaultFontFilename, DefaultAAFontFilename, 
+			BuiltinDataFolder, { TitleFontSize }, true, mResourceManifest);
+
+		// Generate & save GUI sprite textures
+		BuiltinResourcesHelper::generateSpriteTextures(EditorSkinFolder, mResourceManifest);
+
+		// Generate & save GUI skin
+		{
+			GUISkinPtr skin = generateGUISkin();
+			Path outputPath = FileSystem::getWorkingDirectoryPath() + BuiltinDataFolder + (GUISkinFile + L".asset");
+
+			HResource skinResource;
+			if (FileSystem::exists(outputPath))
+				skinResource = gResources().load(outputPath);
+
+			if (skinResource.isLoaded())
+				gResources().update(skinResource, skin);
+			else
+				skinResource = gResources()._createResourceHandle(skin);
+
+			gResources().save(skinResource, outputPath, true);
+			mResourceManifest->registerResource(skinResource.getUUID(), outputPath);
+		}
+
+		Resources::instance().unloadAllUnused();
+	}
+
+	void BuiltinEditorResources::generateResourceIcons(const Path& inputFolder, const ResourceManifestPtr& manifest)
+	{
+		if (!FileSystem::exists(inputFolder))
+			return;
+
+		WString iconsToProcess[] = { FolderIconTex, FontIconTex, MeshIconTex, TextureIconTex, PlainTextIconTex, 
+			ScriptCodeIconTex, ShaderIconTex, ShaderIncludeIconTex, MaterialIconTex, SpriteTextureIconTex, PrefabIconTex,
+			GUISkinIconTex };
+
+		PixelDataPtr srcData[sizeof(iconsToProcess)];
+
+		UINT32 idx = 0;
+		for (auto& iconName : iconsToProcess)
+		{
+			Path path = inputFolder + (iconName + L".asset");
+
+			HTexture source = gResources().load<Texture>(path);
+			if (source != nullptr)
+			{
+				srcData[idx] = source->getProperties().allocateSubresourceBuffer(0);
+				source->readSubresource(gCoreAccessor(), 0, srcData[idx]);
+			}
+
+			idx++;
+		}
+
+		gCoreAccessor().submitToCoreThread(true);
+
+		idx = 0;
+		for (auto& iconName : iconsToProcess)
+		{
+			PixelDataPtr src = srcData[idx];
+
+			PixelDataPtr scaled48 = PixelData::create(48, 48, 1, src->getFormat());
+			PixelUtil::scale(*src, *scaled48);
+
+			PixelDataPtr scaled32 = PixelData::create(32, 32, 1, src->getFormat());
+			PixelUtil::scale(*scaled48, *scaled32);
+
+			PixelDataPtr scaled16 = PixelData::create(16, 16, 1, src->getFormat());
+			PixelUtil::scale(*scaled32, *scaled16);
+
+			HTexture tex48 = Texture::create(scaled48);
+			HTexture tex32 = Texture::create(scaled32);
+			HTexture tex16 = Texture::create(scaled16);
+
+			Path outputPath48 = FileSystem::getWorkingDirectoryPath() + inputFolder + (iconName + L"48.asset");
+			Resources::instance().save(tex48, outputPath48, true);
+			manifest->registerResource(tex48.getUUID(), outputPath48);
+
+			Path outputPath32 = FileSystem::getWorkingDirectoryPath() + inputFolder + (iconName + L"32.asset");
+			Resources::instance().save(tex32, outputPath32, true);
+			manifest->registerResource(tex32.getUUID(), outputPath32);
+
+			Path outputPath16 = FileSystem::getWorkingDirectoryPath() + inputFolder + (iconName + L"16.asset");
+			Resources::instance().save(tex16, outputPath16, true);
+			manifest->registerResource(tex16.getUUID(), outputPath16);
+
+			idx++;
+		}
+	}
+
+	GUISkinPtr BuiltinEditorResources::generateGUISkin()
+	{
+		GUISkinPtr skin = GUISkin::_createPtr();
+
+		Path defaultFontPath = FileSystem::getWorkingDirectoryPath();
+		defaultFontPath.append(BuiltinDataFolder);
+		defaultFontPath.append(DefaultFontFilename + L".asset");
+
+		HFont defaultFont = gResources().load<Font>(defaultFontPath);
+
+		Path defaultAAFontPath = FileSystem::getWorkingDirectoryPath();
+		defaultAAFontPath.append(BuiltinDataFolder);
+		defaultAAFontPath.append(DefaultAAFontFilename + L".asset");
+
+		HFont defaultAAFont = gResources().load<Font>(defaultAAFontPath);
+
+		// Blank entry
+		GUIElementStyle blankStyle;
+
+		skin->setStyle("Blank", blankStyle);
+		skin->setStyle(GUITexture::getGUITypeName(), blankStyle);
+
+		// Label
+		GUIElementStyle labelStyle;
+		labelStyle.font = defaultFont;
+		labelStyle.fontSize = DefaultFontSize;
+		labelStyle.fixedWidth = false;
+		labelStyle.fixedHeight = true;
+		labelStyle.height = 14;
+		labelStyle.minWidth = 10;
+		labelStyle.normal.textColor = TextNormalColor;
+
+		skin->setStyle(GUILabel::getGUITypeName(), labelStyle);
+
+		// Window frame
+		GUIElementStyle windowFrameStyle;
+		windowFrameStyle.normal.texture = getGUITexture(WindowFrameNormal);
+		windowFrameStyle.focused.texture = getGUITexture(WindowFrameFocused);
+		windowFrameStyle.border.left = 1;
+		windowFrameStyle.border.right = 1;
+		windowFrameStyle.border.top = 1;
+		windowFrameStyle.border.bottom = 1;
+
+		skin->setStyle("WindowFrame", windowFrameStyle);
+
+		// Button
+		GUIElementStyle buttonStyle;
+		buttonStyle.normal.texture = getGUITexture(ButtonNormalTex);
+		buttonStyle.hover.texture = getGUITexture(ButtonHoverTex);
+		buttonStyle.active.texture = getGUITexture(ButtonActiveTex);
+		buttonStyle.normalOn.texture = getGUITexture(ButtonActiveTex);
+		buttonStyle.hoverOn.texture = getGUITexture(ButtonActiveTex);
+		buttonStyle.activeOn.texture = getGUITexture(ButtonActiveTex);
+		buttonStyle.normal.textColor = TextNormalColor;
+		buttonStyle.hover.textColor = TextNormalColor;
+		buttonStyle.active.textColor = TextActiveColor;
+		buttonStyle.normalOn.textColor = TextActiveColor;
+		buttonStyle.hoverOn.textColor = TextActiveColor;
+		buttonStyle.activeOn.textColor = TextActiveColor;
+		buttonStyle.border.left = 2;
+		buttonStyle.border.right = 2;
+		buttonStyle.border.top = 2;
+		buttonStyle.border.bottom = 4;
+		buttonStyle.contentOffset.top = 2;
+		buttonStyle.contentOffset.left = 3;
+		buttonStyle.contentOffset.right = 3;
+		buttonStyle.margins.bottom = 2;
+		buttonStyle.fixedHeight = true;
+		buttonStyle.height = 21;
+		buttonStyle.minWidth = 20;
+		buttonStyle.font = defaultFont;
+		buttonStyle.fontSize = DefaultFontSize;
+		buttonStyle.textHorzAlign = THA_Center;
+		buttonStyle.textVertAlign = TVA_Center;
+
+		skin->setStyle(GUIButton::getGUITypeName(), buttonStyle);
+
+		// Left edge button
+		GUIElementStyle leftButtonStyle;
+		leftButtonStyle.normal.texture = getGUITexture(ButtonLeftNormalTex);
+		leftButtonStyle.hover.texture = getGUITexture(ButtonLeftHoverTex);
+		leftButtonStyle.active.texture = getGUITexture(ButtonLeftActiveTex);
+		leftButtonStyle.normalOn.texture = getGUITexture(ButtonLeftActiveTex);
+		leftButtonStyle.hoverOn.texture = getGUITexture(ButtonLeftActiveTex);
+		leftButtonStyle.activeOn.texture = getGUITexture(ButtonLeftActiveTex);
+		leftButtonStyle.normal.textColor = TextNormalColor;
+		leftButtonStyle.hover.textColor = TextNormalColor;
+		leftButtonStyle.active.textColor = TextActiveColor;
+		leftButtonStyle.normalOn.textColor = TextActiveColor;
+		leftButtonStyle.hoverOn.textColor = TextActiveColor;
+		leftButtonStyle.activeOn.textColor = TextActiveColor;
+		leftButtonStyle.border.left = 7;
+		leftButtonStyle.border.right = 2;
+		leftButtonStyle.border.top = 2;
+		leftButtonStyle.border.bottom = 4;
+		leftButtonStyle.contentOffset.top = 2;
+		leftButtonStyle.contentOffset.left = 7;
+		leftButtonStyle.contentOffset.right = 3;
+		leftButtonStyle.margins.bottom = 2;
+		leftButtonStyle.fixedHeight = true;
+		leftButtonStyle.height = 21;
+		leftButtonStyle.minWidth = 20;
+		leftButtonStyle.font = defaultFont;
+		leftButtonStyle.fontSize = DefaultFontSize;
+		leftButtonStyle.textHorzAlign = THA_Center;
+		leftButtonStyle.textVertAlign = TVA_Center;
+
+		skin->setStyle("ButtonLeft", leftButtonStyle);
+
+		// Right edge button
+		GUIElementStyle rightButtonStyle;
+		rightButtonStyle.normal.texture = getGUITexture(ButtonRightNormalTex);
+		rightButtonStyle.hover.texture = getGUITexture(ButtonRightHoverTex);
+		rightButtonStyle.active.texture = getGUITexture(ButtonRightActiveTex);
+		rightButtonStyle.normalOn.texture = getGUITexture(ButtonRightActiveTex);
+		rightButtonStyle.hoverOn.texture = getGUITexture(ButtonRightActiveTex);
+		rightButtonStyle.activeOn.texture = getGUITexture(ButtonRightActiveTex);
+		rightButtonStyle.normal.textColor = TextNormalColor;
+		rightButtonStyle.hover.textColor = TextNormalColor;
+		rightButtonStyle.active.textColor = TextActiveColor;
+		rightButtonStyle.normalOn.textColor = TextActiveColor;
+		rightButtonStyle.hoverOn.textColor = TextActiveColor;
+		rightButtonStyle.activeOn.textColor = TextActiveColor;
+		rightButtonStyle.border.left = 2;
+		rightButtonStyle.border.right = 7;
+		rightButtonStyle.border.top = 2;
+		rightButtonStyle.border.bottom = 4;
+		rightButtonStyle.contentOffset.top = 2;
+		rightButtonStyle.contentOffset.left = 3;
+		rightButtonStyle.contentOffset.right = 7;
+		rightButtonStyle.margins.bottom = 2;
+		rightButtonStyle.fixedHeight = true;
+		rightButtonStyle.height = 21;
+		rightButtonStyle.minWidth = 20;
+		rightButtonStyle.font = defaultFont;
+		rightButtonStyle.fontSize = DefaultFontSize;
+		rightButtonStyle.textHorzAlign = THA_Center;
+		rightButtonStyle.textVertAlign = TVA_Center;
+
+		skin->setStyle("ButtonRight", rightButtonStyle);
+
+		// Toggle
+		GUIElementStyle toggleStyle;
+		toggleStyle.normal.texture = getGUITexture(ToggleNormalTex);
+		toggleStyle.hover.texture = getGUITexture(ToggleHoverTex);
+		toggleStyle.active.texture = toggleStyle.hover.texture;
+		toggleStyle.normalOn.texture = getGUITexture(ToggleNormalOnTex);
+		toggleStyle.hoverOn.texture = getGUITexture(ToggleHoverOnTex);
+		toggleStyle.activeOn.texture = toggleStyle.hoverOn.texture;
+		toggleStyle.fixedHeight = true;
+		toggleStyle.fixedWidth = true;
+		toggleStyle.margins.bottom = 2;
+		toggleStyle.height = 15;
+		toggleStyle.width = 13;
+
+		skin->setStyle(GUIToggle::getGUITypeName(), toggleStyle);
+
+		// Color
+		GUIElementStyle colorStyle;
+		colorStyle.margins.left = 2;
+		colorStyle.margins.right = 2;
+		colorStyle.margins.top = 2;
+		colorStyle.margins.bottom = 2;
+		colorStyle.fixedHeight = true;
+		colorStyle.height = 15;
+		colorStyle.minWidth = 10;
+
+		skin->setStyle(GUIColor::getGUITypeName(), colorStyle);
+
+		// Window background texture
+		GUIElementStyle windowBgStyle;
+		windowBgStyle.normal.texture = getGUITexture(WindowBackgroundTex);
+
+		skin->setStyle("WindowBackground", windowBgStyle);
+
+		// Window tab bar background
+		GUIElementStyle tabBarBgStyle;
+		tabBarBgStyle.normal.texture = getGUITexture(TabBarBackgroundTex);
+		tabBarBgStyle.fixedHeight = true;
+		tabBarBgStyle.height = 16;
+
+		skin->setStyle("TabBarBackground", tabBarBgStyle);
+
+		// Tabbed title bar tab button
+		GUIElementStyle tabbedBarButton;
+		tabbedBarButton.normal.texture = getGUITexture(TabButtonNormalTex);
+		tabbedBarButton.hover.texture = tabbedBarButton.normal.texture;
+		tabbedBarButton.active.texture = getGUITexture(TabButtonFocusedTex);
+		tabbedBarButton.normalOn.texture = tabbedBarButton.active.texture;
+		tabbedBarButton.hoverOn.texture = tabbedBarButton.active.texture;
+		tabbedBarButton.activeOn.texture = tabbedBarButton.active.texture;
+		tabbedBarButton.normal.textColor = TextNormalColor;
+		tabbedBarButton.hover.textColor = TextNormalColor;
+		tabbedBarButton.active.textColor = TextActiveColor;
+		tabbedBarButton.normalOn.textColor = TextActiveColor;
+		tabbedBarButton.hoverOn.textColor = TextActiveColor;
+		tabbedBarButton.activeOn.textColor = TextActiveColor;
+		tabbedBarButton.border.left = 12;
+		tabbedBarButton.border.right = 12;
+		tabbedBarButton.margins.left = 5;
+		tabbedBarButton.margins.right = 5;
+		tabbedBarButton.contentOffset.top = 3;
+		tabbedBarButton.contentOffset.left = 6;
+		tabbedBarButton.contentOffset.right = 6;
+		tabbedBarButton.fixedHeight = true;
+		tabbedBarButton.height = 15;
+		tabbedBarButton.minWidth = 24;
+		tabbedBarButton.maxWidth = 110;
+		tabbedBarButton.font = defaultFont;
+		tabbedBarButton.fontSize = DefaultFontSize;
+		tabbedBarButton.textHorzAlign = THA_Center;
+		tabbedBarButton.textVertAlign = TVA_Center;
+
+		skin->setStyle("TabbedBarBtn", tabbedBarButton);
+
+		// Tabbed title bar drag/drop button
+		GUIElementStyle tabbedBarDropButton;
+		tabbedBarDropButton.fixedHeight = true;
+		tabbedBarDropButton.fixedWidth = true;
+		tabbedBarDropButton.height = 13;
+		tabbedBarDropButton.width = 6;
+
+		skin->setStyle("TabbedBarDropArea", tabbedBarDropButton);
+
+		// Window title bar background
+		GUIElementStyle titleBarBgStyle;
+		titleBarBgStyle.normal.texture = getGUITexture(TitleBarBackgroundTex);
+		titleBarBgStyle.fixedHeight = true;
+		titleBarBgStyle.height = 17;
+
+		skin->setStyle("TitleBarBackground", titleBarBgStyle);
+
+		// Window minimize button
+		GUIElementStyle winMinButtonStyle;
+		winMinButtonStyle.normal.texture = getGUITexture(MinButtonNormalTex);
+		winMinButtonStyle.hover.texture = getGUITexture(MinButtonHoverTex);
+		winMinButtonStyle.active.texture = getGUITexture(MinButtonActiveTex);
+		winMinButtonStyle.fixedHeight = true;
+		winMinButtonStyle.fixedWidth = true;
+		winMinButtonStyle.height = 14;
+		winMinButtonStyle.width = 14;
+
+		skin->setStyle("WinMinimizeBtn", winMinButtonStyle);
+
+		// Window maximize button
+		GUIElementStyle winMaxButtonStyle;
+		winMaxButtonStyle.normal.texture = getGUITexture(MaxButtonNormalTex);
+		winMaxButtonStyle.hover.texture = getGUITexture(MaxButtonHoverTex);
+		winMaxButtonStyle.active.texture = getGUITexture(MaxButtonActiveTex);
+		winMaxButtonStyle.fixedHeight = true;
+		winMaxButtonStyle.fixedWidth = true;
+		winMaxButtonStyle.height = 14;
+		winMaxButtonStyle.width = 14;
+
+		skin->setStyle("WinMaximizeBtn", winMaxButtonStyle);
+
+		// Window close button
+		GUIElementStyle winCloseButtonStyle;
+		winCloseButtonStyle.normal.texture = getGUITexture(CloseButtonNormalTex);
+		winCloseButtonStyle.hover.texture = getGUITexture(CloseButtonHoverTex);
+		winCloseButtonStyle.active.texture = getGUITexture(CloseButtonActiveTex);
+		winCloseButtonStyle.fixedHeight = true;
+		winCloseButtonStyle.fixedWidth = true;
+		winCloseButtonStyle.height = 14;
+		winCloseButtonStyle.width = 14;
+
+		skin->setStyle("WinCloseBtn", winCloseButtonStyle);
+
+		// Input box
+		GUIElementStyle inputBoxStyle;
+		inputBoxStyle.normal.texture = getGUITexture(InputBoxNormalTex);
+		inputBoxStyle.hover.texture = getGUITexture(InputBoxHoverTex);
+		inputBoxStyle.focused.texture = getGUITexture(InputBoxFocusedTex);
+		inputBoxStyle.active.texture = inputBoxStyle.normal.texture;
+		inputBoxStyle.normal.textColor = TextNormalColor;
+		inputBoxStyle.hover.textColor = TextNormalColor;
+		inputBoxStyle.focused.textColor = TextNormalColor;
+		inputBoxStyle.active.textColor = TextNormalColor;
+		inputBoxStyle.border.left = 4;
+		inputBoxStyle.border.right = 4;
+		inputBoxStyle.border.top = 4;
+		inputBoxStyle.border.bottom = 6;
+		inputBoxStyle.contentOffset.left = 4;
+		inputBoxStyle.contentOffset.right = 4;
+		inputBoxStyle.contentOffset.top = 4;
+		inputBoxStyle.contentOffset.bottom = 4;
+		inputBoxStyle.margins.bottom = 2;
+		inputBoxStyle.fixedHeight = true;
+		inputBoxStyle.height = 21;
+		inputBoxStyle.minWidth = 10;
+		inputBoxStyle.font = defaultFont;
+		inputBoxStyle.fontSize = DefaultFontSize;
+		inputBoxStyle.textHorzAlign = THA_Left;
+		inputBoxStyle.textVertAlign = TVA_Top;
+
+		skin->setStyle(GUIInputBox::getGUITypeName(), inputBoxStyle);
+
+		/************************************************************************/
+		/* 								SCROLL BAR                      		*/
+		/************************************************************************/
+
+		// Up button
+		GUIElementStyle scrollUpBtnStyle;
+		scrollUpBtnStyle.normal.texture = getGUITexture(ScrollBarUpNormalTex);
+		scrollUpBtnStyle.hover.texture = getGUITexture(ScrollBarUpHoverTex);
+		scrollUpBtnStyle.active.texture = getGUITexture(ScrollBarUpActiveTex);
+		scrollUpBtnStyle.fixedHeight = true;
+		scrollUpBtnStyle.fixedWidth = true;
+		scrollUpBtnStyle.height = 11;
+		scrollUpBtnStyle.width = 13;
+
+		skin->setStyle("ScrollUpBtn", scrollUpBtnStyle);
+
+		// Down button
+		GUIElementStyle scrollDownBtnStyle;
+		scrollDownBtnStyle.normal.texture = getGUITexture(ScrollBarDownNormalTex);
+		scrollDownBtnStyle.hover.texture = getGUITexture(ScrollBarDownHoverTex);
+		scrollDownBtnStyle.active.texture = getGUITexture(ScrollBarDownActiveTex);
+		scrollDownBtnStyle.fixedHeight = true;
+		scrollDownBtnStyle.fixedWidth = true;
+		scrollDownBtnStyle.height = 11;
+		scrollDownBtnStyle.width = 13;
+
+		skin->setStyle("ScrollDownBtn", scrollDownBtnStyle);
+
+		// Left button
+		GUIElementStyle scrollLeftBtnStyle;
+		scrollLeftBtnStyle.normal.texture = getGUITexture(ScrollBarLeftNormalTex);
+		scrollLeftBtnStyle.hover.texture = getGUITexture(ScrollBarLeftHoverTex);
+		scrollLeftBtnStyle.active.texture = getGUITexture(ScrollBarLeftActiveTex);
+		scrollLeftBtnStyle.fixedHeight = true;
+		scrollLeftBtnStyle.fixedWidth = true;
+		scrollLeftBtnStyle.height = 13;
+		scrollLeftBtnStyle.width = 11;
+
+		skin->setStyle("ScrollLeftBtn", scrollLeftBtnStyle);
+
+		// Right button
+		GUIElementStyle scrollRightBtnStyle;
+		scrollRightBtnStyle.normal.texture = getGUITexture(ScrollBarRightNormalTex);
+		scrollRightBtnStyle.hover.texture = getGUITexture(ScrollBarRightHoverTex);
+		scrollRightBtnStyle.active.texture = getGUITexture(ScrollBarRightActiveTex);
+		scrollRightBtnStyle.fixedHeight = true;
+		scrollRightBtnStyle.fixedWidth = true;
+		scrollRightBtnStyle.height = 13;
+		scrollRightBtnStyle.width = 11;
+
+		skin->setStyle("ScrollRightBtn", scrollRightBtnStyle);
+
+		// Horizontal handle
+		GUIElementStyle scrollBarHorzBtnStyle;
+		scrollBarHorzBtnStyle.normal.texture = getGUITexture(ScrollBarHandleHorzNormalTex);
+		scrollBarHorzBtnStyle.hover.texture = getGUITexture(ScrollBarHandleHorzHoverTex);
+		scrollBarHorzBtnStyle.active.texture = getGUITexture(ScrollBarHandleHorzActiveTex);
+		scrollBarHorzBtnStyle.fixedHeight = true;
+		scrollBarHorzBtnStyle.fixedWidth = false;
+		scrollBarHorzBtnStyle.width = 10;
+		scrollBarHorzBtnStyle.height = 13;
+		scrollBarHorzBtnStyle.border.left = 4;
+		scrollBarHorzBtnStyle.border.right = 4;
+
+		skin->setStyle("ScrollBarHorzBtn", scrollBarHorzBtnStyle);
+
+		// Vertical handle
+		GUIElementStyle scrollBarVertBtnStyle;
+		scrollBarVertBtnStyle.normal.texture = getGUITexture(ScrollBarHandleVertNormalTex);
+		scrollBarVertBtnStyle.hover.texture = getGUITexture(ScrollBarHandleVertHoverTex);
+		scrollBarVertBtnStyle.active.texture = getGUITexture(ScrollBarHandleVertActiveTex);
+		scrollBarVertBtnStyle.fixedHeight = false;
+		scrollBarVertBtnStyle.fixedWidth = true;
+		scrollBarVertBtnStyle.width = 13;
+		scrollBarVertBtnStyle.height = 10;
+		scrollBarVertBtnStyle.border.top = 4;
+		scrollBarVertBtnStyle.border.bottom = 4;
+
+		skin->setStyle("ScrollBarVertBtn", scrollBarVertBtnStyle);
+
+		// Vertical scroll bar
+		GUIElementStyle vertScrollBarStyle;
+		vertScrollBarStyle.normal.texture = getGUITexture(ScrollBarVBgTex);
+		vertScrollBarStyle.hover.texture = vertScrollBarStyle.normal.texture;
+		vertScrollBarStyle.active.texture = vertScrollBarStyle.normal.texture;
+		vertScrollBarStyle.fixedHeight = false;
+		vertScrollBarStyle.fixedWidth = true;
+		vertScrollBarStyle.minHeight = 8;
+		vertScrollBarStyle.width = 16;
+
+		skin->setStyle("ScrollBarVert", vertScrollBarStyle);
+
+		// Horizontal scroll bar
+		GUIElementStyle horzScrollBarStyle;
+		horzScrollBarStyle.normal.texture = getGUITexture(ScrollBarHBgTex);
+		horzScrollBarStyle.hover.texture = horzScrollBarStyle.normal.texture;
+		horzScrollBarStyle.active.texture = horzScrollBarStyle.normal.texture;
+		horzScrollBarStyle.fixedHeight = true;
+		horzScrollBarStyle.fixedWidth = false;
+		horzScrollBarStyle.minWidth = 8;
+		horzScrollBarStyle.height = 16;
+
+		skin->setStyle("ScrollBarHorz", horzScrollBarStyle);
+
+		/************************************************************************/
+		/* 								DROP DOWN BOX                      		*/
+		/************************************************************************/
+
+		// ListBox button
+		GUIElementStyle dropDownListStyle;
+		dropDownListStyle.normal.texture = getGUITexture(DropDownBtnNormalTex);
+		dropDownListStyle.hover.texture = getGUITexture(DropDownBtnHoverTex);
+		dropDownListStyle.active.texture = getGUITexture(DropDownBtnActiveTex);
+		dropDownListStyle.normalOn.texture = dropDownListStyle.active.texture;
+		dropDownListStyle.hoverOn.texture = dropDownListStyle.active.texture;
+		dropDownListStyle.activeOn.texture = dropDownListStyle.active.texture;
+		dropDownListStyle.normal.textColor = TextNormalColor;
+		dropDownListStyle.hover.textColor = TextNormalColor;
+		dropDownListStyle.active.textColor = TextNormalColor;
+		dropDownListStyle.normalOn.textColor = TextNormalColor;
+		dropDownListStyle.hoverOn.textColor = TextNormalColor;
+		dropDownListStyle.activeOn.textColor = TextNormalColor;
+		dropDownListStyle.fixedHeight = true;
+		dropDownListStyle.fixedWidth = false;
+		dropDownListStyle.height = 21;
+		dropDownListStyle.minWidth = 20;
+		dropDownListStyle.contentOffset.left = 3;
+		dropDownListStyle.contentOffset.right = 18;
+		dropDownListStyle.contentOffset.top = 2;
+		dropDownListStyle.contentOffset.bottom = 2;
+		dropDownListStyle.border.left = 2;
+		dropDownListStyle.border.right = 16;
+		dropDownListStyle.border.top = 2;
+		dropDownListStyle.border.bottom = 4;
+		dropDownListStyle.margins.bottom = 2;
+		dropDownListStyle.font = defaultFont;
+		dropDownListStyle.fontSize = DefaultFontSize;
+		dropDownListStyle.textHorzAlign = THA_Left;
+		dropDownListStyle.textVertAlign = TVA_Center;
+
+		skin->setStyle(GUIListBox::getGUITypeName(), dropDownListStyle);
+
+		// DropDown scroll up button
+		GUIElementStyle dropDownScrollUpBtnStyle;
+		dropDownScrollUpBtnStyle.normal.texture = getGUITexture(DropDownBoxBtnUpNormalTex);
+		dropDownScrollUpBtnStyle.hover.texture = getGUITexture(DropDownBoxBtnUpHoverTex);
+		dropDownScrollUpBtnStyle.active.texture = dropDownScrollUpBtnStyle.hover.texture;
+		dropDownScrollUpBtnStyle.fixedHeight = true;
+		dropDownScrollUpBtnStyle.fixedWidth = true;
+		dropDownScrollUpBtnStyle.width = 8;
+		dropDownScrollUpBtnStyle.height = 12;
+
+		skin->setStyle("ListBoxScrollUpBtn", dropDownScrollUpBtnStyle);
+		skin->setStyle("MenuBarScrollUpBtn", dropDownScrollUpBtnStyle);
+		skin->setStyle("ContextMenuScrollUpBtn", dropDownScrollUpBtnStyle);
+
+		// DropDown scroll down button
+		GUIElementStyle dropDownScrollDownBtnStyle;
+		dropDownScrollDownBtnStyle.normal.texture = getGUITexture(DropDownBoxBtnDownNormalTex);
+		dropDownScrollDownBtnStyle.hover.texture = getGUITexture(DropDownBoxBtnDownHoverTex);
+		dropDownScrollDownBtnStyle.active.texture = dropDownScrollDownBtnStyle.hover.texture;
+		dropDownScrollDownBtnStyle.fixedHeight = true;
+		dropDownScrollDownBtnStyle.fixedWidth = true;
+		dropDownScrollDownBtnStyle.width = 8;
+		dropDownScrollDownBtnStyle.height = 12;
+
+		skin->setStyle("ListBoxScrollDownBtn", dropDownScrollDownBtnStyle);
+		skin->setStyle("MenuBarScrollDownBtn", dropDownScrollDownBtnStyle);
+		skin->setStyle("ContextMenuScrollDownBtn", dropDownScrollDownBtnStyle);
+
+		// DropDown handle
+		GUIElementStyle dropDownScrollHandleStyle;
+		dropDownScrollHandleStyle.normal.texture = getGUITexture(DropDownBoxHandleTex);
+		dropDownScrollHandleStyle.fixedHeight = false;
+		dropDownScrollHandleStyle.fixedWidth = true;
+		dropDownScrollHandleStyle.height = 8;
+		dropDownScrollHandleStyle.width = 8;
+
+		skin->setStyle("ListBoxHandle", dropDownScrollHandleStyle);
+		skin->setStyle("MenuBarHandle", dropDownScrollHandleStyle);
+		skin->setStyle("ContextMenuHandle", dropDownScrollHandleStyle);
+
+		// DropDown sidebar background
+		GUIElementStyle dropDownSidebarBg;
+		dropDownSidebarBg.normal.texture = getGUITexture(DropDownBoxSideBgTex);
+		dropDownSidebarBg.fixedHeight = false;
+		dropDownSidebarBg.fixedWidth = true;
+		dropDownSidebarBg.height = 8;
+		dropDownSidebarBg.width = 9;
+		dropDownSidebarBg.border.left = 1;
+		dropDownSidebarBg.border.top = 1;
+		dropDownSidebarBg.border.bottom = 1;
+
+		skin->setStyle("ListBoxSidebarBg", dropDownSidebarBg);
+		skin->setStyle("MenuBarSidebarBg", dropDownSidebarBg);
+		skin->setStyle("ContextMenuSidebarBg", dropDownSidebarBg);
+
+		// DropDown entry button
+		GUIElementStyle dropDownEntryBtnStyle;
+		dropDownEntryBtnStyle.normal.texture = getGUITexture(DropDownBoxEntryNormalTex);
+		dropDownEntryBtnStyle.hover.texture = getGUITexture(DropDownBoxEntryHoverTex);
+		dropDownEntryBtnStyle.active.texture = dropDownEntryBtnStyle.hover.texture;
+		dropDownEntryBtnStyle.normalOn.texture = dropDownEntryBtnStyle.hover.texture;
+		dropDownEntryBtnStyle.hoverOn.texture = dropDownEntryBtnStyle.hover.texture;
+		dropDownEntryBtnStyle.activeOn.texture = dropDownEntryBtnStyle.hover.texture;
+		dropDownEntryBtnStyle.normal.textColor = TextNormalColor;
+		dropDownEntryBtnStyle.hover.textColor = TextNormalColor;
+		dropDownEntryBtnStyle.active.textColor = TextNormalColor;
+		dropDownEntryBtnStyle.normalOn.textColor = TextNormalColor;
+		dropDownEntryBtnStyle.hoverOn.textColor = TextNormalColor;
+		dropDownEntryBtnStyle.activeOn.textColor = TextNormalColor;
+		dropDownEntryBtnStyle.fixedHeight = true;
+		dropDownEntryBtnStyle.fixedWidth = false;
+		dropDownEntryBtnStyle.height = 16;
+		dropDownEntryBtnStyle.width = 30;
+		dropDownEntryBtnStyle.font = defaultFont;
+		dropDownEntryBtnStyle.fontSize = DefaultFontSize;
+		dropDownEntryBtnStyle.textHorzAlign = THA_Left;
+		dropDownEntryBtnStyle.textVertAlign = TVA_Center;
+
+		skin->setStyle(GUIDropDownContent::ENTRY_STYLE_TYPE, dropDownEntryBtnStyle);
+
+		// DropDown toggle entry button
+		GUIElementStyle dropDownToggleEntryBtnStyle;
+		dropDownToggleEntryBtnStyle.normal.texture = getGUITexture(DropDownBoxEntryToggleNormalTex);
+		dropDownToggleEntryBtnStyle.hover.texture = getGUITexture(DropDownBoxEntryToggleHoverTex);
+		dropDownToggleEntryBtnStyle.active.texture = dropDownToggleEntryBtnStyle.hover.texture;
+		dropDownToggleEntryBtnStyle.normalOn.texture = getGUITexture(DropDownBoxEntryToggleNormalOnTex);
+		dropDownToggleEntryBtnStyle.hoverOn.texture = getGUITexture(DropDownBoxEntryToggleHoverOnTex);
+		dropDownToggleEntryBtnStyle.activeOn.texture = dropDownToggleEntryBtnStyle.hoverOn.texture;
+		dropDownToggleEntryBtnStyle.normal.textColor = TextNormalColor;
+		dropDownToggleEntryBtnStyle.hover.textColor = TextNormalColor;
+		dropDownToggleEntryBtnStyle.active.textColor = TextNormalColor;
+		dropDownToggleEntryBtnStyle.normalOn.textColor = TextNormalColor;
+		dropDownToggleEntryBtnStyle.hoverOn.textColor = TextNormalColor;
+		dropDownToggleEntryBtnStyle.activeOn.textColor = TextNormalColor;
+		dropDownToggleEntryBtnStyle.fixedHeight = true;
+		dropDownToggleEntryBtnStyle.fixedWidth = false;
+		dropDownToggleEntryBtnStyle.height = 18;
+		dropDownToggleEntryBtnStyle.width = 30;
+		dropDownToggleEntryBtnStyle.border.left = 17;
+		dropDownToggleEntryBtnStyle.contentOffset.left = 17;
+		dropDownToggleEntryBtnStyle.font = defaultFont;
+		dropDownToggleEntryBtnStyle.fontSize = DefaultFontSize;
+		dropDownToggleEntryBtnStyle.textHorzAlign = THA_Left;
+		dropDownToggleEntryBtnStyle.textVertAlign = TVA_Center;
+
+		skin->setStyle(GUIDropDownContent::ENTRY_TOGGLE_STYLE_TYPE, dropDownToggleEntryBtnStyle);
+
+		// DropDown entry button with expand
+		GUIElementStyle dropDownEntryExpBtnStyle;
+		dropDownEntryExpBtnStyle.normal.texture = getGUITexture(DropDownBoxEntryExpNormalTex);
+		dropDownEntryExpBtnStyle.hover.texture = getGUITexture(DropDownBoxEntryExpHoverTex);
+		dropDownEntryExpBtnStyle.active.texture = dropDownEntryExpBtnStyle.hover.texture;
+		dropDownEntryExpBtnStyle.normalOn.texture = dropDownEntryExpBtnStyle.hover.texture;
+		dropDownEntryExpBtnStyle.hoverOn.texture = dropDownEntryExpBtnStyle.hover.texture;
+		dropDownEntryExpBtnStyle.activeOn.texture = dropDownEntryExpBtnStyle.hover.texture;
+		dropDownEntryExpBtnStyle.normal.textColor = TextNormalColor;
+		dropDownEntryExpBtnStyle.hover.textColor = TextNormalColor;
+		dropDownEntryExpBtnStyle.active.textColor = TextNormalColor;
+		dropDownEntryExpBtnStyle.normalOn.textColor = TextNormalColor;
+		dropDownEntryExpBtnStyle.hoverOn.textColor = TextNormalColor;
+		dropDownEntryExpBtnStyle.activeOn.textColor = TextNormalColor;
+		dropDownEntryExpBtnStyle.fixedHeight = true;
+		dropDownEntryExpBtnStyle.fixedWidth = false;
+		dropDownEntryExpBtnStyle.height = 16;
+		dropDownEntryExpBtnStyle.width = 30;
+		dropDownEntryExpBtnStyle.border.right = 13;
+		dropDownEntryExpBtnStyle.font = defaultFont;
+		dropDownEntryExpBtnStyle.fontSize = DefaultFontSize;
+		dropDownEntryExpBtnStyle.textHorzAlign = THA_Left;
+		dropDownEntryExpBtnStyle.textVertAlign = TVA_Center;
+
+		skin->setStyle(GUIDropDownContent::ENTRY_EXP_STYLE_TYPE, dropDownEntryExpBtnStyle);
+
+		// Drop down separator
+		GUIElementStyle dropDownSeparatorStyle;
+		dropDownSeparatorStyle.normal.texture = getGUITexture(DropDownSeparatorTex);
+		dropDownSeparatorStyle.fixedHeight = true;
+		dropDownSeparatorStyle.fixedWidth = false;
+		dropDownSeparatorStyle.height = 3;
+		dropDownSeparatorStyle.width = 30;
+
+		skin->setStyle(GUIDropDownContent::SEPARATOR_STYLE_TYPE, dropDownSeparatorStyle);
+
+		// Drop down content
+		GUIElementStyle dropDownContentStyle;
+		dropDownContentStyle.minWidth = 50;
+		dropDownContentStyle.minHeight = 20;
+		dropDownContentStyle.subStyles[GUIDropDownContent::ENTRY_TOGGLE_STYLE_TYPE] = GUIDropDownContent::ENTRY_TOGGLE_STYLE_TYPE;
+		dropDownContentStyle.subStyles[GUIDropDownContent::ENTRY_STYLE_TYPE] = GUIDropDownContent::ENTRY_STYLE_TYPE;
+		dropDownContentStyle.subStyles[GUIDropDownContent::ENTRY_EXP_STYLE_TYPE] = GUIDropDownContent::ENTRY_EXP_STYLE_TYPE;
+		dropDownContentStyle.subStyles[GUIDropDownContent::SEPARATOR_STYLE_TYPE] = GUIDropDownContent::SEPARATOR_STYLE_TYPE;
+
+		skin->setStyle("ListBoxContent", dropDownContentStyle);
+		skin->setStyle("MenuBarContent", dropDownContentStyle);
+		skin->setStyle("ContextMenuContent", dropDownContentStyle);
+
+		// DropDown box frame
+		GUIElementStyle dropDownBoxStyle;
+		dropDownBoxStyle.normal.texture = getGUITexture(DropDownBoxBgTex);
+		dropDownBoxStyle.hover.texture = dropDownBoxStyle.normal.texture;
+		dropDownBoxStyle.active.texture = dropDownBoxStyle.hover.texture;
+		dropDownBoxStyle.fixedHeight = false;
+		dropDownBoxStyle.fixedWidth = false;
+		dropDownBoxStyle.border.left = 2;
+		dropDownBoxStyle.border.right = 2;
+		dropDownBoxStyle.border.top = 2;
+		dropDownBoxStyle.border.bottom = 4;
+		dropDownBoxStyle.margins.left = 6;
+		dropDownBoxStyle.margins.right = 6;
+		dropDownBoxStyle.margins.top = 4;
+		dropDownBoxStyle.margins.bottom = 6;
+
+		skin->setStyle("ListBoxFrame", dropDownBoxStyle);
+		skin->setStyle("MenuBarFrame", dropDownBoxStyle);
+		skin->setStyle("ContextMenuFrame", dropDownBoxStyle);
+
+		/************************************************************************/
+		/* 								TOOLTIP                      			*/
+		/************************************************************************/
+
+		GUIElementStyle tooltipFrameStyle;
+		tooltipFrameStyle.normal.texture = getGUITexture(DropDownBoxBgTex);
+		tooltipFrameStyle.hover.texture = tooltipFrameStyle.normal.texture;
+		tooltipFrameStyle.active.texture = tooltipFrameStyle.hover.texture;
+		tooltipFrameStyle.fixedHeight = false;
+		tooltipFrameStyle.fixedWidth = false;
+		tooltipFrameStyle.border.left = 2;
+		tooltipFrameStyle.border.right = 2;
+		tooltipFrameStyle.border.top = 2;
+		tooltipFrameStyle.border.bottom = 4;
+		tooltipFrameStyle.margins.left = 6;
+		tooltipFrameStyle.margins.right = 6;
+		tooltipFrameStyle.margins.top = 4;
+		tooltipFrameStyle.margins.bottom = 6;
+
+		skin->setStyle(GUITooltip::getFrameStyleName(), tooltipFrameStyle);
+
+		/************************************************************************/
+		/* 								MENU BAR	                     		*/
+		/************************************************************************/
+
+		// MenuBar background
+		GUIElementStyle menuBarBgStyle;
+		menuBarBgStyle.normal.texture = getGUITexture(MenuBarBgTex);
+		menuBarBgStyle.height = 14;
+		menuBarBgStyle.width = 2;
+		menuBarBgStyle.border.bottom = 2;
+
+		skin->setStyle(GUIMenuBar::getBackgroundStyleType(), menuBarBgStyle);
+
+		// MenuBar separator line
+		GUIElementStyle menuBarLineStyle;
+		menuBarLineStyle.normal.texture = getGUITexture(MenuBarLineNormalTex);
+		menuBarLineStyle.normalOn.texture = getGUITexture(MenuBarLineActiveTex);
+		menuBarLineStyle.fixedHeight = true;
+		menuBarLineStyle.height = 1;
+
+		skin->setStyle(GUIMenuBar::getLineStyleType(), menuBarLineStyle);
+
+		// MenuBar Banshee logo
+		GUIElementStyle menuBarBansheeLogoStyle;
+		menuBarBansheeLogoStyle.normal.texture = getGUITexture(MenuBarBansheeLogoTex);
+		menuBarBansheeLogoStyle.fixedHeight = true;
+		menuBarBansheeLogoStyle.fixedWidth = true;
+		menuBarBansheeLogoStyle.height = 46;
+		menuBarBansheeLogoStyle.width = 46;
+
+		skin->setStyle(GUIMenuBar::getLogoStyleType(), menuBarBansheeLogoStyle);
+
+		// MenuBar button
+		GUIElementStyle menuBarBtnStyle;
+		menuBarBtnStyle.normal.texture = getGUITexture(MenuBarBtnNormalTex);
+		menuBarBtnStyle.hover.texture = getGUITexture(MenuBarBtnHoverTex);
+		menuBarBtnStyle.active.texture = getGUITexture(MenuBarBtnActiveTex);
+		menuBarBtnStyle.normalOn.texture = menuBarBtnStyle.active.texture;
+		menuBarBtnStyle.hoverOn.texture = menuBarBtnStyle.active.texture;
+		menuBarBtnStyle.activeOn.texture = menuBarBtnStyle.active.texture;
+		menuBarBtnStyle.normal.textColor = TextNormalColor;
+		menuBarBtnStyle.hover.textColor = TextNormalColor;
+		menuBarBtnStyle.active.textColor = TextActiveColor;
+		menuBarBtnStyle.normalOn.textColor = TextActiveColor;
+		menuBarBtnStyle.hoverOn.textColor = TextActiveColor;
+		menuBarBtnStyle.activeOn.textColor = TextActiveColor;
+		menuBarBtnStyle.fixedHeight = true;
+		menuBarBtnStyle.fixedWidth = false;
+		menuBarBtnStyle.height = 14;
+		menuBarBtnStyle.width = 4;
+		menuBarBtnStyle.margins.left = 2;
+		menuBarBtnStyle.margins.right = 2;
+		menuBarBtnStyle.margins.top = 2;
+		menuBarBtnStyle.margins.bottom = 2;
+		menuBarBtnStyle.font = defaultFont;
+		menuBarBtnStyle.fontSize = DefaultFontSize;
+		menuBarBtnStyle.textHorzAlign = THA_Left;
+		menuBarBtnStyle.textVertAlign = TVA_Top;
+
+		skin->setStyle(GUIMenuBar::getMenuItemButtonStyleType(), menuBarBtnStyle);
+
+		// ToolBar separator
+		GUIElementStyle toolBarSeparator;
+		toolBarSeparator.normal.texture = getGUITexture(ToolBarSeparatorTex);
+		toolBarSeparator.fixedWidth = true;
+		toolBarSeparator.width = 3;
+		toolBarSeparator.height = 32;
+
+		skin->setStyle(GUIMenuBar::getToolBarSeparatorStyleType(), toolBarSeparator);
+
+		// ToolBar button
+		GUIElementStyle toolBarBtnStyle;
+		toolBarBtnStyle.normal.texture = getGUITexture(ToolBarBtnNormalTex);
+		toolBarBtnStyle.hover.texture = getGUITexture(ToolBarBtnHoverTex);
+		toolBarBtnStyle.active.texture = getGUITexture(ToolBarBtnActiveTex);
+		toolBarBtnStyle.normalOn.texture = getGUITexture(ToolBarBtnActiveTex);
+		toolBarBtnStyle.hoverOn.texture = getGUITexture(ToolBarBtnActiveTex);
+		toolBarBtnStyle.activeOn.texture = getGUITexture(ToolBarBtnActiveTex);
+		toolBarBtnStyle.normal.textColor = TextNormalColor;
+		toolBarBtnStyle.hover.textColor = TextNormalColor;
+		toolBarBtnStyle.active.textColor = TextActiveColor;
+		toolBarBtnStyle.normalOn.textColor = TextNormalColor;
+		toolBarBtnStyle.hoverOn.textColor = TextNormalColor;
+		toolBarBtnStyle.activeOn.textColor = TextActiveColor;
+		toolBarBtnStyle.fixedHeight = true;
+		toolBarBtnStyle.fixedWidth = true;
+		toolBarBtnStyle.height = 32;
+		toolBarBtnStyle.width = 32;
+
+		skin->setStyle(GUIMenuBar::getToolBarButtonStyleType(), toolBarBtnStyle);
+
+		/************************************************************************/
+		/* 								DOCK SLIDER	                     		*/
+		/************************************************************************/
+
+		GUIElementStyle dockSliderBtnStyle;
+		dockSliderBtnStyle.normal.texture = getGUITexture(DockSliderNormalTex);
+		dockSliderBtnStyle.hover.texture = dockSliderBtnStyle.normal.texture;
+		dockSliderBtnStyle.active.texture = dockSliderBtnStyle.normal.texture;
+		dockSliderBtnStyle.fixedHeight = false;
+		dockSliderBtnStyle.fixedWidth = false;
+		dockSliderBtnStyle.height = 2;
+		dockSliderBtnStyle.width = 2;
+
+		skin->setStyle("DockSliderBtn", dockSliderBtnStyle);
+
+		/************************************************************************/
+		/* 								TREE VIEW	                     		*/
+		/************************************************************************/
+
+		// Expand button
+		GUIElementStyle treeViewExpandButtonStyle;
+		treeViewExpandButtonStyle.normal.texture = getGUITexture(TreeViewExpandButtonOffNormal);
+		treeViewExpandButtonStyle.hover.texture = getGUITexture(TreeViewExpandButtonOffHover);
+		treeViewExpandButtonStyle.active.texture = treeViewExpandButtonStyle.hover.texture;
+		treeViewExpandButtonStyle.normalOn.texture = getGUITexture(TreeViewExpandButtonOnNormal);
+		treeViewExpandButtonStyle.hoverOn.texture = getGUITexture(TreeViewExpandButtonOnHover);
+		treeViewExpandButtonStyle.activeOn.texture = treeViewExpandButtonStyle.hoverOn.texture;
+		treeViewExpandButtonStyle.fixedHeight = true;
+		treeViewExpandButtonStyle.fixedWidth = true;
+		treeViewExpandButtonStyle.height = 10;
+		treeViewExpandButtonStyle.width = 10;
+
+		skin->setStyle("TreeViewFoldoutBtn", treeViewExpandButtonStyle);
+
+		// Entry
+		GUIElementStyle treeViewEntryStyle;
+		treeViewEntryStyle.font = defaultFont;
+		treeViewEntryStyle.fontSize = DefaultFontSize;
+		treeViewEntryStyle.fixedWidth = false;
+		treeViewEntryStyle.fixedHeight = true;
+		treeViewEntryStyle.height = 16;
+		treeViewEntryStyle.minWidth = 10;
+		treeViewEntryStyle.normal.textColor = TextNormalColor;
+
+		skin->setStyle("TreeViewElementBtn", treeViewEntryStyle);
+
+		// Background
+		GUIElementStyle treeViewBackgroundStyle;
+
+		skin->setStyle("TreeViewBackground", treeViewBackgroundStyle);
+
+		// Selection background
+		GUIElementStyle treeViewSelBackgroundStyle;
+		treeViewSelBackgroundStyle.normal.texture = getGUITexture(SelectionBgTex);
+		treeViewSelBackgroundStyle.fixedHeight = false;
+		treeViewSelBackgroundStyle.fixedWidth = false;
+		treeViewSelBackgroundStyle.height = 2;
+		treeViewSelBackgroundStyle.width = 2;
+
+		skin->setStyle("TreeViewSelectionBackground", treeViewSelBackgroundStyle);
+
+		// Highlight background
+		GUIElementStyle treeViewHLBackgroundStyle;
+		treeViewHLBackgroundStyle.normal.texture = getGUITexture(TreeViewHighlightBackground);
+		treeViewHLBackgroundStyle.fixedHeight = false;
+		treeViewHLBackgroundStyle.fixedWidth = false;
+		treeViewHLBackgroundStyle.height = 2;
+		treeViewHLBackgroundStyle.width = 2;
+
+		skin->setStyle("TreeViewHighlightBackground", treeViewHLBackgroundStyle);
+
+		// Edit box
+		GUIElementStyle treeViewEditBox;
+		treeViewEditBox.normal.texture = getGUITexture(TreeViewEditBox);
+		treeViewEditBox.hover.texture = treeViewEditBox.normal.texture;
+		treeViewEditBox.focused.texture = treeViewEditBox.normal.texture;
+		treeViewEditBox.active.texture = treeViewEditBox.normal.texture;
+		treeViewEditBox.normal.textColor = TextNormalColor;
+		treeViewEditBox.hover.textColor = TextNormalColor;
+		treeViewEditBox.focused.textColor = TextNormalColor;
+		treeViewEditBox.active.textColor = TextNormalColor;
+		treeViewEditBox.border.left = 1;
+		treeViewEditBox.border.right = 1;
+		treeViewEditBox.border.top = 1;
+		treeViewEditBox.border.bottom = 1;
+		treeViewEditBox.margins.left = 1;
+		treeViewEditBox.margins.right = 1;
+		treeViewEditBox.margins.top = 1;
+		treeViewEditBox.margins.bottom = 1;
+		treeViewEditBox.fixedHeight = true;
+		treeViewEditBox.height = 13;
+		treeViewEditBox.minWidth = 10;
+		treeViewEditBox.font = defaultFont;
+		treeViewEditBox.fontSize = DefaultFontSize;
+		treeViewEditBox.textHorzAlign = THA_Left;
+		treeViewEditBox.textVertAlign = TVA_Top;
+
+		skin->setStyle(GUITreeViewEditBox::getGUITypeName(), treeViewEditBox);
+
+		// Element highlight
+		GUIElementStyle treeViewElementHighlight;
+		treeViewElementHighlight.normal.texture = getGUITexture(TreeViewElementHighlight);
+		treeViewElementHighlight.border.left = 1;
+		treeViewElementHighlight.border.right = 1;
+		treeViewElementHighlight.border.top = 1;
+		treeViewElementHighlight.border.bottom = 1;
+
+		skin->setStyle("TreeViewElementHighlight", treeViewElementHighlight);
+
+		// Element separator highlight
+		GUIElementStyle treeViewElementSepHighlight;
+		treeViewElementSepHighlight.normal.texture = getGUITexture(TreeViewElementSepHighlight);
+		treeViewElementSepHighlight.border.left = 1;
+		treeViewElementSepHighlight.border.right = 1;
+		treeViewElementSepHighlight.border.top = 1;
+		treeViewElementSepHighlight.border.bottom = 1;
+
+		skin->setStyle("TreeViewElementSepHighlight", treeViewElementSepHighlight);
+
+		/************************************************************************/
+		/* 							OBJECT DROP FIELD                      		*/
+		/************************************************************************/
+		GUIElementStyle objectDropStyle;
+		objectDropStyle.normal.texture = getGUITexture(ObjectDropBtnNormalTex);
+		objectDropStyle.normalOn.texture = getGUITexture(ObjectDropBtnNormalOnTex);
+		objectDropStyle.hover.texture = objectDropStyle.normal.texture;
+		objectDropStyle.hoverOn.texture = objectDropStyle.normalOn.texture;
+		objectDropStyle.active.texture = objectDropStyle.normal.texture;
+		objectDropStyle.activeOn.texture = objectDropStyle.normalOn.texture;
+		objectDropStyle.normal.textColor = TextNormalColor;
+		objectDropStyle.hover.textColor = TextNormalColor;
+		objectDropStyle.active.textColor = TextNormalColor;
+		objectDropStyle.normalOn.textColor = TextNormalColor;
+		objectDropStyle.hoverOn.textColor = TextNormalColor;
+		objectDropStyle.activeOn.textColor = TextNormalColor;
+		objectDropStyle.border.left = 2;
+		objectDropStyle.border.top = 2;
+		objectDropStyle.border.bottom = 4;
+		objectDropStyle.contentOffset.left = 3;
+		objectDropStyle.contentOffset.right = 1;
+		objectDropStyle.margins.bottom = 2;
+		objectDropStyle.fixedHeight = true;
+		objectDropStyle.height = 21;
+		objectDropStyle.minWidth = 20;
+		objectDropStyle.font = defaultFont;
+		objectDropStyle.fontSize = DefaultFontSize;
+		objectDropStyle.textHorzAlign = THA_Center;
+		objectDropStyle.textVertAlign = TVA_Center;
+
+		skin->setStyle(ObjectFieldDropBtnStyleName, objectDropStyle);
+
+		GUIElementStyle objectClearBtnStyle;
+		objectClearBtnStyle.normal.texture = getGUITexture(ObjectClearBtnNormalTex);
+		objectClearBtnStyle.hover.texture = getGUITexture(ObjectClearBtnHoverTex);
+		objectClearBtnStyle.active.texture = getGUITexture(ObjectClearBtnActiveTex);
+		objectClearBtnStyle.fixedHeight = true;
+		objectClearBtnStyle.fixedWidth = true;
+		objectClearBtnStyle.height = 21;
+		objectClearBtnStyle.width = 16;
+		objectClearBtnStyle.margins.bottom = 2;
+
+		skin->setStyle(ObjectFieldClearBtnStyleName, objectClearBtnStyle);
+
+		GUIElementStyle editorObjectFieldStyle;
+		editorObjectFieldStyle.fixedHeight = true;
+		editorObjectFieldStyle.height = 21;
+		editorObjectFieldStyle.minWidth = 30;
+		editorObjectFieldStyle.subStyles[ObjectFieldLabelStyleName] = GUITextField::getLabelStyleType();
+		editorObjectFieldStyle.subStyles[ObjectFieldDropBtnStyleName] = ObjectFieldDropBtnStyleName;
+		editorObjectFieldStyle.subStyles[ObjectFieldClearBtnStyleName] = ObjectFieldClearBtnStyleName;
+
+		skin->setStyle(ObjectFieldStyleName, editorObjectFieldStyle);
+
+		/************************************************************************/
+		/* 						TEXTURE DROP FIELD                      		*/
+		/************************************************************************/
+		GUIElementStyle textureFieldStyle;
+		textureFieldStyle.minHeight = 15;
+		textureFieldStyle.minWidth = 15;
+		textureFieldStyle.subStyles[TextureFieldDropStyleName] = TextureFieldDropStyleName;
+		textureFieldStyle.subStyles[TextureFieldClearBtnStyleName] = TextureFieldClearBtnStyleName;
+		textureFieldStyle.subStyles[TextureFieldLabelStyleName] = GUITextField::getLabelStyleType();
+
+		skin->setStyle(TextureFieldStyleName, textureFieldStyle);
+
+		GUIElementStyle textureDropStyle;
+		textureDropStyle.font = defaultFont;
+		textureDropStyle.fontSize = DefaultFontSize;
+		textureDropStyle.textHorzAlign = THA_Center;
+		textureDropStyle.textVertAlign = TVA_Center;
+		textureDropStyle.normal.textColor = Color(95 / 255.0f, 95 / 255.0f, 95 / 255.0f, 1.0f);
+		textureDropStyle.normal.texture = getGUITexture(TextureDropTex);
+		textureDropStyle.hover.textColor = textureDropStyle.normal.textColor;
+		textureDropStyle.hover.texture = textureDropStyle.normal.texture;
+		textureDropStyle.active.textColor = textureDropStyle.normal.textColor;
+		textureDropStyle.active.texture = textureDropStyle.normal.texture;
+		textureDropStyle.normalOn.textColor = Color(95 / 255.0f, 95 / 255.0f, 95 / 255.0f, 1.0f);
+		textureDropStyle.normalOn.texture = getGUITexture(TextureDropOnTex);
+		textureDropStyle.hoverOn.textColor = textureDropStyle.normalOn.textColor;
+		textureDropStyle.hoverOn.texture = textureDropStyle.normalOn.texture;
+		textureDropStyle.activeOn.textColor = textureDropStyle.normalOn.textColor;
+		textureDropStyle.activeOn.texture = textureDropStyle.normalOn.texture;
+		textureDropStyle.height = 84;
+		textureDropStyle.width = 82;
+		textureDropStyle.fixedHeight = true;
+		textureDropStyle.fixedWidth = true;
+		textureDropStyle.border.left = 2;
+		textureDropStyle.border.right = 2;
+		textureDropStyle.border.top = 2;
+		textureDropStyle.border.bottom = 4;
+		textureDropStyle.contentOffset.left = 4;
+		textureDropStyle.contentOffset.right = 4;
+		textureDropStyle.contentOffset.top = 4;
+		textureDropStyle.contentOffset.bottom = 4;
+
+		skin->setStyle(TextureFieldDropStyleName, textureDropStyle);
+		
+		GUIElementStyle textureDropClearStyle;
+		textureDropClearStyle.normal.texture = getGUITexture(XButtonNormalTex);
+		textureDropClearStyle.hover.texture = getGUITexture(XButtonHoverTex);
+		textureDropClearStyle.active.texture = getGUITexture(XButtonActiveTex);
+		textureDropClearStyle.fixedWidth = true;
+		textureDropClearStyle.fixedHeight = true;
+		textureDropClearStyle.height = 10;
+		textureDropClearStyle.width = 10;
+
+		skin->setStyle(TextureFieldClearBtnStyleName, textureDropClearStyle);
+
+		/************************************************************************/
+		/* 								EDITOR FIELDS                      		*/
+		/************************************************************************/
+
+		GUIElementStyle editorFieldLabelStyle;
+		editorFieldLabelStyle.font = defaultFont;
+		editorFieldLabelStyle.fontSize = DefaultFontSize;
+		editorFieldLabelStyle.normal.textColor = TextNormalColor;
+		editorFieldLabelStyle.fixedWidth = false;
+		editorFieldLabelStyle.fixedHeight = true;
+		editorFieldLabelStyle.height = 14;
+		editorFieldLabelStyle.minWidth = 10;
+		editorFieldLabelStyle.textHorzAlign = THA_Left;
+
+		skin->setStyle(GUITextField::getLabelStyleType(), editorFieldLabelStyle);
+
+		GUIElementStyle editorIntFieldStyle;
+		editorIntFieldStyle.fixedHeight = true;
+		editorIntFieldStyle.height = 21;
+		editorIntFieldStyle.minWidth = 30;
+		editorIntFieldStyle.subStyles[GUIIntField::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorIntFieldStyle.subStyles[GUIIntField::getInputStyleType()] = GUIInputBox::getGUITypeName();
+
+		skin->setStyle(GUIIntField::getGUITypeName(), editorIntFieldStyle);
+
+		GUIElementStyle editorFloatFieldStyle;
+		editorFloatFieldStyle.fixedHeight = true;
+		editorFloatFieldStyle.height = 21;
+		editorFloatFieldStyle.minWidth = 30;
+		editorFloatFieldStyle.subStyles[GUIFloatField::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorFloatFieldStyle.subStyles[GUIFloatField::getInputStyleType()] = GUIInputBox::getGUITypeName();
+
+		skin->setStyle(GUIFloatField::getGUITypeName(), editorFloatFieldStyle);
+
+		GUIElementStyle editorTextFieldStyle;
+		editorTextFieldStyle.fixedHeight = true;
+		editorTextFieldStyle.height = 21;
+		editorTextFieldStyle.minWidth = 30;
+		editorTextFieldStyle.subStyles[GUITextField::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorTextFieldStyle.subStyles[GUITextField::getInputStyleType()] = GUIInputBox::getGUITypeName();
+
+		skin->setStyle(GUITextField::getGUITypeName(), editorTextFieldStyle);
+
+		GUIElementStyle editorColorFieldStyle;
+		editorColorFieldStyle.fixedHeight = true;
+		editorColorFieldStyle.height = 21;
+		editorColorFieldStyle.minWidth = 30;
+		editorColorFieldStyle.subStyles[GUIColorField::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorColorFieldStyle.subStyles[GUIColorField::getColorInputStyleType()] = GUIColor::getGUITypeName();
+
+		skin->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();
+
+		skin->setStyle(GUIToggleField::getGUITypeName(), editorToggleFieldStyle);
+
+		GUIElementStyle editorVector2FieldStyle;
+		editorVector2FieldStyle.fixedHeight = true;
+		editorVector2FieldStyle.height = 35;
+		editorVector2FieldStyle.minWidth = 30;
+		editorVector2FieldStyle.subStyles[GUIVector2Field::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorVector2FieldStyle.subStyles[GUIVector2Field::getFloatFieldStyleType()] = GUIFloatField::getGUITypeName();
+
+		skin->setStyle(GUIVector2Field::getGUITypeName(), editorVector2FieldStyle);
+
+		GUIElementStyle editorVector3FieldStyle;
+		editorVector3FieldStyle.fixedHeight = true;
+		editorVector3FieldStyle.height = 35;
+		editorVector3FieldStyle.minWidth = 30;
+		editorVector3FieldStyle.subStyles[GUIVector3Field::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorVector3FieldStyle.subStyles[GUIVector3Field::getFloatFieldStyleType()] = GUIFloatField::getGUITypeName();
+
+		skin->setStyle(GUIVector3Field::getGUITypeName(), editorVector3FieldStyle);
+
+		GUIElementStyle editorVector4FieldStyle;
+		editorVector4FieldStyle.fixedHeight = true;
+		editorVector4FieldStyle.height = 35;
+		editorVector4FieldStyle.minWidth = 30;
+		editorVector4FieldStyle.subStyles[GUIVector4Field::getLabelStyleType()] = GUITextField::getLabelStyleType();
+		editorVector4FieldStyle.subStyles[GUIVector4Field::getFloatFieldStyleType()] = GUIFloatField::getGUITypeName();
+
+		skin->setStyle(GUIVector4Field::getGUITypeName(), editorVector4FieldStyle);
+
+		GUIElementStyle editorListBoxFieldStyle;
+		editorListBoxFieldStyle.fixedHeight = true;
+		editorListBoxFieldStyle.height = 21;
+		editorListBoxFieldStyle.minWidth = 30;
+		editorListBoxFieldStyle.subStyles[GUIListBoxField::getLabelStyleType()] = GUIListBoxField::getLabelStyleType();
+		editorListBoxFieldStyle.subStyles[GUIListBoxField::getListBoxStyleType()] = GUIListBox::getGUITypeName();
+
+		skin->setStyle(GUIListBoxField::getGUITypeName(), editorListBoxFieldStyle);
+
+		GUIElementStyle editorSliderFieldStyle;
+		editorSliderFieldStyle.fixedHeight = true;
+		editorSliderFieldStyle.height = 21;
+		editorSliderFieldStyle.minWidth = 30;
+		editorSliderFieldStyle.subStyles[GUISliderField::getLabelStyleType()] = GUISliderField::getLabelStyleType();
+		editorSliderFieldStyle.subStyles[GUISliderField::getInputStyleType()] = GUIInputBox::getGUITypeName();
+		editorSliderFieldStyle.subStyles[GUISliderField::getSliderStyleType()] = GUISliderHorz::getGUITypeName();
+
+		skin->setStyle(GUISliderField::getGUITypeName(), editorSliderFieldStyle);
+
+		/************************************************************************/
+		/* 							     FOLDOUT                      		    */
+		/************************************************************************/
+
+		GUIElementStyle foldoutStyle;
+		foldoutStyle.normal.texture = getGUITexture(FoldoutClosedNormalTex);
+		foldoutStyle.hover.texture = getGUITexture(FoldoutClosedHoverTex);
+		foldoutStyle.active.texture = getGUITexture(FoldoutOpenActiveTex);
+		foldoutStyle.normalOn.texture = getGUITexture(FoldoutOpenNormalTex);
+		foldoutStyle.hoverOn.texture = getGUITexture(FoldoutOpenHoverTex);
+		foldoutStyle.activeOn.texture = getGUITexture(FoldoutOpenActiveTex);
+		foldoutStyle.normal.textColor = TextNormalColor;
+		foldoutStyle.hover.textColor = TextNormalColor;
+		foldoutStyle.active.textColor = TextNormalColor;
+		foldoutStyle.normalOn.textColor = TextNormalColor;
+		foldoutStyle.hoverOn.textColor = TextNormalColor;
+		foldoutStyle.activeOn.textColor = TextNormalColor;
+		foldoutStyle.fixedHeight = true;
+		foldoutStyle.fixedWidth = false;
+		foldoutStyle.height = 21;
+		foldoutStyle.minWidth = 17;
+		foldoutStyle.font = defaultFont;
+		foldoutStyle.fontSize = DefaultFontSize;
+		foldoutStyle.textHorzAlign = THA_Left;
+		foldoutStyle.textVertAlign = TVA_Center;
+		foldoutStyle.contentOffset = RectOffset(16, 0, 0, 0);
+		foldoutStyle.border.left = 15;
+		foldoutStyle.border.right = 2;
+		foldoutStyle.border.top = 2;
+		foldoutStyle.border.bottom = 4;
+
+		skin->setStyle("Foldout", foldoutStyle);
+
+		/************************************************************************/
+		/* 								PROGRESS BAR                      		*/
+		/************************************************************************/
+		GUIElementStyle progressBarBgStyle;
+		progressBarBgStyle.fixedHeight = true;
+		progressBarBgStyle.height = 17;
+		progressBarBgStyle.normal.texture = getGUITexture(ProgressBarBgTex);
+		progressBarBgStyle.border.left = 8;
+		progressBarBgStyle.border.right = 8;
+
+		skin->setStyle(GUIProgressBar::getBackgroundStyleType(), progressBarBgStyle);
+
+		GUIElementStyle progressBarFillStyle;
+		progressBarFillStyle.fixedHeight = true;
+		progressBarFillStyle.height = 16;
+		progressBarFillStyle.normal.texture = getGUITexture(ProgressBarFillTex);
+		progressBarFillStyle.border.left = 9;
+		progressBarFillStyle.border.right = 10;
+
+		skin->setStyle(GUIProgressBar::getBarStyleType(), progressBarFillStyle);
+
+		GUIElementStyle progressBarStyle;
+		progressBarStyle.fixedHeight = true;
+		progressBarStyle.height = 17;
+		progressBarStyle.minWidth = 100;
+
+		progressBarStyle.subStyles[GUIProgressBar::getBarStyleType()] = GUIProgressBar::getBarStyleType();
+		progressBarStyle.subStyles[GUIProgressBar::getBackgroundStyleType()] = GUIProgressBar::getBackgroundStyleType();
+
+		skin->setStyle(GUIProgressBar::getGUITypeName(), progressBarStyle);
+
+		/************************************************************************/
+		/* 								SLIDER                      			*/
+		/************************************************************************/
+
+		GUIElementStyle sliderHandleStyle;
+		sliderHandleStyle.fixedHeight = true;
+		sliderHandleStyle.fixedWidth = true;
+		sliderHandleStyle.width = 12;
+		sliderHandleStyle.height = 13;
+		sliderHandleStyle.normal.texture = getGUITexture(SliderHandleNormalTex);
+		sliderHandleStyle.hover.texture = getGUITexture(SliderHandleHoverTex);
+		sliderHandleStyle.active.texture = getGUITexture(SliderHandleActiveTex);
+
+		skin->setStyle(GUISlider::getHandleStyleType(), sliderHandleStyle);
+
+		GUIElementStyle sliderHorizontalBgStyle;
+		sliderHorizontalBgStyle.fixedHeight = true;
+		sliderHorizontalBgStyle.height = 10;
+		sliderHorizontalBgStyle.normal.texture = getGUITexture(SliderHBackgroundTex);
+		sliderHorizontalBgStyle.border.left = 4;
+		sliderHorizontalBgStyle.border.right = 4;
+
+		skin->setStyle("SliderHorzBg", sliderHorizontalBgStyle);
+
+		GUIElementStyle sliderHorizontalFillStyle;
+		sliderHorizontalFillStyle.fixedHeight = true;
+		sliderHorizontalFillStyle.height = 10;
+		sliderHorizontalFillStyle.normal.texture = getGUITexture(SliderHFillTex);
+		sliderHorizontalFillStyle.border.left = 6;
+		sliderHorizontalFillStyle.border.right = 4;
+
+		skin->setStyle("SliderHorzFill", sliderHorizontalFillStyle);
+
+		GUIElementStyle sliderHorizontalStyle;
+		sliderHorizontalStyle.fixedHeight = true;
+		sliderHorizontalStyle.height = 13;
+		sliderHorizontalStyle.width = 150;
+		sliderHorizontalStyle.minWidth = 10;
+		sliderHorizontalStyle.subStyles[GUISlider::getHandleStyleType()] = GUISlider::getHandleStyleType();
+		sliderHorizontalStyle.subStyles[GUISlider::getBackgroundStyleType()] = "SliderHorzBg";
+		sliderHorizontalStyle.subStyles[GUISlider::getFillStyleType()] = "SliderHorzFill";
+
+		skin->setStyle(GUISliderHorz::getGUITypeName(), sliderHorizontalStyle);
+
+		GUIElementStyle sliderVerticalBgStyle;
+		sliderVerticalBgStyle.fixedWidth = true;
+		sliderVerticalBgStyle.width = 10;
+		sliderVerticalBgStyle.normal.texture = getGUITexture(SliderVBackgroundTex);
+		sliderVerticalBgStyle.border.top = 4;
+		sliderVerticalBgStyle.border.bottom = 4;
+
+		skin->setStyle("SliderVertBg", sliderVerticalBgStyle);
+
+		GUIElementStyle sliderVerticalFillStyle;
+		sliderVerticalFillStyle.fixedWidth = true;
+		sliderVerticalFillStyle.width = 10;
+		sliderVerticalFillStyle.normal.texture = getGUITexture(SliderVFillTex);
+		sliderVerticalFillStyle.border.top = 6;
+		sliderVerticalFillStyle.border.bottom = 4;
+
+		skin->setStyle("SliderVertFill", sliderVerticalFillStyle);
+
+		GUIElementStyle sliderVerticalStyle;
+		sliderVerticalStyle.fixedWidth = true;
+		sliderVerticalStyle.width = 13;
+		sliderVerticalStyle.height = 150;
+		sliderVerticalStyle.minHeight = 10;
+		sliderVerticalStyle.subStyles[GUISlider::getHandleStyleType()] = GUISlider::getHandleStyleType();
+		sliderVerticalStyle.subStyles[GUISlider::getBackgroundStyleType()] = "SliderVertBg";
+		sliderVerticalStyle.subStyles[GUISlider::getFillStyleType()] = "SliderVertFill";
+
+		skin->setStyle(GUISliderVert::getGUITypeName(), sliderVerticalStyle);
+
+		/************************************************************************/
+		/* 							COLOR PICKER SLIDER                      	*/
+		/************************************************************************/
+
+		GUIElementStyle colorPickerSliderHorzHandleStyle;
+		colorPickerSliderHorzHandleStyle.fixedHeight = true;
+		colorPickerSliderHorzHandleStyle.fixedWidth = true;
+		colorPickerSliderHorzHandleStyle.height = 20;
+		colorPickerSliderHorzHandleStyle.width = 7;
+		colorPickerSliderHorzHandleStyle.normal.texture = getGUITexture(ColorPickerSliderHorzHandleTex);
+		colorPickerSliderHorzHandleStyle.hover.texture = colorPickerSliderHorzHandleStyle.normal.texture;
+		colorPickerSliderHorzHandleStyle.active.texture = colorPickerSliderHorzHandleStyle.normal.texture;
+
+		skin->setStyle("ColorSliderHorzHandle", colorPickerSliderHorzHandleStyle);
+
+		GUIElementStyle colorPickerSliderHorzStyle;
+		colorPickerSliderHorzStyle.fixedHeight = true;
+		colorPickerSliderHorzStyle.height = 32;
+		colorPickerSliderHorzStyle.minWidth = 20;
+		colorPickerSliderHorzStyle.subStyles[GUISlider::getHandleStyleType()] = "ColorSliderHorzHandle";
+
+		skin->setStyle("ColorSliderHorz", colorPickerSliderHorzStyle);
+
+		GUIElementStyle colorPickerSliderVertHandleStyle;
+		colorPickerSliderVertHandleStyle.fixedHeight = true;
+		colorPickerSliderVertHandleStyle.fixedWidth = true;
+		colorPickerSliderVertHandleStyle.height = 7;
+		colorPickerSliderVertHandleStyle.width = 45;
+		colorPickerSliderVertHandleStyle.normal.texture = getGUITexture(ColorPickerSliderVertHandleTex);
+		colorPickerSliderVertHandleStyle.hover.texture = colorPickerSliderVertHandleStyle.normal.texture;
+		colorPickerSliderVertHandleStyle.active.texture = colorPickerSliderVertHandleStyle.normal.texture;
+
+		skin->setStyle("ColorSliderVertHandle", colorPickerSliderVertHandleStyle);
+
+		GUIElementStyle colorPickerSliderVertStyle;
+		colorPickerSliderVertStyle.fixedWidth = true;
+		colorPickerSliderVertStyle.width = 30;
+		colorPickerSliderVertStyle.minHeight = 20;
+		colorPickerSliderVertStyle.subStyles[GUISlider::getHandleStyleType()] = "ColorSliderVertHandle";
+
+		skin->setStyle("ColorSliderVert", colorPickerSliderVertStyle);
+
+		GUIElementStyle colorPickerSlider2DHandleStyle;
+		colorPickerSlider2DHandleStyle.fixedHeight = true;
+		colorPickerSlider2DHandleStyle.fixedWidth = true;
+		colorPickerSlider2DHandleStyle.height = 7;
+		colorPickerSlider2DHandleStyle.width = 7;
+		colorPickerSlider2DHandleStyle.normal.texture = getGUITexture(ColorPickerSlider2DHandleTex);
+		colorPickerSlider2DHandleStyle.hover.texture = colorPickerSlider2DHandleStyle.normal.texture;
+		colorPickerSlider2DHandleStyle.active.texture = colorPickerSlider2DHandleStyle.normal.texture;
+
+		skin->setStyle("ColorSlider2DHandle", colorPickerSlider2DHandleStyle);
+
+		/************************************************************************/
+		/* 								STATUS BAR                      		*/
+		/************************************************************************/
+		GUIElementStyle statusBarBgStyle;
+		statusBarBgStyle.height = 16;
+		statusBarBgStyle.border.top = 2;
+		statusBarBgStyle.normal.texture = getGUITexture(StatusBarBgTex);
+
+		skin->setStyle(GUIStatusBar::getGUIBackgroundTypeName(), statusBarBgStyle);
+
+		GUIElementStyle statusBarMessageBtnStyle;
+		statusBarMessageBtnStyle.font = defaultFont;
+		statusBarMessageBtnStyle.fontSize = DefaultFontSize;
+		statusBarMessageBtnStyle.fixedHeight = true;
+		statusBarMessageBtnStyle.height = 16;
+		statusBarMessageBtnStyle.minWidth = 10;
+		statusBarMessageBtnStyle.textHorzAlign = THA_Left;
+		statusBarMessageBtnStyle.textVertAlign = TVA_Center;
+		statusBarMessageBtnStyle.imagePosition = GUIImagePosition::Left;
+
+		skin->setStyle(GUIStatusBar::getGUIMessageTypeName(), statusBarMessageBtnStyle);
+
+		GUIElementStyle statusBarStyle;
+		statusBarStyle.height = 16;
+
+		statusBarStyle.subStyles[GUIStatusBar::getGUIBackgroundTypeName()] = GUIStatusBar::getGUIBackgroundTypeName();
+		statusBarStyle.subStyles[GUIStatusBar::getGUIMessageTypeName()] = GUIStatusBar::getGUIMessageTypeName();
+
+		skin->setStyle(GUIStatusBar::getGUITypeName(), statusBarStyle);
+
+		/************************************************************************/
+		/* 									OTHER                      			*/
+		/************************************************************************/
+
+		// Centered label
+		GUIElementStyle centeredLabelStyle;
+		centeredLabelStyle.font = defaultFont;
+		centeredLabelStyle.fontSize = DefaultFontSize;
+		centeredLabelStyle.fixedWidth = false;
+		centeredLabelStyle.fixedHeight = true;
+		centeredLabelStyle.height = 11;
+		centeredLabelStyle.minWidth = 10;
+		centeredLabelStyle.textHorzAlign = THA_Center;
+		centeredLabelStyle.normal.textColor = TextNormalColor;
+
+		skin->setStyle("LabelCentered", centeredLabelStyle);
+
+		// Right-aligned label
+		GUIElementStyle rightAlignedLabelStyle;
+		rightAlignedLabelStyle.font = defaultFont;
+		rightAlignedLabelStyle.fontSize = DefaultFontSize;
+		rightAlignedLabelStyle.fixedWidth = false;
+		rightAlignedLabelStyle.fixedHeight = true;
+		rightAlignedLabelStyle.height = 11;
+		rightAlignedLabelStyle.minWidth = 10;
+		rightAlignedLabelStyle.textHorzAlign = THA_Right;
+		rightAlignedLabelStyle.normal.textColor = TextNormalColor;
+
+		skin->setStyle("RightAlignedLabel", rightAlignedLabelStyle);
+
+		// Multi-line label
+		GUIElementStyle multiLinelabelStyle;
+		multiLinelabelStyle.font = defaultFont;
+		multiLinelabelStyle.fontSize = DefaultFontSize;
+		multiLinelabelStyle.fixedWidth = false;
+		multiLinelabelStyle.fixedHeight = true;
+		multiLinelabelStyle.height = 11;
+		multiLinelabelStyle.minWidth = 10;
+		multiLinelabelStyle.wordWrap = true;
+		multiLinelabelStyle.normal.textColor = TextNormalColor;
+
+		skin->setStyle(BuiltinResources::MultiLineLabelStyle, multiLinelabelStyle);
+
+		// Multi-line centered label
+		GUIElementStyle multiLineCenteredLabelStyle;
+		multiLineCenteredLabelStyle.font = defaultFont;
+		multiLineCenteredLabelStyle.fontSize = DefaultFontSize;
+		multiLineCenteredLabelStyle.fixedWidth = false;
+		multiLineCenteredLabelStyle.fixedHeight = true;
+		multiLineCenteredLabelStyle.height = 11;
+		multiLineCenteredLabelStyle.minWidth = 10;
+		multiLineCenteredLabelStyle.wordWrap = true;
+		multiLineCenteredLabelStyle.textHorzAlign = THA_Center;
+		multiLineCenteredLabelStyle.normal.textColor = TextNormalColor;
+
+		skin->setStyle("MultiLineLabelCentered", multiLineCenteredLabelStyle);
+
+		// Title label
+		GUIElementStyle titleLabel;
+		titleLabel.font = defaultAAFont;
+		titleLabel.fontSize = TitleFontSize;
+		titleLabel.fixedWidth = false;
+		titleLabel.fixedHeight = true;
+		titleLabel.height = 20;
+		titleLabel.minWidth = 10;
+		titleLabel.wordWrap = true;
+		titleLabel.textHorzAlign = THA_Center;
+		titleLabel.normal.textColor = TextNormalColor;
+
+		skin->setStyle("TitleLabel", titleLabel);
+
+		// Selection area
+		GUIElementStyle selectionAreaStyle;
+		selectionAreaStyle.normal.texture = getGUITexture(SelectionAreaTex);
+		selectionAreaStyle.border.left = 1;
+		selectionAreaStyle.border.right = 1;
+		selectionAreaStyle.border.top = 1;
+		selectionAreaStyle.border.bottom = 1;
+
+		skin->setStyle("SelectionArea", selectionAreaStyle);
+
+		// Selectable label
+		GUIElementStyle selectableLabelStyle;
+		selectableLabelStyle.normalOn.texture = getGUITexture(SelectionBgTex);
+		selectableLabelStyle.hoverOn.texture = selectableLabelStyle.normalOn.texture;
+		selectableLabelStyle.activeOn.texture = selectableLabelStyle.normalOn.texture;
+		selectableLabelStyle.fixedHeight = true;
+		selectableLabelStyle.height = 11;
+		selectableLabelStyle.minWidth = 10;
+		selectableLabelStyle.font = defaultFont;
+		selectableLabelStyle.fontSize = DefaultFontSize;
+		selectableLabelStyle.textHorzAlign = THA_Left;
+		selectableLabelStyle.normal.textColor = TextNormalColor;
+
+		skin->setStyle("SelectableLabel", selectableLabelStyle);
+
+		// Scroll area background
+		GUIElementStyle scrollAreaBg;
+		scrollAreaBg.normal.texture = getGUITexture(ScrollAreaBgTex);
+		scrollAreaBg.minHeight = 6;
+		scrollAreaBg.minWidth = 4;
+		scrollAreaBg.border.left = 2;
+		scrollAreaBg.border.right = 2;
+		scrollAreaBg.border.top = 2;
+		scrollAreaBg.border.bottom = 4;
+		
+		skin->setStyle("ScrollAreaBg", scrollAreaBg);
+
+		// Inspector title area background
+		GUIElementStyle inspectorTitleBg;
+		inspectorTitleBg.normal.texture = getGUITexture(InspectorTitleBgTex);
+		inspectorTitleBg.minHeight = 4;
+		inspectorTitleBg.border.bottom = 2;
+
+		skin->setStyle("InspectorTitleBg", inspectorTitleBg);
+
+		// Inspector content background
+		GUIElementStyle inspectorContentBg;
+		inspectorContentBg.normal.texture = getGUITexture(InspectorContentBgTex);
+		inspectorContentBg.minWidth = 4;
+		inspectorContentBg.minHeight = 6;
+		inspectorContentBg.border.left = 2;
+		inspectorContentBg.border.right = 2;
+		inspectorContentBg.border.top = 2;
+		inspectorContentBg.border.bottom = 4;
+
+		skin->setStyle("InspectorContentBg", inspectorContentBg);
+
+		// Inspector content alternate background
+		GUIElementStyle inspectorContentBgAlternate;
+		inspectorContentBgAlternate.normal.texture = getGUITexture(InspectorContentBgAlternateTex);
+		inspectorContentBgAlternate.minWidth = 4;
+		inspectorContentBgAlternate.minHeight = 6;
+		inspectorContentBgAlternate.border.left = 2;
+		inspectorContentBgAlternate.border.right = 2;
+		inspectorContentBgAlternate.border.top = 2;
+		inspectorContentBgAlternate.border.bottom = 4;
+
+		skin->setStyle("InspectorContentBgAlternate", inspectorContentBgAlternate);
+
+		return skin;
+	}
+
+	HSpriteTexture BuiltinEditorResources::getGUITexture(const WString& name) const
+	{
+		Path texturePath = FileSystem::getWorkingDirectoryPath();
+		texturePath.append(EditorSkinFolder);
+		texturePath.append(L"sprite_" + name + L".asset");
+
+		return gResources().load<SpriteTexture>(texturePath);
+	}
+
+	HSpriteTexture BuiltinEditorResources::getGUIIcon(const WString& name) const
+	{
+		Path texturePath = FileSystem::getWorkingDirectoryPath();
+		texturePath.append(EditorIconFolder);
+		texturePath.append(L"sprite_" + name + L".asset");
+
+		return gResources().load<SpriteTexture>(texturePath);
+	}
+
+	HShader BuiltinEditorResources::getShader(const WString& name) const
+	{
+		Path programPath = EditorShaderFolder;
+		programPath.append(name + L".asset");
+
+		return gResources().load<Shader>(programPath);
+	}
+
+	HMaterial BuiltinEditorResources::createDockDropOverlayMaterial() const
+	{
+		return Material::create(mShaderDockOverlay);
+	}
+
+	HMaterial BuiltinEditorResources::createSceneGridMaterial() const
+	{
+		return Material::create(mShaderSceneGrid);
+	}
+
+	HMaterial BuiltinEditorResources::createPicking(CullingMode cullMode) const
+	{
+		UINT32 modeIdx = (UINT32)cullMode;
+
+		return Material::create(mShaderPicking[modeIdx]);
+	}
+
+	HMaterial BuiltinEditorResources::createPickingAlpha(CullingMode cullMode) const
+	{
+		UINT32 modeIdx = (UINT32)cullMode;
+
+		return Material::create(mShaderPickingAlpha[modeIdx]);
+	}
+
+	HMaterial BuiltinEditorResources::createWireGizmoMat() const
+	{
+		return Material::create(mShaderGizmoWire);
+	}
+
+	HMaterial BuiltinEditorResources::createSolidGizmoMat() const
+	{
+		return Material::create(mShaderGizmoSolid);
+	}
+
+	HMaterial BuiltinEditorResources::createIconGizmoMat() const
+	{
+		return Material::create(mShaderGizmoIcon);
+	}
+
+	HMaterial BuiltinEditorResources::createGizmoPickingMat() const
+	{
+		return Material::create(mShaderGizmoPicking);
+	}
+
+	HMaterial BuiltinEditorResources::createAlphaGizmoPickingMat() const
+	{
+		return Material::create(mShaderGizmoAlphaPicking);
+	}
+
+	HMaterial BuiltinEditorResources::createWireHandleMat() const
+	{
+		return Material::create(mShaderHandleWire);
+	}
+
+	HMaterial BuiltinEditorResources::createSolidHandleMat() const
+	{
+		return Material::create(mShaderHandleSolid);
+	}
+
+	HMaterial BuiltinEditorResources::createSelectionMat() const
+	{
+		return Material::create(mShaderSelection);
+	}
+
+	HSpriteTexture BuiltinEditorResources::getLibraryIcon(ProjectIcon icon, int size) const
+	{
+		WString iconName;
+
+		switch (icon)
+		{
+		case ProjectIcon::Folder:
+			iconName = FolderIconTex;
+			break;
+		case ProjectIcon::Font:
+			iconName = FontIconTex;
+			break;
+		case ProjectIcon::Mesh:
+			iconName = MeshIconTex;
+			break;
+		case ProjectIcon::Texture:
+			iconName = TextureIconTex;
+			break;
+		case ProjectIcon::PlainText:
+			iconName = PlainTextIconTex;
+			break;
+		case ProjectIcon::ScriptCode:
+			iconName = ScriptCodeIconTex;
+			break;
+		case ProjectIcon::Shader:
+			iconName = ShaderIconTex;
+			break;
+		case ProjectIcon::ShaderInclude:
+			iconName = ShaderIncludeIconTex;
+			break;
+		case ProjectIcon::Material:
+			iconName = MaterialIconTex;
+			break;
+		case ProjectIcon::SpriteTexture:
+			iconName = SpriteTextureIconTex;
+			break;
+		case ProjectIcon::Prefab:
+			iconName = PrefabIconTex;
+			break;
+		case ProjectIcon::GUISkin:
+			iconName = GUISkinIconTex;
+			break;
+		}
+
+		if (iconName.empty())
+			return HSpriteTexture();
+
+		if (size <= 16)
+			iconName += L"16";
+		else if (size <= 32)
+			iconName += L"32";
+		else if (size <= 48)
+			iconName += L"48";
+
+		return getGUIIcon(iconName);
+	}
+
+	HSpriteTexture BuiltinEditorResources::getToolbarIcon(ToolbarIcon icon) const
+	{
+		switch (icon)
+		{
+		case ToolbarIcon::NewCamera:
+			return getGUIIcon(L"ToolbarNewCameraIcon.png");
+		case ToolbarIcon::NewRenderable:
+			return getGUIIcon(L"ToolbarNewRenderableIcon.png");
+		case ToolbarIcon::NewPointLight:
+			return getGUIIcon(L"ToolbarNewPointLightIcon.png");
+		case ToolbarIcon::NewDirLight:
+			return getGUIIcon(L"ToolbarNewDirectionalLightIcon.png");
+		case ToolbarIcon::NewSpotLight:
+			return getGUIIcon(L"ToolbarNewSpotLightIcon.png");
+		case ToolbarIcon::NewSceneObject:
+			return getGUIIcon(L"ToolbarNewSceneObjectIcon.png");
+		case ToolbarIcon::NewCube:
+			return getGUIIcon(L"ToolbarNewCubeIcon.png");
+		case ToolbarIcon::NewSphere:
+			return getGUIIcon(L"ToolbarNewSphereIcon.png");
+		case ToolbarIcon::NewCone:
+			return getGUIIcon(L"ToolbarNewConeIcon.png");
+		case ToolbarIcon::NewQuad:
+			return getGUIIcon(L"ToolbarNewQuadIcon.png");
+		case ToolbarIcon::NewMat:
+			return getGUIIcon(L"ToolbarNewMaterialIcon.png");
+		case ToolbarIcon::NewCSScript:
+			return getGUIIcon(L"ToolbarNewCSScriptIcon.png");
+		case ToolbarIcon::NewShader:
+			return getGUIIcon(L"ToolbarNewShaderIcon.png");
+		case ToolbarIcon::NewSpriteTex:
+			return getGUIIcon(L"ToolbarNewSpriteTextureIcon.png");
+		case ToolbarIcon::Pause:
+			return getGUIIcon(L"ToolbarPauseIcon.png");
+		case ToolbarIcon::Play:
+			return getGUIIcon(L"ToolbarPlayIcon.png");
+		case ToolbarIcon::Step:
+			return getGUIIcon(L"ToolbarStepIcon.png");
+		case ToolbarIcon::Undo:
+			return getGUIIcon(L"ToolbarUndoIcon.png");
+		case ToolbarIcon::Redo:
+			return getGUIIcon(L"ToolbarRedoIcon.png");
+		case ToolbarIcon::OpenProject:
+			return getGUIIcon(L"ToolbarOpenProjectIcon.png");
+		case ToolbarIcon::SaveProject:
+			return getGUIIcon(L"ToolbarSaveProjectIcon.png");
+		case ToolbarIcon::SaveScene:
+			return getGUIIcon(L"ToolbarSaveSceneIcon.png");
+		}
+
+		return HSpriteTexture();
+	}
+
+	GUIContentImages BuiltinEditorResources::getSceneWindowIcon(SceneWindowIcon icon) const
+	{
+		HSpriteTexture off;
+		HSpriteTexture on;
+
+		switch (icon)
+		{
+		case SceneWindowIcon::View:
+			off = getGUIIcon(L"SceneViewIcon.png");
+			on = getGUIIcon(L"SceneViewIconOn.png");
+			break;
+		case SceneWindowIcon::Move:
+			off = getGUIIcon(L"SceneMoveIcon.png");
+			on = getGUIIcon(L"SceneMoveIconOn.png");
+			break;
+		case SceneWindowIcon::Rotate:
+			off = getGUIIcon(L"SceneRotateIcon.png");
+			on = getGUIIcon(L"SceneRotateIconOn.png");
+			break;
+		case SceneWindowIcon::Scale:
+			off = getGUIIcon(L"SceneScaleIcon.png");
+			on = getGUIIcon(L"SceneScaleIconOn.png");
+			break;
+		case SceneWindowIcon::Pivot:
+			off = getGUIIcon(L"ScenePivotIcon.png");
+			on = getGUIIcon(L"ScenePivotIconOn.png");
+			break;
+		case SceneWindowIcon::Center:
+			off = getGUIIcon(L"SceneCenterIcon.png");
+			on = getGUIIcon(L"SceneCenterIconOn.png");
+			break;
+		case SceneWindowIcon::Local:
+			off = getGUIIcon(L"SceneLocalIcon.png");
+			on = getGUIIcon(L"SceneLocalIconOn.png");
+			break;
+		case SceneWindowIcon::World:
+			off = getGUIIcon(L"SceneWorldIcon.png");
+			on = getGUIIcon(L"SceneWorldIconOn.png");
+			break;
+		case SceneWindowIcon::MoveSnap:
+			off = getGUIIcon(L"SceneMoveSnapIcon.png");
+			on = getGUIIcon(L"SceneMoveSnapIconOn.png");
+			break;
+		case SceneWindowIcon::RotateSnap:
+			off = getGUIIcon(L"SceneRotateSnapIcon.png");
+			on = getGUIIcon(L"SceneRotateSnapIconOn.png");
+			break;
+		}
+
+		GUIContentImages output;
+		output.normal = off;
+		output.hover = off;
+		output.active = on;
+		output.focused = off;
+		output.normalOn = on;
+		output.hoverOn = on;
+		output.activeOn = on;
+		output.focusedOn = on;
+
+		return output;
+	}
+
+	HSpriteTexture BuiltinEditorResources::getLibraryWindowIcon(LibraryWindowIcon icon) const
+	{
+		switch (icon)
+		{
+		case LibraryWindowIcon::Home:
+			return getGUIIcon(L"LibraryHomeIcon.png");
+		case LibraryWindowIcon::Up:
+			return getGUIIcon(L"LibraryUpIcon.png");
+		case LibraryWindowIcon::Clear:
+			return getGUIIcon(L"LibraryClearSearchIcon.png");
+		case LibraryWindowIcon::Options:
+			return getGUIIcon(L"LibraryOptionsIcon.png");
+		}
+
+		return HSpriteTexture();
+	}
+
+	HSpriteTexture BuiltinEditorResources::getInspectorWindowIcon(InspectorWindowIcon icon) const
+	{
+		switch (icon)
+		{
+		case InspectorWindowIcon::Create:
+			return getGUIIcon(L"InspectorCreateIcon.png");
+		case InspectorWindowIcon::Clone:
+			return getGUIIcon(L"InspectorCloneIcon.png");
+		case InspectorWindowIcon::Clear:
+			return getGUIIcon(L"InspectorClearIcon.png");
+		case InspectorWindowIcon::Resize:
+			return getGUIIcon(L"InspectorResizeIcon.png");
+		case InspectorWindowIcon::Delete:
+			return getGUIIcon(L"InspectorDeleteIcon.png");
+		case InspectorWindowIcon::MoveUp:
+			return getGUIIcon(L"InspectorMoveUpIcon.png");
+		case InspectorWindowIcon::MoveDown:
+			return getGUIIcon(L"InspectorMoveDownIcon.png");
+		case InspectorWindowIcon::Edit:
+			return getGUIIcon(L"InspectorEditIcon.png");
+		case InspectorWindowIcon::Apply:
+			return getGUIIcon(L"InspectorApplyIcon.png");
+		case InspectorWindowIcon::Add:
+			return getGUIIcon(L"InspectorAddIcon.png");
+		case InspectorWindowIcon::Cancel:
+			return getGUIIcon(L"InspectorCancelIcon.png");
+		}
+
+		return HSpriteTexture();
+	}
+
+	HSpriteTexture BuiltinEditorResources::getIcon(EditorIcon icon) const
+	{
+		switch (icon)
+		{
+		case EditorIcon::XBtn:
+			return getGUIIcon(XButtonNormalTex);
+		}
+
+		return HSpriteTexture();
+	}
+
+	HSpriteTexture BuiltinEditorResources::getLogMessageIcon(LogMessageIcon icon, UINT32 size, bool dark) const
+	{
+		if (size < 24) // Round to 16
+		{
+			if (dark)
+			{
+				switch (icon)
+				{
+				case LogMessageIcon::Info:
+					return getGUIIcon(L"IconInfoDark.png");
+				case LogMessageIcon::Warning:
+					return getGUIIcon(L"IconWarningDark.png");
+				case LogMessageIcon::Error:
+					return getGUIIcon(L"IconErrorDark.png");
+				}
+			}
+			else
+			{
+				switch (icon)
+				{
+				case LogMessageIcon::Info:
+					return getGUIIcon(L"IconInfo.png");
+				case LogMessageIcon::Warning:
+					return getGUIIcon(L"IconWarning.png");
+				case LogMessageIcon::Error:
+					return getGUIIcon(L"IconError.png");
+				}
+			}
+		}
+		else // Round to 32
+		{
+			switch (icon)
+			{
+			case LogMessageIcon::Info:
+				return getGUIIcon(L"IconInfo32.png");
+			case LogMessageIcon::Warning:
+				return getGUIIcon(L"IconWarning32.png");
+			case LogMessageIcon::Error:
+				return getGUIIcon(L"IconError32.png");
+			}
+		}
+
+		return HSpriteTexture();
+	}
+
+	WString BuiltinEditorResources::getEmptyShaderCode() const
+	{
+		Path filePath = FileSystem::getWorkingDirectoryPath();
+		filePath.append(BuiltinDataFolder);
+		filePath.append(EmptyShaderCodeFile);
+
+		DataStreamPtr fileStream = FileSystem::openFile(filePath);
+		if (fileStream != nullptr)
+			return fileStream->getAsWString();
+
+		return StringUtil::WBLANK;
+	}
+
+	WString BuiltinEditorResources::getEmptyCSScriptCode() const
+	{
+		Path filePath = FileSystem::getWorkingDirectoryPath();
+		filePath.append(BuiltinDataFolder);
+		filePath.append(EmptyCSScriptCodeFile);
+
+		DataStreamPtr fileStream = FileSystem::openFile(filePath);
+		if (fileStream != nullptr)
+			return fileStream->getAsWString();
+
+		return StringUtil::WBLANK;
+	}
+
+	Path BuiltinEditorResources::getShaderIncludeFolder()
+	{
+		return Paths::getRuntimeDataPath() + EDITOR_DATA_FOLDER + ShaderIncludeFolder;
+	}
+
+	Path BuiltinEditorResources::getDefaultWidgetLayoutPath()
+	{
+		return Paths::getRuntimeDataPath() + EDITOR_DATA_FOLDER + "Layout.asset";
+	}
 }

+ 4 - 0
BansheeEngine/BansheeEngine.vcxproj

@@ -262,6 +262,8 @@
     <ClCompile Include="Source\BsGUISkinRTTI.cpp" />
     <ClCompile Include="Source\BsGUISlider.cpp" />
     <ClCompile Include="Source\BsGUISpace.cpp" />
+    <ClCompile Include="Source\BsGUITooltip.cpp" />
+    <ClCompile Include="Source\BsGUITooltipManager.cpp" />
     <ClCompile Include="Source\BsHEString.cpp" />
     <ClCompile Include="Source\BsInputConfiguration.cpp" />
     <ClCompile Include="Source\BsCLight.cpp" />
@@ -299,6 +301,8 @@
     <ClInclude Include="Include\BsGUISkinRTTI.h" />
     <ClInclude Include="Include\BsGUISlider.h" />
     <ClInclude Include="Include\BsCGUIWidgetRTTI.h" />
+    <ClInclude Include="Include\BsGUITooltip.h" />
+    <ClInclude Include="Include\BsGUITooltipManager.h" />
     <ClInclude Include="Include\BsHEString.h" />
     <ClInclude Include="Include\BsCLight.h" />
     <ClInclude Include="Include\BsLight.h" />

+ 12 - 0
BansheeEngine/BansheeEngine.vcxproj.filters

@@ -365,6 +365,12 @@
     <ClInclude Include="Include\BsPaths.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsGUITooltipManager.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsGUITooltip.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsGUIElement.cpp">
@@ -625,5 +631,11 @@
     <ClCompile Include="Source\BsPaths.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsGUITooltipManager.cpp">
+      <Filter>Source Files\GUI</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsGUITooltip.cpp">
+      <Filter>Source Files\GUI</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 2 - 0
BansheeEngine/Include/BsBuiltinResources.h

@@ -154,6 +154,8 @@ namespace BansheeEngine
 		static Path getIconFolder();
 
 		static const WString IconTextureName;
+
+		static const String MultiLineLabelStyle;
 	private:
 		/**
 		 * @brief	Imports all necessary resources and converts them to engine-ready format.

+ 5 - 0
BansheeEngine/Include/BsGUIButtonBase.h

@@ -108,6 +108,11 @@ namespace BansheeEngine
 		 */
 		virtual UINT32 _getRenderElementDepth(UINT32 renderElementIdx) const override;
 
+		/**
+		 * @copydoc GUIElement::_getTooltip
+		 */
+		virtual WString _getTooltip() const override;
+
 		/**
 		 * @brief	Creates or destroys the content image sprite depending if there is a content image for the
 		 *			active state.

+ 1 - 1
BansheeEngine/Include/BsGUIDropDownBoxManager.h

@@ -7,7 +7,7 @@
 namespace BansheeEngine
 {
 	/**
-	 * @brief	Managed opening and closing of a drop down box.
+	 * @brief	Manages opening and closing of a drop down box.
 	 */
 	class BS_EXPORT GUIDropDownBoxManager : public Module<GUIDropDownBoxManager>
 	{

+ 7 - 0
BansheeEngine/Include/BsGUIElement.h

@@ -315,6 +315,13 @@ namespace BansheeEngine
 		 */
 		virtual GUIContextMenuPtr _getContextMenu() const;
 
+		/**
+		 * @brief	Returns text to display when hovering over the element. Returns empty string if no tooltip.
+		 *
+		 * @note	Internal method.
+		 */
+		virtual WString _getTooltip() const { return StringUtil::WBLANK; }
+
 		/**
 		 * @brief	Returns a clip rectangle relative to the element, used for offsetting
 		 * 			the input text.

+ 10 - 0
BansheeEngine/Include/BsGUIManager.h

@@ -335,6 +335,11 @@ namespace BansheeEngine
 		 */
 		const RenderWindow* getWidgetWindow(const CGUIWidget& widget) const;
 
+		/**
+		 * @brief	Hides the tooltip if any is shown.
+		 */
+		void hideTooltip();
+
 		/**
 		 * @brief	Sends a mouse event to the specified GUI element.
 		 *
@@ -368,6 +373,7 @@ namespace BansheeEngine
 		bool sendVirtualButtonEvent(GUIElement* element, const GUIVirtualButtonEvent& event);
 
 		static const UINT32 DRAG_DISTANCE;
+		static const float TOOLTIP_HOVER_TIME;
 
 		static const UINT32 MESH_HEAP_INITIAL_NUM_VERTS;
 		static const UINT32 MESH_HEAP_INITIAL_NUM_INDICES;
@@ -398,6 +404,10 @@ namespace BansheeEngine
 
 		Vector<ElementFocusInfo> mForcedFocusElements;
 
+		// Tooltip
+		GUIElement* mTooltipElement;
+		float mTooltipElementHoverStart;
+
 		GUIInputCaret* mInputCaret;
 		GUIInputSelection* mInputSelection;
 

+ 33 - 0
BansheeEngine/Include/BsGUITooltip.h

@@ -0,0 +1,33 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsCGUIWidget.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	GUI widget that renders a tooltip overlaid over other GUI elements.
+	 */
+	class BS_EXPORT GUITooltip : public CGUIWidget
+	{
+	public:
+		/**
+		 * @brief	Name of the style used for tooltip's background frame.
+		 */
+		static String getFrameStyleName();
+
+		/**
+		 * @brief	Creates a new tooltip widget.
+		 *
+		 * @param	parent			Parent scene object to attach the tooltip to.
+		 * @param	overlaidWidget	Widget over which to overlay the tooltip.
+		 * @param	position		Position of the tooltip, relative to the overlaid widget position.
+		 * @param	text			Text to display in the tooltip.
+		 */
+		GUITooltip(const HSceneObject& parent, const CGUIWidget& overlaidWidget, const Vector2I& position, const WString& text);
+		~GUITooltip();
+
+	private:
+		static const UINT32 TOOLTIP_WIDTH;
+	};
+}

+ 33 - 0
BansheeEngine/Include/BsGUITooltipManager.h

@@ -0,0 +1,33 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsModule.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Manages displaying tooltips over GUI elements.
+	 */
+	class BS_EXPORT GUITooltipManager : public Module<GUITooltipManager>
+	{
+	public:
+		~GUITooltipManager();
+
+		/**
+		 * @brief	Shows a tooltip at the specified location. This will replace any previously shown tooltip.
+		 *
+		 * @param	widget		GUI widget over which to display the tooltip.
+		 * @param	position	Position of the tooltip, relative to the parent GUI widget.
+		 * @param	text		Text to display on the tooltip.
+		 */
+		void show(const CGUIWidget& widget, const Vector2I& position, const WString& text);
+
+		/**
+		 * @brief	Hides the currently shown tooltip.
+		 */
+		void hide();
+
+	private:
+		HSceneObject mTooltipSO;
+	};
+}

+ 24 - 0
BansheeEngine/Source/BsBuiltinResources.cpp

@@ -32,6 +32,7 @@
 #include "BsVertexDataDesc.h"
 #include "BsShapeMeshes3D.h"
 #include "BsMesh.h"
+#include "BsGUITooltip.h"
 #include "BsFileSerializer.h"
 #include "BsTextureImportOptions.h"
 
@@ -43,6 +44,8 @@ namespace BansheeEngine
 	const Color BuiltinResources::TextNormalColor = Color(0.7f, 0.7f, 0.7f);
 	const Color BuiltinResources::TextActiveColor = Color(0.0f, 0.0f, 0.0f);
 
+	const String BuiltinResources::MultiLineLabelStyle = "MultiLineLabel";
+
 	const WString BuiltinResources::GUISkinFile = L"GUISkin";
 
 	const char* BuiltinResources::CursorFolder = "Cursors\\";
@@ -761,6 +764,27 @@ namespace BansheeEngine
 		skin->setStyle("MenuBarFrame", dropDownBoxStyle);
 		skin->setStyle("ContextMenuFrame", dropDownBoxStyle);
 
+		/************************************************************************/
+		/* 								TOOLTIP                      			*/
+		/************************************************************************/
+
+		GUIElementStyle tooltipFrameStyle;
+		tooltipFrameStyle.normal.texture = getSkinTexture(DropDownBoxBgTex);
+		tooltipFrameStyle.hover.texture = tooltipFrameStyle.normal.texture;
+		tooltipFrameStyle.active.texture = tooltipFrameStyle.hover.texture;
+		tooltipFrameStyle.fixedHeight = false;
+		tooltipFrameStyle.fixedWidth = false;
+		tooltipFrameStyle.border.left = 2;
+		tooltipFrameStyle.border.right = 2;
+		tooltipFrameStyle.border.top = 2;
+		tooltipFrameStyle.border.bottom = 4;
+		tooltipFrameStyle.margins.left = 6;
+		tooltipFrameStyle.margins.right = 6;
+		tooltipFrameStyle.margins.top = 4;
+		tooltipFrameStyle.margins.bottom = 6;
+
+		skin->setStyle(GUITooltip::getFrameStyleName(), tooltipFrameStyle);
+
 		/************************************************************************/
 		/* 									OTHER                      			*/
 		/************************************************************************/

+ 5 - 0
BansheeEngine/Source/BsGUIButtonBase.cpp

@@ -327,6 +327,11 @@ namespace BansheeEngine
 		return false;
 	}
 
+	WString GUIButtonBase::_getTooltip() const
+	{
+		return mContent.getTooltip();
+	}
+
 	void GUIButtonBase::refreshContentSprite()
 	{
 		HSpriteTexture contentTex = mContent.getImage(mActiveState);

+ 47 - 1
BansheeEngine/Source/BsGUIManager.cpp

@@ -35,6 +35,7 @@
 #include "BsRendererManager.h"
 #include "BsRenderer.h"
 #include "BsCamera.h"
+#include "BsGUITooltipManager.h"
 #include "BsRendererUtility.h"
 
 using namespace std::placeholders;
@@ -65,6 +66,7 @@ namespace BansheeEngine
 	};
 
 	const UINT32 GUIManager::DRAG_DISTANCE = 3;
+	const float GUIManager::TOOLTIP_HOVER_TIME = 1.0f;
 	const UINT32 GUIManager::MESH_HEAP_INITIAL_NUM_VERTS = 16384;
 	const UINT32 GUIManager::MESH_HEAP_INITIAL_NUM_INDICES = 49152;
 
@@ -72,7 +74,7 @@ namespace BansheeEngine
 		:mSeparateMeshesByWidget(true), mActiveMouseButton(GUIMouseButton::Left),
 		mCaretBlinkInterval(0.5f), mCaretLastBlinkTime(0.0f), mCaretColor(1.0f, 0.6588f, 0.0f), mIsCaretOn(false),
 		mTextSelectionColor(0.0f, 114/255.0f, 188/255.0f), mInputCaret(nullptr), mInputSelection(nullptr), 
-		mDragState(DragState::NoDrag), mActiveCursor(CursorType::Arrow), mCoreDirty(false)
+		mDragState(DragState::NoDrag), mActiveCursor(CursorType::Arrow), mCoreDirty(false), mTooltipElement(nullptr), mTooltipElementHoverStart(0.0f)
 	{
 		mOnPointerMovedConn = gInput().onPointerMoved.connect(std::bind(&GUIManager::onPointerMoved, this, _1));
 		mOnPointerPressedConn = gInput().onPointerPressed.connect(std::bind(&GUIManager::onPointerPressed, this, _1));
@@ -196,6 +198,11 @@ namespace BansheeEngine
 				findIter->widget = nullptr;
 		}
 
+		if(mTooltipElement != nullptr && mTooltipElement->_getParentWidget() == widget)
+		{
+			mTooltipElement = nullptr;
+		}
+
 		const Viewport* renderTarget = widget->getTarget();
 		GUIRenderData& renderData = mCachedGUIData[renderTarget];
 
@@ -263,6 +270,9 @@ namespace BansheeEngine
 
 			mElementsInFocus.swap(mNewElementsInFocus);
 
+			if (mTooltipElement != nullptr && mTooltipElement->_isDestroyed())
+				mTooltipElement = nullptr;
+
 			for (auto& focusElementInfo : mForcedFocusElements)
 			{
 				if (focusElementInfo.element->_isDestroyed())
@@ -324,6 +334,27 @@ namespace BansheeEngine
 			}
 		}
 
+		// Show tooltip if needed
+		if(mTooltipElement != nullptr)
+		{
+			float diff = gTime().getTime() - mTooltipElementHoverStart;
+			if(diff >= TOOLTIP_HOVER_TIME || gInput().isButtonDown(BC_LCONTROL) || gInput().isButtonDown(BC_RCONTROL))
+			{
+				const WString& tooltipText = mTooltipElement->_getTooltip();
+				CGUIWidget* parentWidget = mTooltipElement->_getParentWidget();
+				
+				if (!tooltipText.empty() && parentWidget != nullptr)
+				{
+					const RenderWindow* window = getWidgetWindow(*parentWidget);
+					Vector2I windowPos = window->screenToWindowPos(gInput().getPointerPosition());
+
+					GUITooltipManager::instance().show(*parentWidget, windowPos, tooltipText);
+				}
+
+				mTooltipElement = nullptr;
+			}
+		}
+
 		PROFILE_CALL(updateMeshes(), "UpdateMeshes");
 
 		// Send potentially updated meshes to core for rendering
@@ -1084,6 +1115,7 @@ namespace BansheeEngine
 		if(mElementsInFocus.size() == 0)
 			return;
 
+		hideTooltip();
 		mCommandEvent = GUICommandEvent();
 
 		switch(commandType)
@@ -1137,6 +1169,7 @@ namespace BansheeEngine
 
 	void GUIManager::onVirtualButtonDown(const VirtualButton& button, UINT32 deviceIdx)
 	{
+		hideTooltip();
 		mVirtualButtonEvent.setButton(button);
 		
 		for(auto& elementInFocus : mElementsInFocus)
@@ -1342,6 +1375,12 @@ namespace BansheeEngine
 
 		mElementsUnderPointer.swap(mNewElementsUnderPointer);
 
+		hideTooltip();
+		if(mElementsUnderPointer.size() > 0)
+			mTooltipElement = mElementsUnderPointer[0].element;
+
+		mTooltipElementHoverStart = gTime().getTime();
+
 		return eventProcessed;
 	}
 
@@ -1433,6 +1472,7 @@ namespace BansheeEngine
 
 		mElementsUnderPointer.swap(mNewElementsUnderPointer);
 
+		hideTooltip();
 		if(mDragState != DragState::Dragging)
 		{
 			if(mActiveCursor != CursorType::Arrow)
@@ -1442,6 +1482,12 @@ namespace BansheeEngine
 			}
 		}
 	}
+	
+	void GUIManager::hideTooltip()
+	{
+		GUITooltipManager::instance().hide();
+		mTooltipElement = nullptr;
+	}
 
 	void GUIManager::queueForDestroy(GUIElement* element)
 	{

+ 93 - 0
BansheeEngine/Source/BsGUITooltip.cpp

@@ -0,0 +1,93 @@
+#include "BsGUITooltip.h"
+#include "BsCGUIWidget.h"
+#include "BsGUIPanel.h"
+#include "BsCamera.h"
+#include "BsViewport.h"
+#include "BsGUILayoutY.h"
+#include "BsGUILayoutX.h"
+#include "BsGUITexture.h"
+#include "BsGUILabel.h"
+#include "BsGUIHelper.h"
+#include "BsGUISkin.h"
+#include "BsBuiltinResources.h"
+#include "BsDropDownAreaPlacement.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	const UINT32 GUITooltip::TOOLTIP_WIDTH = 200;
+
+	String GUITooltip::getFrameStyleName()
+	{
+		return "TooltipFrame";
+	}
+
+	GUITooltip::GUITooltip(const HSceneObject& parent, const CGUIWidget& overlaidWidget, const Vector2I& position, const WString& text)
+		:CGUIWidget(parent, overlaidWidget.getCamera())
+	{
+		setDepth(0); // Needs to be in front of everything
+		setSkin(overlaidWidget.getSkinResource());
+		
+		CameraPtr camera = overlaidWidget.getCamera();
+		ViewportPtr viewport = camera->getViewport();
+
+		Rect2I availableBounds(viewport->getX(), viewport->getY(), viewport->getWidth(), viewport->getHeight());
+		
+		const GUISkin& skin = getSkin();
+		const GUIElementStyle* multiLineLabelStyle = skin.getStyle(BuiltinResources::MultiLineLabelStyle);
+		const GUIElementStyle* backgroundStyle = skin.getStyle(getFrameStyleName());
+
+		Vector2I size(TOOLTIP_WIDTH, 25);
+		if (multiLineLabelStyle != nullptr)
+		{
+			GUIDimensions dimensions = GUIDimensions::create(GUIOptions(GUIOption::fixedWidth(TOOLTIP_WIDTH)));
+			size = GUIHelper::calcOptimalContentsSize(text, *multiLineLabelStyle, dimensions);
+		}
+
+		INT32 contentOffsetX = 0;
+		INT32 contentOffsetY = 0;
+		if(backgroundStyle != nullptr)
+		{
+			size.x += backgroundStyle->margins.left + backgroundStyle->margins.right;
+			size.y += backgroundStyle->margins.top + backgroundStyle->margins.bottom;
+
+			contentOffsetX = backgroundStyle->margins.left;
+			contentOffsetY = backgroundStyle->margins.right;
+		}
+
+		// Content area
+		GUIPanel* contentPanel = getPanel()->addNewElement<GUIPanel>();
+		contentPanel->setWidth((UINT32)size.x);
+		contentPanel->setHeight((UINT32)size.y);
+		contentPanel->setDepthRange(-1);
+
+		// Background frame
+		GUIPanel* backgroundPanel = getPanel()->addNewElement<GUIPanel>();
+		backgroundPanel->setWidth((UINT32)size.x);
+		backgroundPanel->setHeight((UINT32)size.y);
+		backgroundPanel->setDepthRange(0);
+
+		GUILayout* backgroundLayout = backgroundPanel->addNewElement<GUILayoutX>();
+
+		GUITexture* backgroundFrame = GUITexture::create(GUIImageScaleMode::StretchToFit, getFrameStyleName());
+		backgroundLayout->addElement(backgroundFrame);
+
+		GUILayout* contentLayout = contentPanel->addNewElement<GUILayoutY>();
+		GUILabel* textLabel = contentLayout->addNewElement<GUILabel>(HString(text), 
+			GUIOptions(GUIOption::fixedWidth(TOOLTIP_WIDTH)), BuiltinResources::MultiLineLabelStyle);
+
+		DropDownAreaPlacement::HorzDir horzDir;
+		DropDownAreaPlacement::VertDir vertDir;
+		DropDownAreaPlacement placement = DropDownAreaPlacement::aroundPosition(position);
+		Rect2I placementBounds = placement.getOptimalBounds((UINT32)size.x, (UINT32)size.y, availableBounds, horzDir, vertDir);
+
+		backgroundPanel->setPosition(placementBounds.x, placementBounds.y);
+		contentPanel->setPosition(placementBounds.x + contentOffsetX, placementBounds.y + contentOffsetY);
+	}
+
+	GUITooltip::~GUITooltip()
+	{
+
+	}
+}

+ 28 - 0
BansheeEngine/Source/BsGUITooltipManager.cpp

@@ -0,0 +1,28 @@
+#include "BsGUITooltipManager.h"
+#include "BsSceneObject.h"
+#include "BsGUITooltip.h"
+
+namespace BansheeEngine
+{
+	GUITooltipManager::~GUITooltipManager()
+	{
+		hide();
+	}
+
+	void GUITooltipManager::show(const CGUIWidget& widget, const Vector2I& position, const WString& text)
+	{
+		hide();
+
+		mTooltipSO = SceneObject::create("Tooltip", SOF_Internal | SOF_Persistent | SOF_DontSave);
+		GameObjectHandle<GUITooltip> tooltip = mTooltipSO->addComponent<GUITooltip>(widget, position, text);
+	}
+
+	void GUITooltipManager::hide()
+	{
+		if (mTooltipSO != nullptr)
+		{
+			mTooltipSO->destroy();
+			mTooltipSO = nullptr;
+		}
+	}
+}

+ 384 - 384
BansheeUtility/Include/BsMemStack.h

@@ -1,385 +1,385 @@
-#pragma once
-
-#include <stack>
-#include <assert.h>
-#include "BsStdHeaders.h"
-#include "BsThreadDefines.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Describes a memory stack of a certain block capacity. See "MemoryStack" for more information.
-	 *
-	 *  @tparam	BlockCapacity Minimum size of a block. Larger blocks mean less memory allocations, but also potentially
-	 * 			more wasted memory. If an allocation requests more bytes than BlockCapacity, first largest multiple is
-	 * 			used instead.
-	 */
-	template <int BlockCapacity = 1024 * 1024>
-	class MemStackInternal
-	{
-	private:
-
-		/**
-		 * @brief	A single block of memory of "BlockCapacity" size. A pointer to the first
-		 * 			free address is stored, and a remaining size. 
-		 */
-		class MemBlock
-		{
-		public:
-			MemBlock(UINT32 size)
-				:mData(nullptr), mFreePtr(0), mSize(size), 
-				mNextBlock(nullptr), mPrevBlock(nullptr)
-			{ }
-
-			~MemBlock()
-			{ }
-
-			/**
-			 * @brief	Returns the first free address and increments the free pointer.
-			 * 			Caller needs to ensure the remaining block size is adequate before
-			 * 			calling.
-			 */
-			UINT8* alloc(UINT32 amount)
-			{
-				UINT8* freePtr = &mData[mFreePtr];
-				mFreePtr += amount;
-
-				return freePtr;
-			}
-
-			/**
-			 * @brief	Deallocates the provided pointer. Deallocation must happen in opposite order
-			 * 			from allocation otherwise corruption will occur.
-			 * 			
-			 * @note	Pointer to "data" isn't actually needed, but is provided for debug purposes in order to more
-			 * 			easily track out-of-order deallocations.
-			 */
-			void dealloc(UINT8* data, UINT32 amount)
-			{
-				mFreePtr -= amount;
-				assert((&mData[mFreePtr]) == data && "Out of order stack deallocation detected. Deallocations need to happen in order opposite of allocations.");
-			}
-
-			UINT8* mData;
-			UINT32 mFreePtr;
-			UINT32 mSize;
-			MemBlock* mNextBlock;
-			MemBlock* mPrevBlock;
-		};
-
-	public:
-		MemStackInternal()
-			:mFreeBlock(nullptr)
-		{
-			mFreeBlock = allocBlock(BlockCapacity);
-		}
-
-		~MemStackInternal()
-		{
-			assert(mFreeBlock->mFreePtr == 0 && "Not all blocks were released before shutting down the stack allocator.");
-
-			MemBlock* curBlock = mFreeBlock;
-			while (curBlock != nullptr)
-			{
-				MemBlock* nextBlock = curBlock->mNextBlock;
-				deallocBlock(curBlock);
-
-				curBlock = nextBlock;
-			}
-		}
-
-		/**
-		 * @brief	Allocates the given amount of memory on the stack.
-		 *
-		 * @param	amount	The amount to allocate in bytes.
-		 *
-		 * @note	Allocates the memory in the currently active block if it is large enough,
-		 * 			otherwise a new block is allocated. If the allocation is larger than
-		 * 			default block size a separate block will be allocated only for that allocation,
-		 * 			making it essentially a slower heap allocator.
-		 * 			
-		 *			Each allocation comes with a 4 byte overhead.
-		 */
-		UINT8* alloc(UINT32 amount)
-		{
-			amount += sizeof(UINT32);
-
-			UINT32 freeMem = mFreeBlock->mSize - mFreeBlock->mFreePtr;
-			if(amount > freeMem)
-				allocBlock(amount);
-
-			UINT8* data = mFreeBlock->alloc(amount);
-
-			UINT32* storedSize = reinterpret_cast<UINT32*>(data);
-			*storedSize = amount;
-
-			return data + sizeof(UINT32);
-		}
-
-		/**
-		 * @brief	Deallocates the given memory. Data must be deallocated in opposite
-		 * 			order then when it was allocated.
-		 */
-		void dealloc(UINT8* data)
-		{
-			data -= sizeof(UINT32);
-
-			UINT32* storedSize = reinterpret_cast<UINT32*>(data);
-			mFreeBlock->dealloc(data, *storedSize);
-
-			if (mFreeBlock->mFreePtr == 0)
-			{
-				MemBlock* emptyBlock = mFreeBlock;
-
-				if (emptyBlock->mPrevBlock != nullptr)
-					mFreeBlock = emptyBlock->mPrevBlock;
-
-				// Merge with next block
-				if (emptyBlock->mNextBlock != nullptr)
-				{
-					UINT32 totalSize = emptyBlock->mSize + emptyBlock->mNextBlock->mSize;
-
-					if (emptyBlock->mPrevBlock != nullptr)
-						emptyBlock->mPrevBlock->mNextBlock = nullptr;
-					else
-						mFreeBlock = nullptr;
-
-					deallocBlock(emptyBlock->mNextBlock);
-					deallocBlock(emptyBlock);
-
-					allocBlock(totalSize);
-				}
-			}
-		}
-
-	private:
-		MemBlock* mFreeBlock;
-
-		/**
-		 * @brief	Allocates a new block of memory using a heap allocator. Block will never be 
-		 * 			smaller than "BlockCapacity" no matter the "wantedSize".
-		 */
-		MemBlock* allocBlock(UINT32 wantedSize)
-		{
-			UINT32 blockSize = BlockCapacity;
-			if(wantedSize > blockSize)
-				blockSize = wantedSize;
-
-			MemBlock* newBlock = nullptr;
-			MemBlock* curBlock = mFreeBlock;
-
-			while (curBlock != nullptr)
-			{
-				MemBlock* nextBlock = curBlock->mNextBlock;
-				if (nextBlock->mSize >= blockSize)
-				{
-					newBlock = nextBlock;
-					break;
-				}
-
-				curBlock = nextBlock;
-			}
-
-			if (newBlock == nullptr)
-			{
-				UINT8* data = (UINT8*)reinterpret_cast<UINT8*>(bs_alloc(blockSize + sizeof(MemBlock)));
-				newBlock = new (data)MemBlock(blockSize);
-				data += sizeof(MemBlock);
-
-				newBlock->mData = data;
-				newBlock->mPrevBlock = mFreeBlock;
-
-				if (mFreeBlock != nullptr)
-					mFreeBlock->mNextBlock = newBlock;
-			}
-
-			mFreeBlock = newBlock;
-			return newBlock;
-		}
-
-		/**
-		 * @brief	Deallocates a block of memory.
-		 */
-		void deallocBlock(MemBlock* block)
-		{
-			block->~MemBlock();
-			bs_free(block);
-		}
-	};
-
-	/**
-	 * @brief	One of the fastest, but also very limiting type of allocator. All deallocations
-	 * 			must happen in opposite order from allocations. 
-	 * 			
-	 * @note	It's mostly useful when you need to allocate something temporarily on the heap,
-	 * 			usually something that gets allocated and freed within the same method.
-	 * 			
-	 *			Each allocation comes with a pretty hefty 4 byte memory overhead, so don't use it for small allocations. 
-	 *			
-	 *			Thread safe. But you cannot allocate on one thread and deallocate on another. Threads will keep
-	 *			separate stacks internally. Make sure to call beginThread/endThread for any thread this stack is used on.
-	 */
-	class MemStack
-	{
-	public:
-		/**
-		 * @brief	Sets up the stack with the currently active thread. You need to call this
-		 * 			on any thread before doing any allocations or deallocations 
-		 */
-		static BS_UTILITY_EXPORT void beginThread();
-
-		/**
-		 * @brief	Cleans up the stack for the current thread. You may not perform any allocations or deallocations
-		 * 			after this is called, unless you call beginThread again.
-		 */
-		static BS_UTILITY_EXPORT void endThread();
-
-		/**
-		 * @copydoc	MemoryStackInternal::alloc
-		 */
-		static BS_UTILITY_EXPORT UINT8* alloc(UINT32 numBytes);
-
-		/**
-		 * @copydoc	MemoryStackInternal::dealloc
-		 */
-		static BS_UTILITY_EXPORT void deallocLast(UINT8* data);
-
-	private:
-		static BS_THREADLOCAL MemStackInternal<1024 * 1024>* ThreadMemStack;
-	};
-
-	/**
-	 * @copydoc	MemoryStackInternal::alloc
-	 */
-	BS_UTILITY_EXPORT inline void* bs_stack_alloc(UINT32 numBytes);
-
-	/**
-	 * @brief	Allocates enough memory to hold the specified type, on the stack, but
-	 * 			does not initialize the object. 
-	 *
-	 * @see		MemoryStackInternal::alloc()
-	 */
-	template<class T>
-	T* bs_stack_alloc()
-	{
-		return (T*)MemStack::alloc(sizeof(T));
-	}
-
-	/**
-	 * @brief	Allocates enough memory to hold N objects of the specified type, 
-	 * 			on the stack, but does not initialize the objects. 
-	 *
-	 * @see		MemoryStackInternal::alloc()
-	 */
-	template<class T>
-	T* bs_stack_alloc(UINT32 count)
-	{
-		return (T*)MemStack::alloc(sizeof(T) * count);
-	}
-
-	/**
-	 * @brief	Allocates enough memory to hold the specified type, on the stack, 
-	 * 			and constructs the object.
-	 *
-	 * @see		MemoryStackInternal::alloc()
-	 */
-	template<class T>
-	T* bs_stack_new(UINT32 count = 0)
-	{
-		T* data = bs_stack_alloc<T>(count);
-
-		for(unsigned int i = 0; i < count; i++)
-			new ((void*)&data[i]) T;
-
-		return data;
-	}
-
-	/**
-	 * @brief	Allocates enough memory to hold the specified type, on the stack, 
-	 * 			and constructs the object.
-	 *
-	 * @see		MemoryStackInternal::alloc()
-	 */
-	template<class T, class... Args>
-	T* bs_stack_new(Args &&...args, UINT32 count = 0)
-	{
-		T* data = bs_stack_alloc<T>(count);
-
-		for(unsigned int i = 0; i < count; i++)
-			new ((void*)&data[i]) T(std::forward<Args>(args)...);
-
-		return data;
-	}
-
-	/**
-	 * @brief	Destructs and deallocates last allocated entry currently located on stack.
-	 *
-	 * @see		MemoryStackInternal::dealloc()
-	 */
-	template<class T>
-	void bs_stack_delete(T* data)
-	{
-		data->~T();
-
-		MemStack::deallocLast((UINT8*)data);
-	}
-
-	/**
-	 * @brief	Destructs an array of objects and deallocates last allocated 
-	 * 			entry currently located on stack.
-	 *
-	 * @see		MemoryStackInternal::dealloc()
-	 */
-	template<class T>
-	void bs_stack_delete(T* data, UINT32 count)
-	{
-		for(unsigned int i = 0; i < count; i++)
-			data[i].~T();
-
-		MemStack::deallocLast((UINT8*)data);
-	}
-
-	/**
-	 * @copydoc	MemoryStackInternal::dealloc()
-	 */
-	BS_UTILITY_EXPORT inline void bs_stack_free(void* data);
-
-	/**
-	* @brief	Allows use of a stack allocator by using normal new/delete/free/dealloc operators.
-	* 			
-	* @see		MemStack
-	*/
-	class StackAlloc
-	{ };
-
-	/**
-	* @brief	Specialized memory allocator implementations that allows use of a 
-	* 			stack allocator in normal new/delete/free/dealloc operators.
-	* 			
-	* @see		MemStack
-	*/
-	template<>
-	class MemoryAllocator<StackAlloc> : public MemoryAllocatorBase
-	{
-	public:
-		static inline void* allocate(size_t bytes)
-		{
-			return bs_stack_alloc((UINT32)bytes);
-		}
-
-		static inline void* allocateArray(size_t bytes, UINT32 count)
-		{
-			return bs_stack_alloc((UINT32)(bytes * count));
-		}
-
-		static inline void free(void* ptr)
-		{
-			bs_stack_free(ptr);
-		}
-
-		static inline void freeArray(void* ptr, UINT32 count)
-		{
-			bs_stack_free(ptr);
-		}
-	};
+#pragma once
+
+#include <stack>
+#include <assert.h>
+#include "BsStdHeaders.h"
+#include "BsThreadDefines.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Describes a memory stack of a certain block capacity. See ::MemStack for more information.
+	 *
+	 *  @tparam	BlockCapacity Minimum size of a block. Larger blocks mean less memory allocations, but also potentially
+	 * 			more wasted memory. If an allocation requests more bytes than BlockCapacity, first largest multiple is
+	 * 			used instead.
+	 */
+	template <int BlockCapacity = 1024 * 1024>
+	class MemStackInternal
+	{
+	private:
+
+		/**
+		 * @brief	A single block of memory of "BlockCapacity" size. A pointer to the first
+		 * 			free address is stored, and a remaining size. 
+		 */
+		class MemBlock
+		{
+		public:
+			MemBlock(UINT32 size)
+				:mData(nullptr), mFreePtr(0), mSize(size), 
+				mNextBlock(nullptr), mPrevBlock(nullptr)
+			{ }
+
+			~MemBlock()
+			{ }
+
+			/**
+			 * @brief	Returns the first free address and increments the free pointer.
+			 * 			Caller needs to ensure the remaining block size is adequate before
+			 * 			calling.
+			 */
+			UINT8* alloc(UINT32 amount)
+			{
+				UINT8* freePtr = &mData[mFreePtr];
+				mFreePtr += amount;
+
+				return freePtr;
+			}
+
+			/**
+			 * @brief	Deallocates the provided pointer. Deallocation must happen in opposite order
+			 * 			from allocation otherwise corruption will occur.
+			 * 			
+			 * @note	Pointer to "data" isn't actually needed, but is provided for debug purposes in order to more
+			 * 			easily track out-of-order deallocations.
+			 */
+			void dealloc(UINT8* data, UINT32 amount)
+			{
+				mFreePtr -= amount;
+				assert((&mData[mFreePtr]) == data && "Out of order stack deallocation detected. Deallocations need to happen in order opposite of allocations.");
+			}
+
+			UINT8* mData;
+			UINT32 mFreePtr;
+			UINT32 mSize;
+			MemBlock* mNextBlock;
+			MemBlock* mPrevBlock;
+		};
+
+	public:
+		MemStackInternal()
+			:mFreeBlock(nullptr)
+		{
+			mFreeBlock = allocBlock(BlockCapacity);
+		}
+
+		~MemStackInternal()
+		{
+			assert(mFreeBlock->mFreePtr == 0 && "Not all blocks were released before shutting down the stack allocator.");
+
+			MemBlock* curBlock = mFreeBlock;
+			while (curBlock != nullptr)
+			{
+				MemBlock* nextBlock = curBlock->mNextBlock;
+				deallocBlock(curBlock);
+
+				curBlock = nextBlock;
+			}
+		}
+
+		/**
+		 * @brief	Allocates the given amount of memory on the stack.
+		 *
+		 * @param	amount	The amount to allocate in bytes.
+		 *
+		 * @note	Allocates the memory in the currently active block if it is large enough,
+		 * 			otherwise a new block is allocated. If the allocation is larger than
+		 * 			default block size a separate block will be allocated only for that allocation,
+		 * 			making it essentially a slower heap allocator.
+		 * 			
+		 *			Each allocation comes with a 4 byte overhead.
+		 */
+		UINT8* alloc(UINT32 amount)
+		{
+			amount += sizeof(UINT32);
+
+			UINT32 freeMem = mFreeBlock->mSize - mFreeBlock->mFreePtr;
+			if(amount > freeMem)
+				allocBlock(amount);
+
+			UINT8* data = mFreeBlock->alloc(amount);
+
+			UINT32* storedSize = reinterpret_cast<UINT32*>(data);
+			*storedSize = amount;
+
+			return data + sizeof(UINT32);
+		}
+
+		/**
+		 * @brief	Deallocates the given memory. Data must be deallocated in opposite
+		 * 			order then when it was allocated.
+		 */
+		void dealloc(UINT8* data)
+		{
+			data -= sizeof(UINT32);
+
+			UINT32* storedSize = reinterpret_cast<UINT32*>(data);
+			mFreeBlock->dealloc(data, *storedSize);
+
+			if (mFreeBlock->mFreePtr == 0)
+			{
+				MemBlock* emptyBlock = mFreeBlock;
+
+				if (emptyBlock->mPrevBlock != nullptr)
+					mFreeBlock = emptyBlock->mPrevBlock;
+
+				// Merge with next block
+				if (emptyBlock->mNextBlock != nullptr)
+				{
+					UINT32 totalSize = emptyBlock->mSize + emptyBlock->mNextBlock->mSize;
+
+					if (emptyBlock->mPrevBlock != nullptr)
+						emptyBlock->mPrevBlock->mNextBlock = nullptr;
+					else
+						mFreeBlock = nullptr;
+
+					deallocBlock(emptyBlock->mNextBlock);
+					deallocBlock(emptyBlock);
+
+					allocBlock(totalSize);
+				}
+			}
+		}
+
+	private:
+		MemBlock* mFreeBlock;
+
+		/**
+		 * @brief	Allocates a new block of memory using a heap allocator. Block will never be 
+		 * 			smaller than "BlockCapacity" no matter the "wantedSize".
+		 */
+		MemBlock* allocBlock(UINT32 wantedSize)
+		{
+			UINT32 blockSize = BlockCapacity;
+			if(wantedSize > blockSize)
+				blockSize = wantedSize;
+
+			MemBlock* newBlock = nullptr;
+			MemBlock* curBlock = mFreeBlock;
+
+			while (curBlock != nullptr)
+			{
+				MemBlock* nextBlock = curBlock->mNextBlock;
+				if (nextBlock->mSize >= blockSize)
+				{
+					newBlock = nextBlock;
+					break;
+				}
+
+				curBlock = nextBlock;
+			}
+
+			if (newBlock == nullptr)
+			{
+				UINT8* data = (UINT8*)reinterpret_cast<UINT8*>(bs_alloc(blockSize + sizeof(MemBlock)));
+				newBlock = new (data)MemBlock(blockSize);
+				data += sizeof(MemBlock);
+
+				newBlock->mData = data;
+				newBlock->mPrevBlock = mFreeBlock;
+
+				if (mFreeBlock != nullptr)
+					mFreeBlock->mNextBlock = newBlock;
+			}
+
+			mFreeBlock = newBlock;
+			return newBlock;
+		}
+
+		/**
+		 * @brief	Deallocates a block of memory.
+		 */
+		void deallocBlock(MemBlock* block)
+		{
+			block->~MemBlock();
+			bs_free(block);
+		}
+	};
+
+	/**
+	 * @brief	One of the fastest, but also very limiting type of allocator. All deallocations
+	 * 			must happen in opposite order from allocations. 
+	 * 			
+	 * @note	It's mostly useful when you need to allocate something temporarily on the heap,
+	 * 			usually something that gets allocated and freed within the same method.
+	 * 			
+	 *			Each allocation comes with a pretty hefty 4 byte memory overhead, so don't use it for small allocations. 
+	 *			
+	 *			Thread safe. But you cannot allocate on one thread and deallocate on another. Threads will keep
+	 *			separate stacks internally. Make sure to call beginThread/endThread for any thread this stack is used on.
+	 */
+	class MemStack
+	{
+	public:
+		/**
+		 * @brief	Sets up the stack with the currently active thread. You need to call this
+		 * 			on any thread before doing any allocations or deallocations 
+		 */
+		static BS_UTILITY_EXPORT void beginThread();
+
+		/**
+		 * @brief	Cleans up the stack for the current thread. You may not perform any allocations or deallocations
+		 * 			after this is called, unless you call beginThread again.
+		 */
+		static BS_UTILITY_EXPORT void endThread();
+
+		/**
+		 * @copydoc	MemoryStackInternal::alloc
+		 */
+		static BS_UTILITY_EXPORT UINT8* alloc(UINT32 numBytes);
+
+		/**
+		 * @copydoc	MemoryStackInternal::dealloc
+		 */
+		static BS_UTILITY_EXPORT void deallocLast(UINT8* data);
+
+	private:
+		static BS_THREADLOCAL MemStackInternal<1024 * 1024>* ThreadMemStack;
+	};
+
+	/**
+	 * @copydoc	MemoryStackInternal::alloc
+	 */
+	BS_UTILITY_EXPORT inline void* bs_stack_alloc(UINT32 numBytes);
+
+	/**
+	 * @brief	Allocates enough memory to hold the specified type, on the stack, but
+	 * 			does not initialize the object. 
+	 *
+	 * @see		MemoryStackInternal::alloc()
+	 */
+	template<class T>
+	T* bs_stack_alloc()
+	{
+		return (T*)MemStack::alloc(sizeof(T));
+	}
+
+	/**
+	 * @brief	Allocates enough memory to hold N objects of the specified type, 
+	 * 			on the stack, but does not initialize the objects. 
+	 *
+	 * @see		MemoryStackInternal::alloc()
+	 */
+	template<class T>
+	T* bs_stack_alloc(UINT32 count)
+	{
+		return (T*)MemStack::alloc(sizeof(T) * count);
+	}
+
+	/**
+	 * @brief	Allocates enough memory to hold the specified type, on the stack, 
+	 * 			and constructs the object.
+	 *
+	 * @see		MemoryStackInternal::alloc()
+	 */
+	template<class T>
+	T* bs_stack_new(UINT32 count = 0)
+	{
+		T* data = bs_stack_alloc<T>(count);
+
+		for(unsigned int i = 0; i < count; i++)
+			new ((void*)&data[i]) T;
+
+		return data;
+	}
+
+	/**
+	 * @brief	Allocates enough memory to hold the specified type, on the stack, 
+	 * 			and constructs the object.
+	 *
+	 * @see		MemoryStackInternal::alloc()
+	 */
+	template<class T, class... Args>
+	T* bs_stack_new(Args &&...args, UINT32 count = 0)
+	{
+		T* data = bs_stack_alloc<T>(count);
+
+		for(unsigned int i = 0; i < count; i++)
+			new ((void*)&data[i]) T(std::forward<Args>(args)...);
+
+		return data;
+	}
+
+	/**
+	 * @brief	Destructs and deallocates last allocated entry currently located on stack.
+	 *
+	 * @see		MemoryStackInternal::dealloc()
+	 */
+	template<class T>
+	void bs_stack_delete(T* data)
+	{
+		data->~T();
+
+		MemStack::deallocLast((UINT8*)data);
+	}
+
+	/**
+	 * @brief	Destructs an array of objects and deallocates last allocated 
+	 * 			entry currently located on stack.
+	 *
+	 * @see		MemoryStackInternal::dealloc()
+	 */
+	template<class T>
+	void bs_stack_delete(T* data, UINT32 count)
+	{
+		for(unsigned int i = 0; i < count; i++)
+			data[i].~T();
+
+		MemStack::deallocLast((UINT8*)data);
+	}
+
+	/**
+	 * @copydoc	MemoryStackInternal::dealloc()
+	 */
+	BS_UTILITY_EXPORT inline void bs_stack_free(void* data);
+
+	/**
+	* @brief	Allows use of a stack allocator by using normal new/delete/free/dealloc operators.
+	* 			
+	* @see		MemStack
+	*/
+	class StackAlloc
+	{ };
+
+	/**
+	* @brief	Specialized memory allocator implementations that allows use of a 
+	* 			stack allocator in normal new/delete/free/dealloc operators.
+	* 			
+	* @see		MemStack
+	*/
+	template<>
+	class MemoryAllocator<StackAlloc> : public MemoryAllocatorBase
+	{
+	public:
+		static inline void* allocate(size_t bytes)
+		{
+			return bs_stack_alloc((UINT32)bytes);
+		}
+
+		static inline void* allocateArray(size_t bytes, UINT32 count)
+		{
+			return bs_stack_alloc((UINT32)(bytes * count));
+		}
+
+		static inline void free(void* ptr)
+		{
+			bs_stack_free(ptr);
+		}
+
+		static inline void freeArray(void* ptr, UINT32 count)
+		{
+			bs_stack_free(ptr);
+		}
+	};
 }

+ 3 - 3
MBansheeEditor/EditorApplication.cs

@@ -430,7 +430,7 @@ namespace BansheeEditor
         /// Wrapper for menu items for <see cref="SaveScene(Action, Action)"/> method
         /// </summary>
         [MenuItem("File/Save Scene", ButtonModifier.Ctrl, ButtonCode.S, 10049)]
-        [ToolbarItem("Save Scene", ToolbarIcon.SaveScene, "", 1998)]
+        [ToolbarItem("Save Scene", ToolbarIcon.SaveScene, "Save scene (Ctrl + S)", 1998)]
         private static void SaveSceneMenu()
         {
             SaveScene();
@@ -449,7 +449,7 @@ namespace BansheeEditor
         /// Opens a Project Window allowing you to browse for or create a project.
         /// </summary>
         [MenuItem("File/Open Project", 10100)]
-        [ToolbarItem("Open Project", ToolbarIcon.OpenProject, "", 2000)]
+        [ToolbarItem("Open Project", ToolbarIcon.OpenProject, "Project manager", 2000)]
         public static void BrowseForProject()
         {
             ProjectWindow.Open();
@@ -459,7 +459,7 @@ namespace BansheeEditor
         /// Saves all data in the currently open project.
         /// </summary>
         [MenuItem("File/Save Project", 10099)]
-        [ToolbarItem("Save Project", ToolbarIcon.SaveProject, "", 1999)]
+        [ToolbarItem("Save Project", ToolbarIcon.SaveProject, "Save project", 1999)]
         public static void SaveProject()
         {
             foreach (var resourceUUID in dirtyResources)

+ 1250 - 1240
MBansheeEditor/GUI/GUIDictionaryField.cs

@@ -1,1241 +1,1251 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Base class for objects that display GUI for a modifyable dictionary of elements. Elements can be added, modified or
-    /// removed.
-    /// </summary>
-    public abstract class GUIDictionaryFieldBase
-    {
-        private const int IndentAmount = 5;
-
-        protected Dictionary<int, GUIDictionaryFieldRow> rows = new Dictionary<int, GUIDictionaryFieldRow>();
-        protected GUIDictionaryFieldRow editRow;
-        protected GUILayoutY guiLayout;
-        protected GUILayoutX guiChildLayout;
-        protected GUILayoutX guiTitleLayout;
-        protected GUILayoutX guiInternalTitleLayout;
-        protected GUILayoutY guiContentLayout;
-        protected bool isExpanded;
-        protected int depth;
-        protected LocString title;
-
-        private int editRowIdx = -1;
-        private object editKey;
-        private object editValue;
-        private object editOriginalKey;
-
-        private State state;
-        private bool isModified;
-
-        /// <summary>
-        /// Constructs a new GUI dictionary.
-        /// </summary>
-        /// <param name="title">Label to display on the dictionary GUI title.</param>
-        /// <param name="layout">Layout to which to append the list GUI elements to.</param>
-        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
-        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
-        ///                     depths divisible by two will use an alternate style.</param>
-        protected GUIDictionaryFieldBase(LocString title, GUILayout layout, int depth = 0)
-        {
-            this.title = title;
-            this.depth = depth;
-            guiLayout = layout.AddLayoutY();
-            guiTitleLayout = guiLayout.AddLayoutX();
-        }
-
-        /// <summary>
-        /// Completely rebuilds the dictionary GUI elements.
-        /// </summary>
-        public void BuildGUI()
-        {
-            editKey = CreateKey();
-            editValue = CreateValue();
-
-            UpdateHeaderGUI();
-
-            foreach (var KVP in rows)
-                KVP.Value.Destroy();
-
-            rows.Clear();
-
-            if (editRow != null)
-            {
-                editRow.Destroy();
-                editRow = null;
-            }
-
-            if (!IsNull())
-            {
-                // Hidden dependency: BuildGUI must be called after all elements are 
-                // in the dictionary so we do it in two steps
-                int numRows = GetNumRows();
-                for (int i = 0; i < numRows; i++)
-                {
-                    GUIDictionaryFieldRow newRow = CreateRow();
-                    rows.Add(i, newRow);
-                }
-
-                editRow = CreateRow();
-                editRow.Initialize(this, guiContentLayout, numRows, depth + 1);
-                editRow.Enabled = false;
-
-                for (int i = 0; i < numRows; i++)
-                    rows[i].Initialize(this, guiContentLayout, i, depth + 1);
-            }
-        }
-
-        /// <summary>
-        /// Rebuilds the GUI dictionary header if needed. 
-        /// </summary>
-        protected void UpdateHeaderGUI()
-        {
-            Action BuildEmptyGUI = () =>
-            {
-                guiInternalTitleLayout = guiTitleLayout.InsertLayoutX(0);
-
-                guiInternalTitleLayout.AddElement(new GUILabel(title));
-                guiInternalTitleLayout.AddElement(new GUILabel("Empty", GUIOption.FixedWidth(100)));
-
-                GUIContent createIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Create));
-                GUIButton createBtn = new GUIButton(createIcon, GUIOption.FixedWidth(30));
-                createBtn.OnClick += OnCreateButtonClicked;
-                guiInternalTitleLayout.AddElement(createBtn);
-            };
-
-            Action BuildFilledGUI = () =>
-            {
-                guiInternalTitleLayout = guiTitleLayout.InsertLayoutX(0);
-
-                GUIToggle guiFoldout = new GUIToggle(title, EditorStyles.Foldout);
-                guiFoldout.Value = isExpanded;
-                guiFoldout.OnToggled += ToggleFoldout;
-
-                GUIContent clearIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Clear));
-                GUIButton guiClearBtn = new GUIButton(clearIcon, GUIOption.FixedWidth(30));
-                guiClearBtn.OnClick += OnClearButtonClicked;
-
-                GUIContent addIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Add));
-                GUIButton guiAddBtn = new GUIButton(addIcon, GUIOption.FixedWidth(30));
-                guiAddBtn.OnClick += OnAddButtonClicked;
-
-                guiInternalTitleLayout.AddElement(guiFoldout);
-                guiInternalTitleLayout.AddElement(guiAddBtn);
-                guiInternalTitleLayout.AddElement(guiClearBtn);
-
-                guiChildLayout = guiLayout.AddLayoutX();
-                guiChildLayout.AddSpace(IndentAmount);
-
-                GUIPanel guiContentPanel = guiChildLayout.AddPanel();
-                GUILayoutX guiIndentLayoutX = guiContentPanel.AddLayoutX();
-                guiIndentLayoutX.AddSpace(IndentAmount);
-                GUILayoutY guiIndentLayoutY = guiIndentLayoutX.AddLayoutY();
-                guiIndentLayoutY.AddSpace(IndentAmount);
-                guiContentLayout = guiIndentLayoutY.AddLayoutY();
-                guiIndentLayoutY.AddSpace(IndentAmount);
-                guiIndentLayoutX.AddSpace(IndentAmount);
-                guiChildLayout.AddSpace(IndentAmount);
-
-                short backgroundDepth = (short)(Inspector.START_BACKGROUND_DEPTH - depth - 1);
-                string bgPanelStyle = depth % 2 == 0
-                    ? EditorStyles.InspectorContentBgAlternate
-                    : EditorStyles.InspectorContentBg;
-
-                GUIPanel backgroundPanel = guiContentPanel.AddPanel(backgroundDepth);
-                GUITexture inspectorContentBg = new GUITexture(null, bgPanelStyle);
-                backgroundPanel.AddElement(inspectorContentBg);
-
-                ToggleFoldout(isExpanded);
-            };
-
-            if (state == State.None)
-            {
-                if (!IsNull())
-                {
-                    BuildFilledGUI();
-                    state = State.Filled;
-                }
-                else
-                {
-                    BuildEmptyGUI();
-
-                    state = State.Empty;
-                }
-            }
-            else if (state == State.Empty)
-            {
-                if (!IsNull())
-                {
-                    guiInternalTitleLayout.Destroy();
-                    BuildFilledGUI();
-                    state = State.Filled;
-                }
-            }
-            else if (state == State.Filled)
-            {
-                if (IsNull())
-                {
-                    guiInternalTitleLayout.Destroy();
-                    guiChildLayout.Destroy();
-                    BuildEmptyGUI();
-
-                    state = State.Empty;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Destroys all rows and clears the row list.
-        /// </summary>
-        private void ClearRows()
-        {
-            foreach (var KVP in rows)
-                KVP.Value.Destroy();
-
-            editRow.Destroy();
-            rows.Clear();
-        }
-
-        /// <summary>
-        /// Returns the layout that is used for positioning the elements in the title bar.
-        /// </summary>
-        /// <returns>Horizontal layout for positioning the title bar elements.</returns>
-        public GUILayoutX GetTitleLayout()
-        {
-            return guiTitleLayout;
-        }
-
-        /// <summary>
-        /// Refreshes contents of all dictionary rows and checks if anything was modified.
-        /// </summary>
-        /// <returns>State representing was anything modified between two last calls to <see cref="Refresh"/>.</returns>
-        public virtual InspectableState Refresh()
-        {
-            InspectableState state = InspectableState.NotModified;
-            for (int i = 0; i < rows.Count; i++)
-                state |= rows[i].Refresh();
-
-            if (editRow != null && editRow.Enabled)
-                state |= editRow.Refresh();
-
-            if (isModified)
-            {
-                state |= InspectableState.Modified;
-                isModified = false;
-            }
-
-            return state;
-        }
-
-        /// <summary>
-        /// Destroys the GUI elements.
-        /// </summary>
-        public void Destroy()
-        {
-            if (guiLayout != null)
-            {
-                guiLayout.Destroy();
-                guiLayout = null;
-            }
-
-            guiLayout = null;
-            guiTitleLayout = null;
-            guiChildLayout = null;
-
-            for (int i = 0; i < rows.Count; i++)
-                rows[i].Destroy();
-
-            rows.Clear();
-
-            if (editRow != null)
-                editRow.Destroy();
-
-            editRow = null;
-        }
-
-        /// <summary>
-        /// Checks is the specified row index the temporary edit row.
-        /// </summary>
-        /// <param name="rowIdx">Sequential index of the row to check.</param>
-        /// <returns>True if the index is of an edit row.</returns>
-        private bool IsTemporaryRow(int rowIdx)
-        {
-            return rowIdx == rows.Count;
-        }
-
-        /// <summary>
-        /// Checks is any row being currently edited.
-        /// </summary>
-        /// <returns>True if a row is being edited, false otherwise.</returns>
-        private bool IsEditInProgress()
-        {
-            return editRowIdx != -1;
-        }
-
-        /// <summary>
-        /// Returns the number of rows in the dictionary.
-        /// </summary>
-        /// <returns>Number of rows in the dictionary.</returns>
-        protected abstract int GetNumRows();
-
-        /// <summary>
-        /// Checks is the dictionary instance not assigned.
-        /// </summary>
-        /// <returns>True if there is not a dictionary instance.</returns>
-        protected abstract bool IsNull();
-
-        /// <summary>
-        /// Gets a value of an element at the specified index in the list. Also handles temporary edit fields.
-        /// </summary>
-        /// <param name="rowIdx">Sequential index of the row to set the value for.</param>
-        /// <returns>Value of the list element at the specified key.</returns>
-        protected internal virtual object GetValueInternal(int rowIdx)
-        {
-            if (rowIdx == editRowIdx || IsTemporaryRow(rowIdx))
-                return editValue;
-            else
-                return GetValue(GetKey(rowIdx));
-        }
-
-        /// <summary>
-        /// Sets a value of an element at the specified index in the list. Also handles temporary edit fields.
-        /// </summary>
-        /// <param name="rowIdx">Sequential index of the row to set the value for.</param>
-        /// <param name="value">Value to assign to the element. Caller must ensure it is of valid type.</param>
-        protected internal virtual void SetValueInternal(int rowIdx, object value)
-        {
-            if (rowIdx == editRowIdx || IsTemporaryRow(rowIdx))
-                editValue = value;
-            else
-                SetValue(GetKey(rowIdx), value);
-        }
-
-        /// <summary>
-        /// Changes the value of the key of the specified row.
-        /// </summary>
-        /// <param name="rowIdx">Sequential index of the row to set the key for.</param>
-        /// <param name="key">Key to assign to the specified row.</param>
-        protected internal void SetKey(int rowIdx, object key)
-        {
-            if (editRowIdx != rowIdx)
-            {
-                Debug.LogError("Cannot change a dictionary row that is not in edit state.");
-                return;
-            }
-
-            editKey = key;
-        }
-
-        /// <summary>
-        /// Gets a key for a row at the specified index. Handles the special case for the currently edited row.
-        /// </summary>
-        /// <param name="rowIdx">Sequential index of the row for which to retrieve the key.</param>
-        /// <returns>Key for a row at the specified index.</returns>
-        protected internal object GetKeyInternal(int rowIdx)
-        {
-            if (editRowIdx == rowIdx || IsTemporaryRow(rowIdx))
-                return editKey;
-
-            return GetKey(rowIdx);
-        }
-
-        /// <summary>
-        /// Creates a new dictionary row GUI.
-        /// </summary>
-        /// <returns>Object containing the dictionary row GUI.</returns>
-        protected abstract GUIDictionaryFieldRow CreateRow();
-
-        /// <summary>
-        /// Gets a key for a row at the specified index.
-        /// </summary>
-        /// <param name="rowIdx">Sequential index of the row for which to retrieve the key.</param>
-        /// <returns>Key for a row at the specified index.</returns>
-        protected internal abstract object GetKey(int rowIdx);
-
-        /// <summary>
-        /// Gets a value of an element at the specified index in the list.
-        /// </summary>
-        /// <param name="key">Key of the element whose value to retrieve.</param>
-        /// <returns>Value of the dictionary entry for the specified key.</returns>
-        protected internal abstract object GetValue(object key);
-
-        /// <summary>
-        /// Sets a value of an element at the specified index in the list.
-        /// </summary>
-        /// <param name="key">Key of the element whose value to set.</param>
-        /// <param name="value">Value to assign to the element. Caller must ensure it is of valid type.</param>
-        protected internal abstract void SetValue(object key, object value);
-
-        /// <summary>
-        /// Updates both key and value of an existing entry.
-        /// </summary>
-        /// <param name="oldKey">Original key of the entry.</param>
-        /// <param name="newKey">New key of the entry.</param>
-        /// <param name="value">New value of the entry.</param>
-        protected internal abstract void EditEntry(object oldKey, object newKey, object value);
-
-        /// <summary>
-        /// Adds a new entry to the dictionary.
-        /// </summary>
-        /// <param name="key">Key of the entry to add.</param>
-        /// <param name="value">Value of the entry to add.</param>
-        protected internal abstract void AddEntry(object key, object value);
-
-        /// <summary>
-        /// Removes the specified entry from the dictionary.
-        /// </summary>
-        /// <param name="key">Key of the entry to remove.</param>
-        protected internal abstract void RemoveEntry(object key);
-
-        /// <summary>
-        /// Creates a new empty key object of a valid type that can be used in the dictionary.
-        /// </summary>
-        /// <returns>New empty key object.</returns>
-        protected internal abstract object CreateKey();
-
-        /// <summary>
-        /// Creates a new empty value object of a valid type that can be used in the dictionary.
-        /// </summary>
-        /// <returns>New empty value object.</returns>
-        protected internal abstract object CreateValue();
-
-        /// <summary>
-        /// Checks does the element with the specified key exist in the dictionary.
-        /// </summary>
-        /// <param name="key">Key of the element to check for existence.</param>
-        /// <returns>True if the key exists in the dictionary, false otherwise.</returns>
-        protected internal abstract bool Contains(object key);
-
-        /// <summary>
-        /// Clones the specified dictionary element.
-        /// </summary>
-        /// <param name="index">Sequential index of the element in the dictionary to clone.</param>
-        protected internal abstract KeyValuePair<object, object> CloneElement(int index);
-
-        /// <summary>
-        /// Creates a brand new dictionary with zero elements in the place of the current dictionary.
-        /// </summary>
-        protected abstract void CreateDictionary();
-
-        /// <summary>
-        /// Deletes the current dictionary object.
-        /// </summary>
-        protected abstract void DeleteDictionary();
-
-        /// <summary>
-        /// Hides or shows the dictionary rows.
-        /// </summary>
-        /// <param name="expanded">True if the rows should be displayed, false otherwise.</param>
-        private void ToggleFoldout(bool expanded)
-        {
-            isExpanded = expanded;
-
-            if (guiChildLayout != null)
-                guiChildLayout.Active = isExpanded && (rows.Count > 0 || IsEditInProgress());
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the create button on the title bar. Creates a brand new dictionary with zero
-        /// elements in the place of the current dictionary.
-        /// </summary>
-        protected void OnCreateButtonClicked()
-        {
-            CreateDictionary();
-            UpdateHeaderGUI();
-
-            editRow.Initialize(this, guiContentLayout, 0, depth + 1);
-            editRow.Enabled = false;
-
-            isModified = true;
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the add button on the title bar. Adds a new empty element to the dictionary.
-        /// </summary>
-        protected virtual void OnAddButtonClicked()
-        {
-            if (IsEditInProgress())
-            {
-                DialogBox.Open(
-                    new LocEdString("Edit in progress."),
-                    new LocEdString("You are editing the entry with key \"" + editKey + "\". You cannot add a row " +
-                                    "before applying or discarding those changes. Do you wish to apply those changes first?"),
-                    DialogBox.Type.YesNoCancel,
-                    x =>
-                    {
-                        switch (x)
-                        {
-                            case DialogBox.ResultType.Yes:
-                                if (ApplyChanges())
-                                    StartAdd();
-                                break;
-                            case DialogBox.ResultType.No:
-                                DiscardChanges();
-                                StartAdd();
-                                break;
-                        }
-                    });
-            }
-            else
-            {
-                if (!isExpanded)
-                    ToggleFoldout(true);
-
-                StartAdd();
-            }
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the clear button on the title bar. Deletes the current dictionary object.
-        /// </summary>
-        protected void OnClearButtonClicked()
-        {
-            DeleteDictionary();
-            UpdateHeaderGUI();
-            ClearRows();
-
-            isModified = true;
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the delete button next to a dictionary entry. Deletes an element in the 
-        /// dictionary. 
-        /// </summary>
-        /// <param name="rowIdx">Sequential row index of the entry that was clicked.</param>
-        protected internal virtual void OnDeleteButtonClicked(int rowIdx)
-        {
-            if (IsEditInProgress())
-                DiscardChanges();
-            else
-            {
-                RemoveEntry(GetKey(rowIdx));
-
-                rows[rows.Count - 1].Destroy();
-                rows.Remove(rows.Count - 1);
-
-                editRow.SetIndex(GetNumRows());
-                isModified = true;
-            }
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the clone button next to a dictionary entry. Clones an element and
-        /// adds the clone to the dictionary.
-        /// </summary>
-        /// <param name="rowIdx">Sequential row index of the entry that was clicked.</param>
-        protected internal virtual void OnCloneButtonClicked(int rowIdx)
-        {
-            if (IsEditInProgress())
-            {
-                DialogBox.Open(
-                    new LocEdString("Edit in progress."),
-                    new LocEdString("You are editing the entry with key \"" + editKey + "\". You cannot clone a row " +
-                        "before applying or discarding those changes. Do you wish to apply those changes first?"),
-                    DialogBox.Type.YesNoCancel,
-                    x =>
-                    {
-                        switch (x)
-                        {
-                            case DialogBox.ResultType.Yes:
-                                if (ApplyChanges())
-                                    StartClone(rowIdx);
-                                break;
-                            case DialogBox.ResultType.No:
-                                DiscardChanges();
-                                StartClone(rowIdx);
-                                break;
-                        }
-                    });
-            }
-            else
-                StartClone(rowIdx);
-        }
-
-        /// <summary>
-        /// Triggered when user clicks the edit or apply (depending on state) button next to the dictionary entry. Starts
-        /// edit mode for the element, if not already in edit mode. Applies edit mode changes if already in edit mode.
-        /// </summary>
-        /// <param name="rowIdx">Sequential row index of the entry that was clicked.</param>
-        protected internal virtual void OnEditButtonClicked(int rowIdx)
-        {
-            if (editRowIdx == rowIdx)
-                ApplyChanges();
-            else
-            {
-                if (IsEditInProgress())
-                {
-                    DialogBox.Open(
-                        new LocEdString("Edit in progress."),
-                        new LocEdString("You are already editing the entry with key \"" + editKey + "\". You cannot edit " +
-                            "another row before applying or discarding those changes. Do you wish to apply those changes first?"),
-                        DialogBox.Type.YesNoCancel,
-                        x =>
-                        {
-                            switch (x)
-                            {
-                                case DialogBox.ResultType.Yes:
-                                    if (ApplyChanges())
-                                        StartEdit(rowIdx);
-                                    break;
-                                case DialogBox.ResultType.No:
-                                    DiscardChanges();
-                                    StartEdit(rowIdx);
-                                    break;
-                            }
-                        });
-                }
-                else
-                    StartEdit(rowIdx);
-            }
-        }
-
-        /// <summary>
-        /// Starts an edit operation on a row with the specified key. Allows the user to change the key of the specified row.
-        /// Caller must ensure no edit operation is already in progress.
-        /// </summary>
-        /// <param name="rowIdx">Sequential row index of the entry to edit.</param>
-        private void StartEdit(int rowIdx)
-        {
-            object key = GetKey(rowIdx);
-            KeyValuePair<object, object> clone = CloneElement(rowIdx);
-
-            editKey = clone.Key;
-            editValue = clone.Value;
-            editOriginalKey = key;
-            editRowIdx = rowIdx;
-
-            rows[rowIdx].EditMode = true;
-            guiChildLayout.Active = rows.Count > 0 && isExpanded;
-        }
-
-        /// <summary>
-        /// Starts an add operation. Adds a new key/value pair and allows the user to set them up in a temporary row
-        /// before inserting them into the dictionary. Caller must ensure no edit operation is already in progress.
-        /// </summary>
-        private void StartAdd()
-        {
-            editKey = CreateKey();
-            editValue = CreateValue();
-            editOriginalKey = null;
-            editRowIdx = rows.Count;
-
-            editRow.BuildGUI();
-            editRow.Enabled = true;
-            editRow.EditMode = true;
-
-            ToggleFoldout(isExpanded);
-        }
-
-        /// <summary>
-        /// Starts a clone operation. Adds a new key/value pair by cloning an existing one. Allows the user to modify the 
-        /// new pair in a temporary row before inserting them into the dictionary. Caller must ensure no edit operation is 
-        /// already in progress.
-        /// </summary>
-        /// <param name="rowIdx">Sequential row index of the entry to clone.</param>
-        private void StartClone(int rowIdx)
-        {
-            KeyValuePair<object, object> clone = CloneElement(rowIdx);
-
-            editKey = clone.Key;
-            editValue = clone.Value;
-            editOriginalKey = null;
-            editRowIdx = rows.Count;
-
-            editRow.BuildGUI();
-            editRow.Enabled = true;
-            editRow.EditMode = true;
-
-            ToggleFoldout(isExpanded);
-        }
-
-        /// <summary>
-        /// Attempts to apply any changes made to the currently edited row.
-        /// </summary>
-        /// <returns>True if the changes were successfully applied, false if the new key already exists in the dictionary.
-        ///          </returns>
-        private bool ApplyChanges()
-        {
-            if (!IsEditInProgress())
-                return true;
-
-            if (Contains(editKey) && (editOriginalKey == null || !editOriginalKey.Equals(editKey)))
-            {
-                DialogBox.Open(
-                    new LocEdString("Key already exists."),
-                    new LocEdString("Cannot add a key \"" + editKey + "\" to dictionary. Key already exists"),
-                    DialogBox.Type.OK);
-
-                return false;
-            }
-            else
-            {
-                if (IsTemporaryRow(editRowIdx))
-                {
-                    editRow.EditMode = false;
-                    editRow.Enabled = false;
-                }
-                else
-                {
-                    rows[editRowIdx].EditMode = false;
-                }
-
-                if (editOriginalKey != null) // Editing
-                    EditEntry(editOriginalKey, editKey, editValue);
-                else // Adding/Cloning
-                {
-                    AddEntry(editKey, editValue);
-
-                    // Hidden dependency: Initialize must be called after all elements are 
-                    // in the dictionary so we do it in two steps
-                    int newRowIdx = rows.Count;
-                    rows[newRowIdx] = CreateRow();
-                    rows[newRowIdx].Initialize(this, guiContentLayout, newRowIdx, depth + 1);
-                }
-
-                editRow.SetIndex(rows.Count);
-
-                editKey = CreateKey();
-                editValue = CreateValue();
-                editOriginalKey = null;
-                editRowIdx = -1;
-
-                ToggleFoldout(isExpanded);
-                isModified = true;
-
-                return true;
-            }
-        }
-
-        /// <summary>
-        /// Cancels any changes made on the currently edited row.
-        /// </summary>
-        private void DiscardChanges()
-        {
-            if (IsEditInProgress())
-            {
-                if (IsTemporaryRow(editRowIdx))
-                {
-                    editRow.EditMode = false;
-                    editRow.Enabled = false;
-                }
-                else
-                {
-                    rows[editRowIdx].EditMode = false;
-                }
-
-                editKey = CreateKey();
-                editValue = CreateValue();
-                editOriginalKey = null;
-                editRow.Enabled = false;
-                editRowIdx = -1;
-
-                ToggleFoldout(isExpanded);
-            }
-        }
-
-        /// <summary>
-        /// Possible states dictionary GUI can be in.
-        /// </summary>
-        private enum State
-        {
-            None,
-            Empty,
-            Filled
-        }
-    }
-
-    /// <summary>
-    /// Creates GUI elements that allow viewing and manipulation of a <see cref="Dictionary{TKey,TValue}"/>. When constructing the
-    /// object user can provide a custom type that manages GUI for individual dictionary elements.
-    /// </summary>
-    /// <typeparam name="Key">Type of key used by the dictionary.</typeparam>
-    /// <typeparam name="Value">Type of value stored in the dictionary.</typeparam>
-    /// <typeparam name="RowType">Type of rows that are used to handle GUI for individual dictionary elements.</typeparam>
-    public class GUIDictionaryField<Key, Value, RowType> : GUIDictionaryFieldBase where RowType : GUIDictionaryFieldRow, new()
-    {
-        public delegate int SortDictionaryDelegate(Key a, Key b);
-
-        /// <summary>
-        /// Triggered when the reference array has been changed. This does not include changes that only happen to its 
-        /// internal elements.
-        /// </summary>
-        public Action<Dictionary<Key, Value>> OnChanged;
-
-        /// <summary>
-        /// Triggered when an element in the list has been added or changed.
-        /// </summary>
-        public Action<Key> OnValueChanged;
-
-        /// <summary>
-        /// Triggered when an element in the dictionary has been removed.
-        /// </summary>
-        public Action<Key> OnValueRemoved;
-
-        /// <summary>
-        /// Optional method that will be used for sorting the elements in the dictionary.
-        /// </summary>
-        public SortDictionaryDelegate SortMethod;
-
-        /// <summary>
-        /// Array object whose contents are displayed.
-        /// </summary>
-        public Dictionary<Key, Value> Dictionary { get { return dictionary; } }
-        protected Dictionary<Key, Value> dictionary;
-
-        private List<Key> orderedKeys = new List<Key>();
-
-        /// <summary>
-        /// Constructs a new dictionary GUI field.
-        /// </summary>
-        /// <param name="title">Label to display on the dictionary GUI title.</param>
-        /// <param name="dictionary">Object containing the data. Can be null.</param>
-        /// <param name="layout">Layout to which to append the list GUI elements to.</param>
-        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
-        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
-        ///                     depths divisible by two will use an alternate style.</param>
-        protected GUIDictionaryField(LocString title, Dictionary<Key, Value> dictionary, GUILayout layout, int depth = 0)
-            : base(title, layout, depth)
-        {
-            this.dictionary = dictionary;
-            UpdateKeys();
-        }
-
-        /// <summary>
-        /// Creates a dictionary GUI field containing GUI elements required for displaying the provided dictionary.
-        /// </summary>
-        /// <typeparam name="RowType">Type of rows that are used to handle GUI for individual dictionary elements.</typeparam>
-        /// <param name="title">Label to display on the list GUI title.</param>
-        /// <param name="dictionary">Object containing the data. Can be null.</param>
-        /// <param name="layout">Layout to which to append the list GUI elements to.</param>
-        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
-        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
-        ///                     depths divisible by two will use an alternate style.</param>
-        /// <returns>New instance of dictionary GUI field.</returns>
-        public static GUIDictionaryField<Key, Value, RowType> Create(LocString title, Dictionary<Key, Value> dictionary, 
-            GUILayout layout, int depth = 0)
-
-        {
-            GUIDictionaryField<Key, Value, RowType> guiDictionary = new GUIDictionaryField<Key, Value, RowType>(
-                title, dictionary, layout, depth);
-
-            guiDictionary.BuildGUI();
-            return guiDictionary;
-        }
-
-        /// <summary>
-        /// Updates the ordered set of keys used for mapping sequential indexes to keys. Should be called whenever a 
-        /// dictionary key changes.
-        /// </summary>
-        private void UpdateKeys()
-        {
-            orderedKeys.Clear();
-
-            if (dictionary != null)
-            {
-                foreach (var KVP in dictionary)
-                    orderedKeys.Add(KVP.Key);
-
-                if (SortMethod != null)
-                    orderedKeys.Sort((x,y) => SortMethod(x, y));
-                else
-                    orderedKeys.Sort();
-            }
-        }
-
-        /// <inheritdoc/>
-        protected override GUIDictionaryFieldRow CreateRow()
-        {
-            return new RowType();
-        }
-
-        /// <inheritdoc/>
-        protected override int GetNumRows()
-        {
-            if (dictionary != null)
-                return dictionary.Count;
-
-            return 0;
-        }
-
-        /// <inheritdoc/>
-        protected override bool IsNull()
-        {
-            return dictionary == null;
-        }
-
-        /// <inheritdoc/>
-        protected internal override object GetKey(int rowIdx)
-        {
-            return orderedKeys[rowIdx];
-        }
-
-        /// <inheritdoc/>
-        protected internal override object GetValue(object key)
-        {
-            return dictionary[(Key)key];
-        }
-
-        /// <inheritdoc/>
-        protected internal override void SetValue(object key, object value)
-        {
-            dictionary[(Key)key] = (Value)value;
-
-            if (OnValueChanged != null)
-                OnValueChanged((Key)key);
-        }
-
-        /// <inheritdoc/>
-        protected internal override bool Contains(object key)
-        {
-            return dictionary.ContainsKey((Key)key); ;
-        }
-
-        /// <inheritdoc/>
-        protected internal override void EditEntry(object oldKey, object newKey, object value)
-        {
-            dictionary.Remove((Key)oldKey);
-            dictionary[(Key)newKey] = (Value)value;
-
-            if (OnValueRemoved != null)
-                OnValueRemoved((Key)oldKey);
-
-            if (OnValueChanged != null)
-                OnValueChanged((Key)newKey);
-
-            UpdateKeys();
-        }
-
-        /// <inheritdoc/>
-        protected internal override void AddEntry(object key, object value)
-        {
-            dictionary[(Key)key] = (Value)value;
-
-            if (OnValueChanged != null)
-                OnValueChanged((Key)key);
-
-            UpdateKeys();
-        }
-
-        /// <inheritdoc/>
-        protected internal override void RemoveEntry(object key)
-        {
-            dictionary.Remove((Key) key);
-
-            if (OnValueRemoved != null)
-                OnValueRemoved((Key)key);
-
-            UpdateKeys();
-        }
-
-        /// <inheritdoc/>
-        protected internal override object CreateKey()
-        {
-            return SerializableUtility.Create<Key>();
-        }
-
-        /// <inheritdoc/>
-        protected internal override object CreateValue()
-        {
-            return SerializableUtility.Create<Value>();
-        }
-
-        /// <inheritdoc/>
-        protected internal override KeyValuePair<object, object> CloneElement(int index)
-        {
-            object key = GetKey(index);
-            object value = GetValue(key);
-
-            KeyValuePair<object, object> clone = new KeyValuePair<object, object>(
-                SerializableUtility.Clone(key), SerializableUtility.Clone(value));
-
-            return clone;
-        }
-
-        /// <inheritdoc/>
-        protected override void CreateDictionary()
-        {
-            dictionary = new Dictionary<Key, Value>();
-
-            if (OnChanged != null)
-                OnChanged(dictionary);
-
-            UpdateKeys();
-        }
-
-        /// <inheritdoc/>
-        protected override void DeleteDictionary()
-        {
-            dictionary = null;
-
-            if (OnChanged != null)
-                OnChanged(dictionary);
-
-            UpdateKeys();
-        }
-    }
-
-    /// <summary>
-    /// Contains GUI elements for a single entry in a dictionary.
-    /// </summary>
-    public abstract class GUIDictionaryFieldRow
-    {
-        private GUILayoutY rowLayout;
-        private GUILayoutX keyRowLayout;
-        private GUILayoutY keyLayout;
-        private GUILayoutY valueLayout;
-        private GUILayoutX titleLayout;
-        private GUIButton cloneBtn;
-        private GUIButton deleteBtn;
-        private GUIButton editBtn;
-        private bool localTitleLayout;
-        private bool enabled = true;
-        private bool editMode = false;
-        private GUIDictionaryFieldBase parent;
-        private int rowIdx;
-        private int depth;
-        private InspectableState modifiedState;
-
-        /// <summary>
-        /// Returns the depth at which the row is rendered.
-        /// </summary>
-        protected int Depth { get { return depth; } }
-
-        /// <summary>
-        /// Determines is the row currently being displayed.
-        /// </summary>
-        internal bool Enabled
-        {
-            get { return enabled; }
-            set { enabled = value; rowLayout.Active = value; }
-        }
-
-        /// <summary>
-        /// Enables or disables the row's edit mode. This determines what type of buttons are shown on the row title bar.
-        /// </summary>
-        internal bool EditMode
-        {
-            set
-            {
-                if (value)
-                {
-                    GUIContent cancelIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Cancel));
-                    GUIContent applyIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Apply));
-
-                    deleteBtn.SetContent(cancelIcon);
-                    editBtn.SetContent(applyIcon);
-                }
-                else
-                {
-                    GUIContent deleteIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Delete));
-                    GUIContent editIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Edit));
-
-                    deleteBtn.SetContent(deleteIcon);
-                    editBtn.SetContent(editIcon);
-                }
-
-                editMode = value;
-                OnEditModeChanged(value);
-            }
-        }
-
-        /// <summary>
-        /// Constructs a new dictionary row object.
-        /// </summary>
-        protected GUIDictionaryFieldRow()
-        {
-
-        }
-
-        /// <summary>
-        ///  Initializes the row and creates row GUI elements.
-        /// </summary>
-        /// <param name="parent">Parent array GUI object that the entry is contained in.</param>
-        /// <param name="parentLayout">Parent layout that row GUI elements will be added to.</param>
-        /// <param name="rowIdx">Sequential index of the row.</param>
-        /// <param name="depth">Determines the depth at which the element is rendered.</param>
-        internal void Initialize(GUIDictionaryFieldBase parent, GUILayout parentLayout, int rowIdx, int depth)
-        {
-            this.parent = parent;
-            this.rowIdx = rowIdx;
-            this.depth = depth;
-
-            rowLayout = parentLayout.AddLayoutY();
-            keyRowLayout = rowLayout.AddLayoutX();
-            keyLayout = keyRowLayout.AddLayoutY();
-            valueLayout = rowLayout.AddLayoutY();
-
-            BuildGUI();
-        }
-
-        /// <summary>
-        /// Changes the index of the dictionary element this row represents.
-        /// </summary>
-        /// <param name="seqIndex">Sequential index of the dictionary entry.</param>
-        internal void SetIndex(int seqIndex)
-        {
-            this.rowIdx = seqIndex;
-        }
-
-        /// <summary>
-        /// (Re)creates all row GUI elements.
-        /// </summary>
-        internal protected void BuildGUI()
-        {
-            keyLayout.Clear();
-            valueLayout.Clear();
-
-            GUILayoutX externalTitleLayout = CreateKeyGUI(keyLayout);
-            CreateValueGUI(valueLayout);
-            if (localTitleLayout || (titleLayout != null && titleLayout == externalTitleLayout))
-                return;
-
-            if (externalTitleLayout != null)
-            {
-                localTitleLayout = false;
-                titleLayout = externalTitleLayout;
-            }
-            else
-            {
-                GUILayoutY buttonCenter = keyRowLayout.AddLayoutY();
-                buttonCenter.AddFlexibleSpace();
-                titleLayout = buttonCenter.AddLayoutX();
-                buttonCenter.AddFlexibleSpace();
-
-                localTitleLayout = true;
-            }
-
-            GUIContent cloneIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Clone));
-            GUIContent deleteIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Delete));
-            GUIContent editIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Edit));
-
-            cloneBtn = new GUIButton(cloneIcon, GUIOption.FixedWidth(30));
-            deleteBtn = new GUIButton(deleteIcon, GUIOption.FixedWidth(30));
-            editBtn = new GUIButton(editIcon, GUIOption.FixedWidth(30));
-
-            cloneBtn.OnClick += () => parent.OnCloneButtonClicked(rowIdx);
-            deleteBtn.OnClick += () => parent.OnDeleteButtonClicked(rowIdx);
-            editBtn.OnClick += () => parent.OnEditButtonClicked(rowIdx);
-
-            titleLayout.AddElement(cloneBtn);
-            titleLayout.AddElement(deleteBtn);
-            titleLayout.AddSpace(10);
-            titleLayout.AddElement(editBtn);
-
-            EditMode = editMode;
-        }
-
-        /// <summary>
-        /// Creates GUI elements specific to type in the key portion of a dictionary entry.
-        /// </summary>
-        /// <param name="layout">Layout to insert the row GUI elements to.</param>
-        /// <returns>An optional title bar layout that the standard dictionary buttons will be appended to.</returns>
-        protected abstract GUILayoutX CreateKeyGUI(GUILayoutY layout);
-
-        /// <summary>
-        /// Creates GUI elements specific to type in the key portion of a dictionary entry.
-        /// </summary>
-        /// <param name="layout">Layout to insert the row GUI elements to.</param>
-        protected abstract void CreateValueGUI(GUILayoutY layout);
-
-        /// <summary>
-        /// Triggered when a GUI rows enters or leaves edit mode. Allows the row GUI to be updated accordingly.
-        /// </summary>
-        /// <param name="editMode">True if the edit mode is being enabled, false otherwise.</param>
-        protected virtual void OnEditModeChanged(bool editMode) { }
-
-        /// <summary>
-        /// Refreshes the GUI for the dictionary row and checks if anything was modified.
-        /// </summary>
-        /// <returns>State representing was anything modified between two last calls to <see cref="Refresh"/>.</returns>
-        internal protected virtual InspectableState Refresh()
-        {
-            InspectableState oldState = modifiedState;
-            if (modifiedState.HasFlag(InspectableState.Modified))
-                modifiedState = InspectableState.NotModified;
-
-            return oldState;
-        }
-
-        /// <summary>
-        /// Marks the contents of the row as modified.
-        /// </summary>
-        protected void MarkAsModified()
-        {
-            modifiedState |= InspectableState.ModifyInProgress;
-        }
-
-        /// <summary>
-        /// Confirms any queued modifications, signaling parent elements.
-        /// </summary>
-        protected void ConfirmModify()
-        {
-            if (modifiedState.HasFlag(InspectableState.ModifyInProgress))
-                modifiedState |= InspectableState.Modified;
-        }
-
-        /// <summary>
-        /// Gets the key contained in this dictionary's row.
-        /// </summary>
-        /// <typeparam name="T">Type of the key. Must match the dictionary's element type.</typeparam>
-        /// <returns>Key in this dictionary's row.</returns>
-        protected T GetKey<T>()
-        {
-            return (T)parent.GetKeyInternal(rowIdx);
-        }
-
-        /// <summary>
-        /// Sets the key for in this dictionary's row.
-        /// </summary>
-        /// <typeparam name="T">Type of the key. Must match the dictionary's element type.</typeparam>
-        /// <param name="key">Key to assign to this row.</param>
-        protected void SetKey<T>(T key)
-        {
-            parent.SetKey(rowIdx, key);
-        }
-
-        /// <summary>
-        /// Gets the value contained in this dictionary's row.
-        /// </summary>
-        /// <typeparam name="T">Type of the value. Must match the dictionary's element type.</typeparam>
-        /// <returns>Value in this dictionary's row.</returns>
-        protected T GetValue<T>()
-        {
-            return (T)parent.GetValueInternal(rowIdx);
-        }
-
-        /// <summary>
-        /// Sets the value contained in this dictionary's row.
-        /// </summary>
-        /// <typeparam name="T">Type of the value. Must match the dictionary's element type.</typeparam>
-        /// <param name="value">Value to set.</param>
-        protected void SetValue<T>(T value)
-        {
-            parent.SetValueInternal(rowIdx, value);
-        }
-
-        /// <summary>
-        /// Destroys all row GUI elements.
-        /// </summary>
-        public void Destroy()
-        {
-            if (rowLayout != null)
-            {
-                rowLayout.Destroy();
-                rowLayout = null;
-            }
-
-            keyRowLayout = null;
-            keyLayout = null;
-            valueLayout = null;
-            titleLayout = null;
-            cloneBtn = null;
-            deleteBtn = null;
-            editBtn = null;
-            localTitleLayout = false;
-        }
-    }
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Base class for objects that display GUI for a modifyable dictionary of elements. Elements can be added, modified or
+    /// removed.
+    /// </summary>
+    public abstract class GUIDictionaryFieldBase
+    {
+        private const int IndentAmount = 5;
+
+        protected Dictionary<int, GUIDictionaryFieldRow> rows = new Dictionary<int, GUIDictionaryFieldRow>();
+        protected GUIDictionaryFieldRow editRow;
+        protected GUILayoutY guiLayout;
+        protected GUILayoutX guiChildLayout;
+        protected GUILayoutX guiTitleLayout;
+        protected GUILayoutX guiInternalTitleLayout;
+        protected GUILayoutY guiContentLayout;
+        protected bool isExpanded;
+        protected int depth;
+        protected LocString title;
+
+        private int editRowIdx = -1;
+        private object editKey;
+        private object editValue;
+        private object editOriginalKey;
+
+        private State state;
+        private bool isModified;
+
+        /// <summary>
+        /// Constructs a new GUI dictionary.
+        /// </summary>
+        /// <param name="title">Label to display on the dictionary GUI title.</param>
+        /// <param name="layout">Layout to which to append the list GUI elements to.</param>
+        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
+        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
+        ///                     depths divisible by two will use an alternate style.</param>
+        protected GUIDictionaryFieldBase(LocString title, GUILayout layout, int depth = 0)
+        {
+            this.title = title;
+            this.depth = depth;
+            guiLayout = layout.AddLayoutY();
+            guiTitleLayout = guiLayout.AddLayoutX();
+        }
+
+        /// <summary>
+        /// Completely rebuilds the dictionary GUI elements.
+        /// </summary>
+        public void BuildGUI()
+        {
+            editKey = CreateKey();
+            editValue = CreateValue();
+
+            UpdateHeaderGUI();
+
+            foreach (var KVP in rows)
+                KVP.Value.Destroy();
+
+            rows.Clear();
+
+            if (editRow != null)
+            {
+                editRow.Destroy();
+                editRow = null;
+            }
+
+            if (!IsNull())
+            {
+                // Hidden dependency: BuildGUI must be called after all elements are 
+                // in the dictionary so we do it in two steps
+                int numRows = GetNumRows();
+                for (int i = 0; i < numRows; i++)
+                {
+                    GUIDictionaryFieldRow newRow = CreateRow();
+                    rows.Add(i, newRow);
+                }
+
+                editRow = CreateRow();
+                editRow.Initialize(this, guiContentLayout, numRows, depth + 1);
+                editRow.Enabled = false;
+
+                for (int i = 0; i < numRows; i++)
+                    rows[i].Initialize(this, guiContentLayout, i, depth + 1);
+            }
+        }
+
+        /// <summary>
+        /// Rebuilds the GUI dictionary header if needed. 
+        /// </summary>
+        protected void UpdateHeaderGUI()
+        {
+            Action BuildEmptyGUI = () =>
+            {
+                guiInternalTitleLayout = guiTitleLayout.InsertLayoutX(0);
+
+                guiInternalTitleLayout.AddElement(new GUILabel(title));
+                guiInternalTitleLayout.AddElement(new GUILabel("Empty", GUIOption.FixedWidth(100)));
+
+                GUIContent createIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Create), 
+                    new LocEdString("Create"));
+                GUIButton createBtn = new GUIButton(createIcon, GUIOption.FixedWidth(30));
+                createBtn.OnClick += OnCreateButtonClicked;
+                guiInternalTitleLayout.AddElement(createBtn);
+            };
+
+            Action BuildFilledGUI = () =>
+            {
+                guiInternalTitleLayout = guiTitleLayout.InsertLayoutX(0);
+
+                GUIToggle guiFoldout = new GUIToggle(title, EditorStyles.Foldout);
+                guiFoldout.Value = isExpanded;
+                guiFoldout.OnToggled += ToggleFoldout;
+
+                GUIContent clearIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Clear), 
+                    new LocEdString("Clear"));
+                GUIButton guiClearBtn = new GUIButton(clearIcon, GUIOption.FixedWidth(30));
+                guiClearBtn.OnClick += OnClearButtonClicked;
+
+                GUIContent addIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Add), 
+                    new LocEdString("Add"));
+                GUIButton guiAddBtn = new GUIButton(addIcon, GUIOption.FixedWidth(30));
+                guiAddBtn.OnClick += OnAddButtonClicked;
+
+                guiInternalTitleLayout.AddElement(guiFoldout);
+                guiInternalTitleLayout.AddElement(guiAddBtn);
+                guiInternalTitleLayout.AddElement(guiClearBtn);
+
+                guiChildLayout = guiLayout.AddLayoutX();
+                guiChildLayout.AddSpace(IndentAmount);
+
+                GUIPanel guiContentPanel = guiChildLayout.AddPanel();
+                GUILayoutX guiIndentLayoutX = guiContentPanel.AddLayoutX();
+                guiIndentLayoutX.AddSpace(IndentAmount);
+                GUILayoutY guiIndentLayoutY = guiIndentLayoutX.AddLayoutY();
+                guiIndentLayoutY.AddSpace(IndentAmount);
+                guiContentLayout = guiIndentLayoutY.AddLayoutY();
+                guiIndentLayoutY.AddSpace(IndentAmount);
+                guiIndentLayoutX.AddSpace(IndentAmount);
+                guiChildLayout.AddSpace(IndentAmount);
+
+                short backgroundDepth = (short)(Inspector.START_BACKGROUND_DEPTH - depth - 1);
+                string bgPanelStyle = depth % 2 == 0
+                    ? EditorStyles.InspectorContentBgAlternate
+                    : EditorStyles.InspectorContentBg;
+
+                GUIPanel backgroundPanel = guiContentPanel.AddPanel(backgroundDepth);
+                GUITexture inspectorContentBg = new GUITexture(null, bgPanelStyle);
+                backgroundPanel.AddElement(inspectorContentBg);
+
+                ToggleFoldout(isExpanded);
+            };
+
+            if (state == State.None)
+            {
+                if (!IsNull())
+                {
+                    BuildFilledGUI();
+                    state = State.Filled;
+                }
+                else
+                {
+                    BuildEmptyGUI();
+
+                    state = State.Empty;
+                }
+            }
+            else if (state == State.Empty)
+            {
+                if (!IsNull())
+                {
+                    guiInternalTitleLayout.Destroy();
+                    BuildFilledGUI();
+                    state = State.Filled;
+                }
+            }
+            else if (state == State.Filled)
+            {
+                if (IsNull())
+                {
+                    guiInternalTitleLayout.Destroy();
+                    guiChildLayout.Destroy();
+                    BuildEmptyGUI();
+
+                    state = State.Empty;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Destroys all rows and clears the row list.
+        /// </summary>
+        private void ClearRows()
+        {
+            foreach (var KVP in rows)
+                KVP.Value.Destroy();
+
+            editRow.Destroy();
+            rows.Clear();
+        }
+
+        /// <summary>
+        /// Returns the layout that is used for positioning the elements in the title bar.
+        /// </summary>
+        /// <returns>Horizontal layout for positioning the title bar elements.</returns>
+        public GUILayoutX GetTitleLayout()
+        {
+            return guiTitleLayout;
+        }
+
+        /// <summary>
+        /// Refreshes contents of all dictionary rows and checks if anything was modified.
+        /// </summary>
+        /// <returns>State representing was anything modified between two last calls to <see cref="Refresh"/>.</returns>
+        public virtual InspectableState Refresh()
+        {
+            InspectableState state = InspectableState.NotModified;
+            for (int i = 0; i < rows.Count; i++)
+                state |= rows[i].Refresh();
+
+            if (editRow != null && editRow.Enabled)
+                state |= editRow.Refresh();
+
+            if (isModified)
+            {
+                state |= InspectableState.Modified;
+                isModified = false;
+            }
+
+            return state;
+        }
+
+        /// <summary>
+        /// Destroys the GUI elements.
+        /// </summary>
+        public void Destroy()
+        {
+            if (guiLayout != null)
+            {
+                guiLayout.Destroy();
+                guiLayout = null;
+            }
+
+            guiLayout = null;
+            guiTitleLayout = null;
+            guiChildLayout = null;
+
+            for (int i = 0; i < rows.Count; i++)
+                rows[i].Destroy();
+
+            rows.Clear();
+
+            if (editRow != null)
+                editRow.Destroy();
+
+            editRow = null;
+        }
+
+        /// <summary>
+        /// Checks is the specified row index the temporary edit row.
+        /// </summary>
+        /// <param name="rowIdx">Sequential index of the row to check.</param>
+        /// <returns>True if the index is of an edit row.</returns>
+        private bool IsTemporaryRow(int rowIdx)
+        {
+            return rowIdx == rows.Count;
+        }
+
+        /// <summary>
+        /// Checks is any row being currently edited.
+        /// </summary>
+        /// <returns>True if a row is being edited, false otherwise.</returns>
+        private bool IsEditInProgress()
+        {
+            return editRowIdx != -1;
+        }
+
+        /// <summary>
+        /// Returns the number of rows in the dictionary.
+        /// </summary>
+        /// <returns>Number of rows in the dictionary.</returns>
+        protected abstract int GetNumRows();
+
+        /// <summary>
+        /// Checks is the dictionary instance not assigned.
+        /// </summary>
+        /// <returns>True if there is not a dictionary instance.</returns>
+        protected abstract bool IsNull();
+
+        /// <summary>
+        /// Gets a value of an element at the specified index in the list. Also handles temporary edit fields.
+        /// </summary>
+        /// <param name="rowIdx">Sequential index of the row to set the value for.</param>
+        /// <returns>Value of the list element at the specified key.</returns>
+        protected internal virtual object GetValueInternal(int rowIdx)
+        {
+            if (rowIdx == editRowIdx || IsTemporaryRow(rowIdx))
+                return editValue;
+            else
+                return GetValue(GetKey(rowIdx));
+        }
+
+        /// <summary>
+        /// Sets a value of an element at the specified index in the list. Also handles temporary edit fields.
+        /// </summary>
+        /// <param name="rowIdx">Sequential index of the row to set the value for.</param>
+        /// <param name="value">Value to assign to the element. Caller must ensure it is of valid type.</param>
+        protected internal virtual void SetValueInternal(int rowIdx, object value)
+        {
+            if (rowIdx == editRowIdx || IsTemporaryRow(rowIdx))
+                editValue = value;
+            else
+                SetValue(GetKey(rowIdx), value);
+        }
+
+        /// <summary>
+        /// Changes the value of the key of the specified row.
+        /// </summary>
+        /// <param name="rowIdx">Sequential index of the row to set the key for.</param>
+        /// <param name="key">Key to assign to the specified row.</param>
+        protected internal void SetKey(int rowIdx, object key)
+        {
+            if (editRowIdx != rowIdx)
+            {
+                Debug.LogError("Cannot change a dictionary row that is not in edit state.");
+                return;
+            }
+
+            editKey = key;
+        }
+
+        /// <summary>
+        /// Gets a key for a row at the specified index. Handles the special case for the currently edited row.
+        /// </summary>
+        /// <param name="rowIdx">Sequential index of the row for which to retrieve the key.</param>
+        /// <returns>Key for a row at the specified index.</returns>
+        protected internal object GetKeyInternal(int rowIdx)
+        {
+            if (editRowIdx == rowIdx || IsTemporaryRow(rowIdx))
+                return editKey;
+
+            return GetKey(rowIdx);
+        }
+
+        /// <summary>
+        /// Creates a new dictionary row GUI.
+        /// </summary>
+        /// <returns>Object containing the dictionary row GUI.</returns>
+        protected abstract GUIDictionaryFieldRow CreateRow();
+
+        /// <summary>
+        /// Gets a key for a row at the specified index.
+        /// </summary>
+        /// <param name="rowIdx">Sequential index of the row for which to retrieve the key.</param>
+        /// <returns>Key for a row at the specified index.</returns>
+        protected internal abstract object GetKey(int rowIdx);
+
+        /// <summary>
+        /// Gets a value of an element at the specified index in the list.
+        /// </summary>
+        /// <param name="key">Key of the element whose value to retrieve.</param>
+        /// <returns>Value of the dictionary entry for the specified key.</returns>
+        protected internal abstract object GetValue(object key);
+
+        /// <summary>
+        /// Sets a value of an element at the specified index in the list.
+        /// </summary>
+        /// <param name="key">Key of the element whose value to set.</param>
+        /// <param name="value">Value to assign to the element. Caller must ensure it is of valid type.</param>
+        protected internal abstract void SetValue(object key, object value);
+
+        /// <summary>
+        /// Updates both key and value of an existing entry.
+        /// </summary>
+        /// <param name="oldKey">Original key of the entry.</param>
+        /// <param name="newKey">New key of the entry.</param>
+        /// <param name="value">New value of the entry.</param>
+        protected internal abstract void EditEntry(object oldKey, object newKey, object value);
+
+        /// <summary>
+        /// Adds a new entry to the dictionary.
+        /// </summary>
+        /// <param name="key">Key of the entry to add.</param>
+        /// <param name="value">Value of the entry to add.</param>
+        protected internal abstract void AddEntry(object key, object value);
+
+        /// <summary>
+        /// Removes the specified entry from the dictionary.
+        /// </summary>
+        /// <param name="key">Key of the entry to remove.</param>
+        protected internal abstract void RemoveEntry(object key);
+
+        /// <summary>
+        /// Creates a new empty key object of a valid type that can be used in the dictionary.
+        /// </summary>
+        /// <returns>New empty key object.</returns>
+        protected internal abstract object CreateKey();
+
+        /// <summary>
+        /// Creates a new empty value object of a valid type that can be used in the dictionary.
+        /// </summary>
+        /// <returns>New empty value object.</returns>
+        protected internal abstract object CreateValue();
+
+        /// <summary>
+        /// Checks does the element with the specified key exist in the dictionary.
+        /// </summary>
+        /// <param name="key">Key of the element to check for existence.</param>
+        /// <returns>True if the key exists in the dictionary, false otherwise.</returns>
+        protected internal abstract bool Contains(object key);
+
+        /// <summary>
+        /// Clones the specified dictionary element.
+        /// </summary>
+        /// <param name="index">Sequential index of the element in the dictionary to clone.</param>
+        protected internal abstract KeyValuePair<object, object> CloneElement(int index);
+
+        /// <summary>
+        /// Creates a brand new dictionary with zero elements in the place of the current dictionary.
+        /// </summary>
+        protected abstract void CreateDictionary();
+
+        /// <summary>
+        /// Deletes the current dictionary object.
+        /// </summary>
+        protected abstract void DeleteDictionary();
+
+        /// <summary>
+        /// Hides or shows the dictionary rows.
+        /// </summary>
+        /// <param name="expanded">True if the rows should be displayed, false otherwise.</param>
+        private void ToggleFoldout(bool expanded)
+        {
+            isExpanded = expanded;
+
+            if (guiChildLayout != null)
+                guiChildLayout.Active = isExpanded && (rows.Count > 0 || IsEditInProgress());
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the create button on the title bar. Creates a brand new dictionary with zero
+        /// elements in the place of the current dictionary.
+        /// </summary>
+        protected void OnCreateButtonClicked()
+        {
+            CreateDictionary();
+            UpdateHeaderGUI();
+
+            editRow.Initialize(this, guiContentLayout, 0, depth + 1);
+            editRow.Enabled = false;
+
+            isModified = true;
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the add button on the title bar. Adds a new empty element to the dictionary.
+        /// </summary>
+        protected virtual void OnAddButtonClicked()
+        {
+            if (IsEditInProgress())
+            {
+                DialogBox.Open(
+                    new LocEdString("Edit in progress."),
+                    new LocEdString("You are editing the entry with key \"" + editKey + "\". You cannot add a row " +
+                                    "before applying or discarding those changes. Do you wish to apply those changes first?"),
+                    DialogBox.Type.YesNoCancel,
+                    x =>
+                    {
+                        switch (x)
+                        {
+                            case DialogBox.ResultType.Yes:
+                                if (ApplyChanges())
+                                    StartAdd();
+                                break;
+                            case DialogBox.ResultType.No:
+                                DiscardChanges();
+                                StartAdd();
+                                break;
+                        }
+                    });
+            }
+            else
+            {
+                if (!isExpanded)
+                    ToggleFoldout(true);
+
+                StartAdd();
+            }
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the clear button on the title bar. Deletes the current dictionary object.
+        /// </summary>
+        protected void OnClearButtonClicked()
+        {
+            DeleteDictionary();
+            UpdateHeaderGUI();
+            ClearRows();
+
+            isModified = true;
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the delete button next to a dictionary entry. Deletes an element in the 
+        /// dictionary. 
+        /// </summary>
+        /// <param name="rowIdx">Sequential row index of the entry that was clicked.</param>
+        protected internal virtual void OnDeleteButtonClicked(int rowIdx)
+        {
+            if (IsEditInProgress())
+                DiscardChanges();
+            else
+            {
+                RemoveEntry(GetKey(rowIdx));
+
+                rows[rows.Count - 1].Destroy();
+                rows.Remove(rows.Count - 1);
+
+                editRow.SetIndex(GetNumRows());
+                isModified = true;
+            }
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the clone button next to a dictionary entry. Clones an element and
+        /// adds the clone to the dictionary.
+        /// </summary>
+        /// <param name="rowIdx">Sequential row index of the entry that was clicked.</param>
+        protected internal virtual void OnCloneButtonClicked(int rowIdx)
+        {
+            if (IsEditInProgress())
+            {
+                DialogBox.Open(
+                    new LocEdString("Edit in progress."),
+                    new LocEdString("You are editing the entry with key \"" + editKey + "\". You cannot clone a row " +
+                        "before applying or discarding those changes. Do you wish to apply those changes first?"),
+                    DialogBox.Type.YesNoCancel,
+                    x =>
+                    {
+                        switch (x)
+                        {
+                            case DialogBox.ResultType.Yes:
+                                if (ApplyChanges())
+                                    StartClone(rowIdx);
+                                break;
+                            case DialogBox.ResultType.No:
+                                DiscardChanges();
+                                StartClone(rowIdx);
+                                break;
+                        }
+                    });
+            }
+            else
+                StartClone(rowIdx);
+        }
+
+        /// <summary>
+        /// Triggered when user clicks the edit or apply (depending on state) button next to the dictionary entry. Starts
+        /// edit mode for the element, if not already in edit mode. Applies edit mode changes if already in edit mode.
+        /// </summary>
+        /// <param name="rowIdx">Sequential row index of the entry that was clicked.</param>
+        protected internal virtual void OnEditButtonClicked(int rowIdx)
+        {
+            if (editRowIdx == rowIdx)
+                ApplyChanges();
+            else
+            {
+                if (IsEditInProgress())
+                {
+                    DialogBox.Open(
+                        new LocEdString("Edit in progress."),
+                        new LocEdString("You are already editing the entry with key \"" + editKey + "\". You cannot edit " +
+                            "another row before applying or discarding those changes. Do you wish to apply those changes first?"),
+                        DialogBox.Type.YesNoCancel,
+                        x =>
+                        {
+                            switch (x)
+                            {
+                                case DialogBox.ResultType.Yes:
+                                    if (ApplyChanges())
+                                        StartEdit(rowIdx);
+                                    break;
+                                case DialogBox.ResultType.No:
+                                    DiscardChanges();
+                                    StartEdit(rowIdx);
+                                    break;
+                            }
+                        });
+                }
+                else
+                    StartEdit(rowIdx);
+            }
+        }
+
+        /// <summary>
+        /// Starts an edit operation on a row with the specified key. Allows the user to change the key of the specified row.
+        /// Caller must ensure no edit operation is already in progress.
+        /// </summary>
+        /// <param name="rowIdx">Sequential row index of the entry to edit.</param>
+        private void StartEdit(int rowIdx)
+        {
+            object key = GetKey(rowIdx);
+            KeyValuePair<object, object> clone = CloneElement(rowIdx);
+
+            editKey = clone.Key;
+            editValue = clone.Value;
+            editOriginalKey = key;
+            editRowIdx = rowIdx;
+
+            rows[rowIdx].EditMode = true;
+            guiChildLayout.Active = rows.Count > 0 && isExpanded;
+        }
+
+        /// <summary>
+        /// Starts an add operation. Adds a new key/value pair and allows the user to set them up in a temporary row
+        /// before inserting them into the dictionary. Caller must ensure no edit operation is already in progress.
+        /// </summary>
+        private void StartAdd()
+        {
+            editKey = CreateKey();
+            editValue = CreateValue();
+            editOriginalKey = null;
+            editRowIdx = rows.Count;
+
+            editRow.BuildGUI();
+            editRow.Enabled = true;
+            editRow.EditMode = true;
+
+            ToggleFoldout(isExpanded);
+        }
+
+        /// <summary>
+        /// Starts a clone operation. Adds a new key/value pair by cloning an existing one. Allows the user to modify the 
+        /// new pair in a temporary row before inserting them into the dictionary. Caller must ensure no edit operation is 
+        /// already in progress.
+        /// </summary>
+        /// <param name="rowIdx">Sequential row index of the entry to clone.</param>
+        private void StartClone(int rowIdx)
+        {
+            KeyValuePair<object, object> clone = CloneElement(rowIdx);
+
+            editKey = clone.Key;
+            editValue = clone.Value;
+            editOriginalKey = null;
+            editRowIdx = rows.Count;
+
+            editRow.BuildGUI();
+            editRow.Enabled = true;
+            editRow.EditMode = true;
+
+            ToggleFoldout(isExpanded);
+        }
+
+        /// <summary>
+        /// Attempts to apply any changes made to the currently edited row.
+        /// </summary>
+        /// <returns>True if the changes were successfully applied, false if the new key already exists in the dictionary.
+        ///          </returns>
+        private bool ApplyChanges()
+        {
+            if (!IsEditInProgress())
+                return true;
+
+            if (Contains(editKey) && (editOriginalKey == null || !editOriginalKey.Equals(editKey)))
+            {
+                DialogBox.Open(
+                    new LocEdString("Key already exists."),
+                    new LocEdString("Cannot add a key \"" + editKey + "\" to dictionary. Key already exists"),
+                    DialogBox.Type.OK);
+
+                return false;
+            }
+            else
+            {
+                if (IsTemporaryRow(editRowIdx))
+                {
+                    editRow.EditMode = false;
+                    editRow.Enabled = false;
+                }
+                else
+                {
+                    rows[editRowIdx].EditMode = false;
+                }
+
+                if (editOriginalKey != null) // Editing
+                    EditEntry(editOriginalKey, editKey, editValue);
+                else // Adding/Cloning
+                {
+                    AddEntry(editKey, editValue);
+
+                    // Hidden dependency: Initialize must be called after all elements are 
+                    // in the dictionary so we do it in two steps
+                    int newRowIdx = rows.Count;
+                    rows[newRowIdx] = CreateRow();
+                    rows[newRowIdx].Initialize(this, guiContentLayout, newRowIdx, depth + 1);
+                }
+
+                editRow.SetIndex(rows.Count);
+
+                editKey = CreateKey();
+                editValue = CreateValue();
+                editOriginalKey = null;
+                editRowIdx = -1;
+
+                ToggleFoldout(isExpanded);
+                isModified = true;
+
+                return true;
+            }
+        }
+
+        /// <summary>
+        /// Cancels any changes made on the currently edited row.
+        /// </summary>
+        private void DiscardChanges()
+        {
+            if (IsEditInProgress())
+            {
+                if (IsTemporaryRow(editRowIdx))
+                {
+                    editRow.EditMode = false;
+                    editRow.Enabled = false;
+                }
+                else
+                {
+                    rows[editRowIdx].EditMode = false;
+                }
+
+                editKey = CreateKey();
+                editValue = CreateValue();
+                editOriginalKey = null;
+                editRow.Enabled = false;
+                editRowIdx = -1;
+
+                ToggleFoldout(isExpanded);
+            }
+        }
+
+        /// <summary>
+        /// Possible states dictionary GUI can be in.
+        /// </summary>
+        private enum State
+        {
+            None,
+            Empty,
+            Filled
+        }
+    }
+
+    /// <summary>
+    /// Creates GUI elements that allow viewing and manipulation of a <see cref="Dictionary{TKey,TValue}"/>. When constructing the
+    /// object user can provide a custom type that manages GUI for individual dictionary elements.
+    /// </summary>
+    /// <typeparam name="Key">Type of key used by the dictionary.</typeparam>
+    /// <typeparam name="Value">Type of value stored in the dictionary.</typeparam>
+    /// <typeparam name="RowType">Type of rows that are used to handle GUI for individual dictionary elements.</typeparam>
+    public class GUIDictionaryField<Key, Value, RowType> : GUIDictionaryFieldBase where RowType : GUIDictionaryFieldRow, new()
+    {
+        public delegate int SortDictionaryDelegate(Key a, Key b);
+
+        /// <summary>
+        /// Triggered when the reference array has been changed. This does not include changes that only happen to its 
+        /// internal elements.
+        /// </summary>
+        public Action<Dictionary<Key, Value>> OnChanged;
+
+        /// <summary>
+        /// Triggered when an element in the list has been added or changed.
+        /// </summary>
+        public Action<Key> OnValueChanged;
+
+        /// <summary>
+        /// Triggered when an element in the dictionary has been removed.
+        /// </summary>
+        public Action<Key> OnValueRemoved;
+
+        /// <summary>
+        /// Optional method that will be used for sorting the elements in the dictionary.
+        /// </summary>
+        public SortDictionaryDelegate SortMethod;
+
+        /// <summary>
+        /// Array object whose contents are displayed.
+        /// </summary>
+        public Dictionary<Key, Value> Dictionary { get { return dictionary; } }
+        protected Dictionary<Key, Value> dictionary;
+
+        private List<Key> orderedKeys = new List<Key>();
+
+        /// <summary>
+        /// Constructs a new dictionary GUI field.
+        /// </summary>
+        /// <param name="title">Label to display on the dictionary GUI title.</param>
+        /// <param name="dictionary">Object containing the data. Can be null.</param>
+        /// <param name="layout">Layout to which to append the list GUI elements to.</param>
+        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
+        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
+        ///                     depths divisible by two will use an alternate style.</param>
+        protected GUIDictionaryField(LocString title, Dictionary<Key, Value> dictionary, GUILayout layout, int depth = 0)
+            : base(title, layout, depth)
+        {
+            this.dictionary = dictionary;
+            UpdateKeys();
+        }
+
+        /// <summary>
+        /// Creates a dictionary GUI field containing GUI elements required for displaying the provided dictionary.
+        /// </summary>
+        /// <typeparam name="RowType">Type of rows that are used to handle GUI for individual dictionary elements.</typeparam>
+        /// <param name="title">Label to display on the list GUI title.</param>
+        /// <param name="dictionary">Object containing the data. Can be null.</param>
+        /// <param name="layout">Layout to which to append the list GUI elements to.</param>
+        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
+        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
+        ///                     depths divisible by two will use an alternate style.</param>
+        /// <returns>New instance of dictionary GUI field.</returns>
+        public static GUIDictionaryField<Key, Value, RowType> Create(LocString title, Dictionary<Key, Value> dictionary, 
+            GUILayout layout, int depth = 0)
+
+        {
+            GUIDictionaryField<Key, Value, RowType> guiDictionary = new GUIDictionaryField<Key, Value, RowType>(
+                title, dictionary, layout, depth);
+
+            guiDictionary.BuildGUI();
+            return guiDictionary;
+        }
+
+        /// <summary>
+        /// Updates the ordered set of keys used for mapping sequential indexes to keys. Should be called whenever a 
+        /// dictionary key changes.
+        /// </summary>
+        private void UpdateKeys()
+        {
+            orderedKeys.Clear();
+
+            if (dictionary != null)
+            {
+                foreach (var KVP in dictionary)
+                    orderedKeys.Add(KVP.Key);
+
+                if (SortMethod != null)
+                    orderedKeys.Sort((x,y) => SortMethod(x, y));
+                else
+                    orderedKeys.Sort();
+            }
+        }
+
+        /// <inheritdoc/>
+        protected override GUIDictionaryFieldRow CreateRow()
+        {
+            return new RowType();
+        }
+
+        /// <inheritdoc/>
+        protected override int GetNumRows()
+        {
+            if (dictionary != null)
+                return dictionary.Count;
+
+            return 0;
+        }
+
+        /// <inheritdoc/>
+        protected override bool IsNull()
+        {
+            return dictionary == null;
+        }
+
+        /// <inheritdoc/>
+        protected internal override object GetKey(int rowIdx)
+        {
+            return orderedKeys[rowIdx];
+        }
+
+        /// <inheritdoc/>
+        protected internal override object GetValue(object key)
+        {
+            return dictionary[(Key)key];
+        }
+
+        /// <inheritdoc/>
+        protected internal override void SetValue(object key, object value)
+        {
+            dictionary[(Key)key] = (Value)value;
+
+            if (OnValueChanged != null)
+                OnValueChanged((Key)key);
+        }
+
+        /// <inheritdoc/>
+        protected internal override bool Contains(object key)
+        {
+            return dictionary.ContainsKey((Key)key); ;
+        }
+
+        /// <inheritdoc/>
+        protected internal override void EditEntry(object oldKey, object newKey, object value)
+        {
+            dictionary.Remove((Key)oldKey);
+            dictionary[(Key)newKey] = (Value)value;
+
+            if (OnValueRemoved != null)
+                OnValueRemoved((Key)oldKey);
+
+            if (OnValueChanged != null)
+                OnValueChanged((Key)newKey);
+
+            UpdateKeys();
+        }
+
+        /// <inheritdoc/>
+        protected internal override void AddEntry(object key, object value)
+        {
+            dictionary[(Key)key] = (Value)value;
+
+            if (OnValueChanged != null)
+                OnValueChanged((Key)key);
+
+            UpdateKeys();
+        }
+
+        /// <inheritdoc/>
+        protected internal override void RemoveEntry(object key)
+        {
+            dictionary.Remove((Key) key);
+
+            if (OnValueRemoved != null)
+                OnValueRemoved((Key)key);
+
+            UpdateKeys();
+        }
+
+        /// <inheritdoc/>
+        protected internal override object CreateKey()
+        {
+            return SerializableUtility.Create<Key>();
+        }
+
+        /// <inheritdoc/>
+        protected internal override object CreateValue()
+        {
+            return SerializableUtility.Create<Value>();
+        }
+
+        /// <inheritdoc/>
+        protected internal override KeyValuePair<object, object> CloneElement(int index)
+        {
+            object key = GetKey(index);
+            object value = GetValue(key);
+
+            KeyValuePair<object, object> clone = new KeyValuePair<object, object>(
+                SerializableUtility.Clone(key), SerializableUtility.Clone(value));
+
+            return clone;
+        }
+
+        /// <inheritdoc/>
+        protected override void CreateDictionary()
+        {
+            dictionary = new Dictionary<Key, Value>();
+
+            if (OnChanged != null)
+                OnChanged(dictionary);
+
+            UpdateKeys();
+        }
+
+        /// <inheritdoc/>
+        protected override void DeleteDictionary()
+        {
+            dictionary = null;
+
+            if (OnChanged != null)
+                OnChanged(dictionary);
+
+            UpdateKeys();
+        }
+    }
+
+    /// <summary>
+    /// Contains GUI elements for a single entry in a dictionary.
+    /// </summary>
+    public abstract class GUIDictionaryFieldRow
+    {
+        private GUILayoutY rowLayout;
+        private GUILayoutX keyRowLayout;
+        private GUILayoutY keyLayout;
+        private GUILayoutY valueLayout;
+        private GUILayoutX titleLayout;
+        private GUIButton cloneBtn;
+        private GUIButton deleteBtn;
+        private GUIButton editBtn;
+        private bool localTitleLayout;
+        private bool enabled = true;
+        private bool editMode = false;
+        private GUIDictionaryFieldBase parent;
+        private int rowIdx;
+        private int depth;
+        private InspectableState modifiedState;
+
+        /// <summary>
+        /// Returns the depth at which the row is rendered.
+        /// </summary>
+        protected int Depth { get { return depth; } }
+
+        /// <summary>
+        /// Determines is the row currently being displayed.
+        /// </summary>
+        internal bool Enabled
+        {
+            get { return enabled; }
+            set { enabled = value; rowLayout.Active = value; }
+        }
+
+        /// <summary>
+        /// Enables or disables the row's edit mode. This determines what type of buttons are shown on the row title bar.
+        /// </summary>
+        internal bool EditMode
+        {
+            set
+            {
+                if (value)
+                {
+                    GUIContent cancelIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Cancel), 
+                        new LocEdString("Cancel"));
+                    GUIContent applyIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Apply), 
+                        new LocEdString("Apply"));
+
+                    deleteBtn.SetContent(cancelIcon);
+                    editBtn.SetContent(applyIcon);
+                }
+                else
+                {
+                    GUIContent deleteIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Delete), 
+                        new LocEdString("Delete"));
+                    GUIContent editIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Edit), 
+                        new LocEdString("Edit"));
+
+                    deleteBtn.SetContent(deleteIcon);
+                    editBtn.SetContent(editIcon);
+                }
+
+                editMode = value;
+                OnEditModeChanged(value);
+            }
+        }
+
+        /// <summary>
+        /// Constructs a new dictionary row object.
+        /// </summary>
+        protected GUIDictionaryFieldRow()
+        {
+
+        }
+
+        /// <summary>
+        ///  Initializes the row and creates row GUI elements.
+        /// </summary>
+        /// <param name="parent">Parent array GUI object that the entry is contained in.</param>
+        /// <param name="parentLayout">Parent layout that row GUI elements will be added to.</param>
+        /// <param name="rowIdx">Sequential index of the row.</param>
+        /// <param name="depth">Determines the depth at which the element is rendered.</param>
+        internal void Initialize(GUIDictionaryFieldBase parent, GUILayout parentLayout, int rowIdx, int depth)
+        {
+            this.parent = parent;
+            this.rowIdx = rowIdx;
+            this.depth = depth;
+
+            rowLayout = parentLayout.AddLayoutY();
+            keyRowLayout = rowLayout.AddLayoutX();
+            keyLayout = keyRowLayout.AddLayoutY();
+            valueLayout = rowLayout.AddLayoutY();
+
+            BuildGUI();
+        }
+
+        /// <summary>
+        /// Changes the index of the dictionary element this row represents.
+        /// </summary>
+        /// <param name="seqIndex">Sequential index of the dictionary entry.</param>
+        internal void SetIndex(int seqIndex)
+        {
+            this.rowIdx = seqIndex;
+        }
+
+        /// <summary>
+        /// (Re)creates all row GUI elements.
+        /// </summary>
+        internal protected void BuildGUI()
+        {
+            keyLayout.Clear();
+            valueLayout.Clear();
+
+            GUILayoutX externalTitleLayout = CreateKeyGUI(keyLayout);
+            CreateValueGUI(valueLayout);
+            if (localTitleLayout || (titleLayout != null && titleLayout == externalTitleLayout))
+                return;
+
+            if (externalTitleLayout != null)
+            {
+                localTitleLayout = false;
+                titleLayout = externalTitleLayout;
+            }
+            else
+            {
+                GUILayoutY buttonCenter = keyRowLayout.AddLayoutY();
+                buttonCenter.AddFlexibleSpace();
+                titleLayout = buttonCenter.AddLayoutX();
+                buttonCenter.AddFlexibleSpace();
+
+                localTitleLayout = true;
+            }
+
+            GUIContent cloneIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Clone), 
+                new LocEdString("Clone"));
+            GUIContent deleteIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Delete), 
+                new LocEdString("Delete"));
+            GUIContent editIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Edit), 
+                new LocEdString("Edit"));
+
+            cloneBtn = new GUIButton(cloneIcon, GUIOption.FixedWidth(30));
+            deleteBtn = new GUIButton(deleteIcon, GUIOption.FixedWidth(30));
+            editBtn = new GUIButton(editIcon, GUIOption.FixedWidth(30));
+
+            cloneBtn.OnClick += () => parent.OnCloneButtonClicked(rowIdx);
+            deleteBtn.OnClick += () => parent.OnDeleteButtonClicked(rowIdx);
+            editBtn.OnClick += () => parent.OnEditButtonClicked(rowIdx);
+
+            titleLayout.AddElement(cloneBtn);
+            titleLayout.AddElement(deleteBtn);
+            titleLayout.AddSpace(10);
+            titleLayout.AddElement(editBtn);
+
+            EditMode = editMode;
+        }
+
+        /// <summary>
+        /// Creates GUI elements specific to type in the key portion of a dictionary entry.
+        /// </summary>
+        /// <param name="layout">Layout to insert the row GUI elements to.</param>
+        /// <returns>An optional title bar layout that the standard dictionary buttons will be appended to.</returns>
+        protected abstract GUILayoutX CreateKeyGUI(GUILayoutY layout);
+
+        /// <summary>
+        /// Creates GUI elements specific to type in the key portion of a dictionary entry.
+        /// </summary>
+        /// <param name="layout">Layout to insert the row GUI elements to.</param>
+        protected abstract void CreateValueGUI(GUILayoutY layout);
+
+        /// <summary>
+        /// Triggered when a GUI rows enters or leaves edit mode. Allows the row GUI to be updated accordingly.
+        /// </summary>
+        /// <param name="editMode">True if the edit mode is being enabled, false otherwise.</param>
+        protected virtual void OnEditModeChanged(bool editMode) { }
+
+        /// <summary>
+        /// Refreshes the GUI for the dictionary row and checks if anything was modified.
+        /// </summary>
+        /// <returns>State representing was anything modified between two last calls to <see cref="Refresh"/>.</returns>
+        internal protected virtual InspectableState Refresh()
+        {
+            InspectableState oldState = modifiedState;
+            if (modifiedState.HasFlag(InspectableState.Modified))
+                modifiedState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Marks the contents of the row as modified.
+        /// </summary>
+        protected void MarkAsModified()
+        {
+            modifiedState |= InspectableState.ModifyInProgress;
+        }
+
+        /// <summary>
+        /// Confirms any queued modifications, signaling parent elements.
+        /// </summary>
+        protected void ConfirmModify()
+        {
+            if (modifiedState.HasFlag(InspectableState.ModifyInProgress))
+                modifiedState |= InspectableState.Modified;
+        }
+
+        /// <summary>
+        /// Gets the key contained in this dictionary's row.
+        /// </summary>
+        /// <typeparam name="T">Type of the key. Must match the dictionary's element type.</typeparam>
+        /// <returns>Key in this dictionary's row.</returns>
+        protected T GetKey<T>()
+        {
+            return (T)parent.GetKeyInternal(rowIdx);
+        }
+
+        /// <summary>
+        /// Sets the key for in this dictionary's row.
+        /// </summary>
+        /// <typeparam name="T">Type of the key. Must match the dictionary's element type.</typeparam>
+        /// <param name="key">Key to assign to this row.</param>
+        protected void SetKey<T>(T key)
+        {
+            parent.SetKey(rowIdx, key);
+        }
+
+        /// <summary>
+        /// Gets the value contained in this dictionary's row.
+        /// </summary>
+        /// <typeparam name="T">Type of the value. Must match the dictionary's element type.</typeparam>
+        /// <returns>Value in this dictionary's row.</returns>
+        protected T GetValue<T>()
+        {
+            return (T)parent.GetValueInternal(rowIdx);
+        }
+
+        /// <summary>
+        /// Sets the value contained in this dictionary's row.
+        /// </summary>
+        /// <typeparam name="T">Type of the value. Must match the dictionary's element type.</typeparam>
+        /// <param name="value">Value to set.</param>
+        protected void SetValue<T>(T value)
+        {
+            parent.SetValueInternal(rowIdx, value);
+        }
+
+        /// <summary>
+        /// Destroys all row GUI elements.
+        /// </summary>
+        public void Destroy()
+        {
+            if (rowLayout != null)
+            {
+                rowLayout.Destroy();
+                rowLayout = null;
+            }
+
+            keyRowLayout = null;
+            keyLayout = null;
+            valueLayout = null;
+            titleLayout = null;
+            cloneBtn = null;
+            deleteBtn = null;
+            editBtn = null;
+            localTitleLayout = false;
+        }
+    }
 }

+ 1011 - 1004
MBansheeEditor/GUI/GUIListField.cs

@@ -1,1004 +1,1011 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Base class for objects that display GUI for a modifyable list of elements. Elements can be added, removed and moved.
-    /// </summary>
-    public abstract class GUIListFieldBase
-    {
-        private const int IndentAmount = 5;
-
-        protected List<GUIListFieldRow> rows = new List<GUIListFieldRow>();
-        protected GUILayoutY guiLayout;
-        protected GUIIntField guiSizeField;
-        protected GUILayoutX guiChildLayout;
-        protected GUILayoutX guiTitleLayout;
-        protected GUILayoutX guiInternalTitleLayout;
-        protected GUILayoutY guiContentLayout;
-
-        protected bool isExpanded;
-        protected int depth;
-        protected LocString title;
-
-        private State state;
-        private bool isModified;
-
-        /// <summary>
-        /// Constructs a new GUI list.
-        /// </summary>
-        /// <param name="title">Label to display on the list GUI title.</param>
-        /// <param name="layout">Layout to which to append the array GUI elements to.</param>
-        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
-        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
-        ///                     depths divisible by two will use an alternate style.</param>
-        protected GUIListFieldBase(LocString title, GUILayout layout, int depth)
-        {
-            this.title = title;
-            this.depth = depth;
-            guiLayout = layout.AddLayoutY();
-            guiTitleLayout = guiLayout.AddLayoutX();
-        }
-
-        /// <summary>
-        /// (Re)builds the list GUI elements. Must be called at least once in order for the contents to be populated.
-        /// </summary>
-        public void BuildGUI()
-        {
-            UpdateHeaderGUI();
-
-            if (!IsNull())
-            {
-                // Hidden dependency: Initialize must be called after all elements are 
-                // in the dictionary so we do it in two steps
-                int numRows = GetNumRows();
-                int oldNumRows = rows.Count;
-
-                for (int i = oldNumRows; i < numRows; i++)
-                {
-                    GUIListFieldRow newRow = CreateRow();
-                    rows.Add(newRow);
-                }
-
-                for (int i = oldNumRows - 1; i >= numRows; i--)
-                {
-                    rows[i].Destroy();
-                    rows.RemoveAt(i);
-                }
-
-                for (int i = oldNumRows; i < numRows; i++)
-                    rows[i].Initialize(this, guiContentLayout, i, depth + 1);
-
-                for (int i = 0; i < rows.Count; i++)
-                    rows[i].SetIndex(i);
-            }
-            else
-            {
-                foreach (var row in rows)
-                    row.Destroy();
-
-                rows.Clear();
-            }
-        }
-
-        /// <summary>
-        /// Rebuilds the GUI list header if needed.
-        /// </summary>
-        protected void UpdateHeaderGUI()
-        {
-            Action BuildEmptyGUI = () =>
-            {
-                guiInternalTitleLayout = guiTitleLayout.InsertLayoutX(0);
-
-                guiInternalTitleLayout.AddElement(new GUILabel(title));
-                guiInternalTitleLayout.AddElement(new GUILabel("Empty", GUIOption.FixedWidth(100)));
-
-                GUIContent createIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Create));
-                GUIButton createBtn = new GUIButton(createIcon, GUIOption.FixedWidth(30));
-                createBtn.OnClick += OnCreateButtonClicked;
-                guiInternalTitleLayout.AddElement(createBtn);
-            };
-
-            Action BuildFilledGUI = () =>
-            {
-                guiInternalTitleLayout = guiTitleLayout.InsertLayoutX(0);
-
-                GUIToggle guiFoldout = new GUIToggle(title, EditorStyles.Foldout);
-                guiFoldout.Value = isExpanded;
-                guiFoldout.OnToggled += OnFoldoutToggled;
-                guiSizeField = new GUIIntField("", GUIOption.FixedWidth(50));
-                guiSizeField.SetRange(0, int.MaxValue);
-
-                GUIContent resizeIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Resize));
-                GUIButton guiResizeBtn = new GUIButton(resizeIcon, GUIOption.FixedWidth(30));
-                guiResizeBtn.OnClick += OnResizeButtonClicked;
-
-                GUIContent clearIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Clear));
-                GUIButton guiClearBtn = new GUIButton(clearIcon, GUIOption.FixedWidth(30));
-                guiClearBtn.OnClick += OnClearButtonClicked;
-
-                guiInternalTitleLayout.AddElement(guiFoldout);
-                guiInternalTitleLayout.AddElement(guiSizeField);
-                guiInternalTitleLayout.AddElement(guiResizeBtn);
-                guiInternalTitleLayout.AddElement(guiClearBtn);
-
-                guiSizeField.Value = GetNumRows();
-
-                guiChildLayout = guiLayout.AddLayoutX();
-                guiChildLayout.AddSpace(IndentAmount);
-                guiChildLayout.Active = isExpanded;
-
-                GUIPanel guiContentPanel = guiChildLayout.AddPanel();
-                GUILayoutX guiIndentLayoutX = guiContentPanel.AddLayoutX();
-                guiIndentLayoutX.AddSpace(IndentAmount);
-                GUILayoutY guiIndentLayoutY = guiIndentLayoutX.AddLayoutY();
-                guiIndentLayoutY.AddSpace(IndentAmount);
-                guiContentLayout = guiIndentLayoutY.AddLayoutY();
-                guiIndentLayoutY.AddSpace(IndentAmount);
-                guiIndentLayoutX.AddSpace(IndentAmount);
-                guiChildLayout.AddSpace(IndentAmount);
-
-                short backgroundDepth = (short)(Inspector.START_BACKGROUND_DEPTH - depth - 1);
-                string bgPanelStyle = depth % 2 == 0
-                    ? EditorStyles.InspectorContentBgAlternate
-                    : EditorStyles.InspectorContentBg;
-
-                GUIPanel backgroundPanel = guiContentPanel.AddPanel(backgroundDepth);
-                GUITexture inspectorContentBg = new GUITexture(null, bgPanelStyle);
-                backgroundPanel.AddElement(inspectorContentBg);
-            };
-
-            if (state == State.None)
-            {
-                if (!IsNull())
-                {
-                    BuildFilledGUI();
-                    state = State.Filled;
-                }
-                else
-                {
-                    BuildEmptyGUI();
-
-                    state = State.Empty;
-                }
-            }
-            else if (state == State.Empty)
-            {
-                if (!IsNull())
-                {
-                    guiInternalTitleLayout.Destroy();
-                    BuildFilledGUI();
-                    state = State.Filled;
-                }
-            }
-            else if (state == State.Filled)
-            {
-                if (IsNull())
-                {
-                    guiInternalTitleLayout.Destroy();
-                    guiChildLayout.Destroy();
-                    BuildEmptyGUI();
-
-                    state = State.Empty;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Returns the layout that is used for positioning the elements in the title bar.
-        /// </summary>
-        /// <returns>Horizontal layout for positioning the title bar elements.</returns>
-        public GUILayoutX GetTitleLayout()
-        {
-            return guiTitleLayout;
-        }
-
-        /// <summary>
-        /// Refreshes contents of all list rows and checks if anything was modified.
-        /// </summary>
-        /// <returns>State representing was anything modified between two last calls to <see cref="Refresh"/>.</returns>
-        public virtual InspectableState Refresh()
-        {
-            InspectableState state = InspectableState.NotModified;
-
-            for (int i = 0; i < rows.Count; i++)
-                state |= rows[i].Refresh();
-
-            if (isModified)
-            {
-                state |= InspectableState.Modified;
-                isModified = false;
-            }
-
-            return state;
-        }
-
-        /// <summary>
-        /// Destroys the GUI elements.
-        /// </summary>
-        public void Destroy()
-        {
-            if (guiTitleLayout != null)
-            {
-                guiTitleLayout.Destroy();
-                guiTitleLayout = null;
-            }
-
-            if (guiChildLayout != null)
-            {
-                guiChildLayout.Destroy();
-                guiChildLayout = null;
-            }
-
-            for (int i = 0; i < rows.Count; i++)
-                rows[i].Destroy();
-
-            rows.Clear();
-        }
-
-        /// <summary>
-        /// Creates a new list row GUI.
-        /// </summary>
-        /// <returns>Object containing the list row GUI.</returns>
-        protected abstract GUIListFieldRow CreateRow();
-
-        /// <summary>
-        /// Checks is the list instance not assigned.
-        /// </summary>
-        /// <returns>True if there is not a list instance.</returns>
-        protected abstract bool IsNull();
-
-        /// <summary>
-        /// Returns the number of rows in the list.
-        /// </summary>
-        /// <returns>Number of rows in the list.</returns>
-        protected abstract int GetNumRows();
-
-        /// <summary>
-        /// Gets a value of an element at the specified index in the list.
-        /// </summary>
-        /// <param name="seqIndex">Sequential index of the element whose value to retrieve.</param>
-        /// <returns>Value of the list element at the specified index.</returns>
-        protected internal abstract object GetValue(int seqIndex);
-
-        /// <summary>
-        /// Sets a value of an element at the specified index in the list.
-        /// </summary>
-        /// <param name="seqIndex">Sequential index of the element whose value to set.</param>
-        /// <param name="value">Value to assign to the element. Caller must ensure it is of valid type.</param>
-        protected internal abstract void SetValue(int seqIndex, object value);
-
-        /// <summary>
-        /// Triggered when the user clicks on the expand/collapse toggle in the title bar.
-        /// </summary>
-        /// <param name="expanded">Determines whether the contents were expanded or collapsed.</param>
-        private void OnFoldoutToggled(bool expanded)
-        {
-            isExpanded = expanded;
-
-            if (guiChildLayout != null)
-                guiChildLayout.Active = isExpanded;
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the create button on the title bar. Creates a brand new list with zero
-        /// elements in the place of the current list.
-        /// </summary>
-        protected void OnCreateButtonClicked()
-        {
-            CreateList();
-
-            BuildGUI();
-            isModified = true;
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the resize button on the title bar. Changes the size of the list while
-        /// preserving existing contents.
-        /// </summary>
-        protected void OnResizeButtonClicked()
-        {
-            ResizeList();
-
-            BuildGUI();
-            isModified = true;
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the clear button on the title bar. Deletes the current list object.
-        /// </summary>
-        protected void OnClearButtonClicked()
-        {
-            ClearList();
-
-            BuildGUI();
-            isModified = true;
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the delete button next to a list entry. Deletes an element in the list.
-        /// </summary>
-        /// <param name="index">Sequential index of the element in the list to remove.</param>
-        protected internal void OnDeleteButtonClicked(int index)
-        {
-            DeleteElement(index);
-
-            guiSizeField.Value = GetNumRows();
-            BuildGUI();
-            isModified = true;
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the clone button next to a list entry. Clones the element and adds the clone 
-        /// to the back of the list. 
-        /// </summary>
-        /// <param name="index">Sequential index of the element in the list to clone.</param>
-        protected internal void OnCloneButtonClicked(int index)
-        {
-            CloneElement(index);
-
-            guiSizeField.Value = GetNumRows();
-            BuildGUI();
-            isModified = true;
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the move up button next to a list entry. Moves an element from the current
-        /// list index to the one right before it, if not at zero.
-        /// </summary>
-        /// <param name="index">Sequential index of the element in the list to move.</param>
-        protected internal void OnMoveUpButtonClicked(int index)
-        {
-            MoveUpElement(index);
-
-            BuildGUI();
-            isModified = true;
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the move down button next to a list entry. Moves an element from the current
-        /// list index to the one right after it, if the element isn't already the last element.
-        /// </summary>
-        /// <param name="index">Sequential index of the element in the list to move.</param>
-        protected internal void OnMoveDownButtonClicked(int index)
-        {
-            MoveDownElement(index);
-
-            BuildGUI();
-            isModified = true;
-        }
-
-        /// <summary>
-        /// Creates a brand new list with zero elements in the place of the current list.
-        /// </summary>
-        protected abstract void CreateList();
-
-        /// <summary>
-        /// Changes the size of the list while preserving existing contents.
-        /// </summary>
-        protected abstract void ResizeList();
-
-        /// <summary>
-        /// Deletes the current list object.
-        /// </summary>
-        protected abstract void ClearList();
-
-        /// <summary>
-        /// Deletes an element in the list.
-        /// </summary>
-        /// <param name="index">Sequential index of the element in the list to remove.</param>
-        protected internal abstract void DeleteElement(int index);
-
-        /// <summary>
-        /// Clones the element and adds the clone to the back of the list. 
-        /// </summary>
-        /// <param name="index">Sequential index of the element in the list to clone.</param>
-        protected internal abstract void CloneElement(int index);
-
-        /// <summary>
-        /// Moves an element from the current list index to the one right before it, if not at zero.
-        /// </summary>
-        /// <param name="index">Sequential index of the element in the list to move.</param>
-        protected internal abstract void MoveUpElement(int index);
-
-        /// <summary>
-        /// Moves an element from the current list index to the one right after it, if the element isn't already the last 
-        /// element.
-        /// </summary>
-        /// <param name="index">Sequential index of the element in the list to move.</param>
-        protected internal abstract void MoveDownElement(int index);
-
-        /// <summary>
-        /// Possible states list GUI can be in.
-        /// </summary>
-        private enum State
-        {
-            None,
-            Empty,
-            Filled
-        }
-    }
-
-    /// <summary>
-    /// Creates GUI elements that allow viewing and manipulation of a <see cref="System.Array"/>. When constructing the
-    /// object user can provide a custom type that manages GUI for individual array elements.
-    /// </summary>
-    /// <typeparam name="ElementType">Type of elements stored in the array.</typeparam>
-    /// <typeparam name="RowType">Type of rows that are used to handle GUI for individual array elements.</typeparam>
-    public class GUIArrayField<ElementType, RowType> : GUIListFieldBase where RowType : GUIListFieldRow, new() 
-    {
-        /// <summary>
-        /// Triggered when the reference array has been changed. This does not include changes that only happen to its 
-        /// internal elements.
-        /// </summary>
-        public Action<ElementType[]> OnChanged;
-
-        /// <summary>
-        /// Triggered when an element in the array has been changed.
-        /// </summary>
-        public Action OnValueChanged;
-
-        /// <summary>
-        /// Array object whose contents are displayed.
-        /// </summary>
-        public ElementType[] Array { get { return array; } }
-        protected ElementType[] array;
-
-        /// <summary>
-        /// Constructs a new GUI array field.
-        /// </summary>
-        /// <param name="title">Label to display on the array GUI title.</param>
-        /// <param name="array">Object containing the array data. Can be null.</param>
-        /// <param name="layout">Layout to which to append the array GUI elements to.</param>
-        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
-        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
-        ///                     depths divisible by two will use an alternate style.</param>
-        protected GUIArrayField(LocString title, ElementType[] array, GUILayout layout, int depth = 0)
-            :base(title, layout, depth)
-        {
-            this.array = array;
-        }
-
-        /// <summary>
-        /// Creates a array GUI field containing GUI elements for displaying an array.
-        /// </summary>
-        /// <param name="title">Label to display on the array GUI title.</param>
-        /// <param name="array">Object containing the array data. Can be null.</param>
-        /// <param name="layout">Layout to which to append the array GUI elements to.</param>
-        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
-        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
-        ///                     depths divisible by two will use an alternate style.</param>
-        /// <returns>New instance of an array GUI field.</returns>
-        public static GUIArrayField<ElementType, RowType> Create(LocString title, ElementType[] array, GUILayout layout, 
-            int depth = 0)
-        {
-            GUIArrayField<ElementType, RowType> guiArray = new GUIArrayField<ElementType, RowType>(title, array, layout,
-                depth);
-
-            guiArray.BuildGUI();
-            return guiArray;
-        }
-
-        /// <inheritdoc/>
-        protected override GUIListFieldRow CreateRow()
-        {
-            return new RowType();
-        }
-
-        /// <inheritdoc/>
-        protected override bool IsNull()
-        {
-            return array == null;
-        }
-
-        /// <inheritdoc/>
-        protected override int GetNumRows()
-        {
-            if (array != null)
-                return array.GetLength(0);
-
-            return 0;
-        }
-
-        /// <inheritdoc/>
-        protected internal override object GetValue(int seqIndex)
-        {
-            return array.GetValue(seqIndex);
-        }
-
-        /// <inheritdoc/>
-        protected internal override void SetValue(int seqIndex, object value)
-        {
-            array.SetValue(value, seqIndex);
-
-            if (OnValueChanged != null)
-                OnValueChanged();
-        }
-
-        /// <inheritdoc/>
-        protected override void CreateList()
-        {
-            array = new ElementType[0];
-
-            if (OnChanged != null)
-                OnChanged(array);
-        }
-
-        /// <inheritdoc/>
-        protected override void ResizeList()
-        {
-            int size = guiSizeField.Value;
-
-            ElementType[] newArray = new ElementType[size];
-
-            int maxSize = MathEx.Min(size, array.GetLength(0));
-
-            for (int i = 0; i < maxSize; i++)
-                newArray.SetValue(array.GetValue(i), i);
-
-            array = newArray;
-
-            if(OnChanged != null)
-                OnChanged(array);
-        }
-
-        /// <inheritdoc/>
-        protected override void ClearList()
-        {
-            array = null;
-
-            if (OnChanged != null)
-                OnChanged(array);
-        }
-
-        /// <inheritdoc/>
-        protected internal override void DeleteElement(int index)
-        {
-            int size = MathEx.Max(0, array.GetLength(0) - 1);
-            ElementType[] newArray = new ElementType[size];
-
-            int destIdx = 0;
-            for (int i = 0; i < array.GetLength(0); i++)
-            {
-                if (i == index)
-                    continue;
-
-                newArray.SetValue(array.GetValue(i), destIdx);
-                destIdx++;
-            }
-
-            array = newArray;
-
-            if (OnChanged != null)
-                OnChanged(array);
-        }
-
-        /// <inheritdoc/>
-        protected internal override void CloneElement(int index)
-        {
-            int size = array.GetLength(0) + 1;
-            ElementType[] newArray = new ElementType[size];
-
-            object clonedEntry = null;
-            for (int i = 0; i < array.GetLength(0); i++)
-            {
-                object value = array.GetValue(i);
-                newArray.SetValue(value, i);
-
-                if (i == index)
-                {
-                    if (value == null)
-                        clonedEntry = null;
-                    else
-                        clonedEntry = SerializableUtility.Clone(value);
-                }
-            }
-
-            newArray.SetValue(clonedEntry, size - 1);
-
-            array = newArray;
-
-            if (OnChanged != null)
-                OnChanged(array);
-        }
-
-        /// <inheritdoc/>
-        protected internal override void MoveUpElement(int index)
-        {
-            if ((index - 1) >= 0)
-            {
-                object previousEntry = array.GetValue(index - 1);
-
-                array.SetValue(array.GetValue(index), index - 1);
-                array.SetValue(previousEntry, index);
-
-                if (OnValueChanged != null)
-                    OnValueChanged();
-            }
-        }
-
-        /// <inheritdoc/>
-        protected internal override void MoveDownElement(int index)
-        {
-            if ((index + 1) < array.GetLength(0))
-            {
-                object nextEntry = array.GetValue(index + 1);
-
-                array.SetValue(array.GetValue(index), index + 1);
-                array.SetValue(nextEntry, index);
-
-                if (OnValueChanged != null)
-                    OnValueChanged();
-            }
-        }
-    }
-
-    /// <summary>
-    /// Creates GUI elements that allow viewing and manipulation of a <see cref="List{T}"/>. When constructing the
-    /// object user can provide a custom type that manages GUI for individual list elements.
-    /// </summary>
-    /// <typeparam name="ElementType">Type of elements stored in the list.</typeparam>
-    /// <typeparam name="RowType">Type of rows that are used to handle GUI for individual list elements.</typeparam>
-    public class GUIListField<ElementType, RowType> : GUIListFieldBase where RowType : GUIListFieldRow, new()
-    {
-        /// <summary>
-        /// Triggered when the reference list has been changed. This does not include changes that only happen to its 
-        /// internal elements.
-        /// </summary>
-        public Action<List<ElementType>> OnChanged;
-
-        /// <summary>
-        /// Triggered when an element in the list has been changed.
-        /// </summary>
-        public Action OnValueChanged;
-
-        /// <summary>
-        /// List object whose contents are displayed.
-        /// </summary>
-        public List<ElementType> List { get { return list; } }
-        protected List<ElementType> list;
-
-        /// <summary>
-        /// Constructs a new GUI list field.
-        /// </summary>
-        /// <param name="title">Label to display on the list GUI title.</param>
-        /// <param name="list">Object containing the list data. Can be null.</param>
-        /// <param name="layout">Layout to which to append the list GUI elements to.</param>
-        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
-        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
-        ///                     depths divisible by two will use an alternate style.</param>
-        protected GUIListField(LocString title, List<ElementType> list, GUILayout layout, int depth = 0)
-            : base(title, layout, depth)
-        {
-            this.list = list;
-        }
-
-        /// <summary>
-        /// Creates a list GUI field containing GUI elements for displaying a list.
-        /// </summary>
-        /// <param name="title">Label to display on the list GUI title.</param>
-        /// <param name="list">Object containing the list data. Can be null.</param>
-        /// <param name="layout">Layout to which to append the list GUI elements to.</param>
-        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
-        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
-        ///                     depths divisible by two will use an alternate style.</param>
-        /// <returns>New instance of a list GUI field.</returns>
-        public static GUIListField<ElementType, RowType> Create(LocString title, List<ElementType> list, GUILayout layout, 
-            int depth = 0)
-        {
-            GUIListField<ElementType, RowType> guiList = new GUIListField<ElementType, RowType>(title, list, layout, depth);
-            guiList.BuildGUI();
-
-            return guiList;
-        }
-
-        /// <inheritdoc/>
-        protected override GUIListFieldRow CreateRow()
-        {
-            return new RowType();
-        }
-
-        /// <inheritdoc/>
-        protected override bool IsNull()
-        {
-            return list == null;
-        }
-
-        /// <inheritdoc/>
-        protected override int GetNumRows()
-        {
-            if (list != null)
-                return list.Count;
-
-            return 0;
-        }
-
-        /// <inheritdoc/>
-        protected internal override object GetValue(int seqIndex)
-        {
-            return list[seqIndex];
-        }
-
-        /// <inheritdoc/>
-        protected internal override void SetValue(int seqIndex, object value)
-        {
-            list[seqIndex] = (ElementType)value;
-
-            if (OnValueChanged != null)
-                OnValueChanged();
-        }
-
-        /// <inheritdoc/>
-        protected override void CreateList()
-        {
-            list = new List<ElementType>();
-
-            if (OnChanged != null)
-                OnChanged(list);
-        }
-
-        /// <inheritdoc/>
-        protected override void ResizeList()
-        {
-            int size = guiSizeField.Value;
-            if(size == list.Count)
-                return;
-
-            if (size < list.Count)
-                list.RemoveRange(size, list.Count - size);
-            else
-            {
-                ElementType[] extraElements = new ElementType[size - list.Count];
-                list.AddRange(extraElements);
-            }
-
-            if (OnValueChanged != null)
-                OnValueChanged();
-        }
-
-        /// <inheritdoc/>
-        protected override void ClearList()
-        {
-            list = null;
-
-            if (OnChanged != null)
-                OnChanged(list);
-        }
-
-        /// <inheritdoc/>
-        protected internal override void DeleteElement(int index)
-        {
-            list.RemoveAt(index);
-
-            if (OnValueChanged != null)
-                OnValueChanged();
-        }
-
-        /// <inheritdoc/>
-        protected internal override void CloneElement(int index)
-        {
-            object clonedEntry = null;
-            if (list[index] != null)
-                clonedEntry = SerializableUtility.Clone(list[index]);
-
-            list.Add((ElementType)clonedEntry);
-
-            if (OnValueChanged != null)
-                OnValueChanged();
-        }
-
-        /// <inheritdoc/>
-        protected internal override void MoveUpElement(int index)
-        {
-            if ((index - 1) >= 0)
-            {
-                ElementType previousEntry = list[index - 1];
-
-                list[index - 1] = list[index];
-                list[index] = previousEntry;
-
-                if (OnValueChanged != null)
-                    OnValueChanged();
-            }
-        }
-
-        /// <inheritdoc/>
-        protected internal override void MoveDownElement(int index)
-        {
-            if ((index + 1) < list.Count)
-            {
-                ElementType nextEntry = list[index + 1];
-
-                list[index + 1] = list[index];
-                list[index] = nextEntry;
-
-                if (OnValueChanged != null)
-                    OnValueChanged();
-            }
-        }
-    }
-
-    /// <summary>
-    /// Contains GUI elements for a single entry in a list.
-    /// </summary>
-    public abstract class GUIListFieldRow
-    {
-        private GUILayoutX rowLayout;
-        private GUILayoutY contentLayout;
-        private GUILayoutX titleLayout;
-        private bool localTitleLayout;
-        private GUIListFieldBase parent;
-        private int seqIndex;
-        private int depth;
-        private InspectableState modifiedState;
-
-        /// <summary>
-        /// Returns the sequential index of the list entry that this row displays.
-        /// </summary>
-        protected int SeqIndex { get { return seqIndex; } }
-
-        /// <summary>
-        /// Returns the depth at which the row is rendered.
-        /// </summary>
-        protected int Depth { get { return depth; } }
-
-        /// <summary>
-        /// Constructs a new list row object.
-        /// </summary>
-        protected GUIListFieldRow()
-        {
-
-        }
-
-        /// <summary>
-        /// Initializes the row and creates row GUI elements.
-        /// </summary>
-        /// <param name="parent">Parent array GUI object that the entry is contained in.</param>
-        /// <param name="parentLayout">Parent layout that row GUI elements will be added to.</param>
-        /// <param name="seqIndex">Sequential index of the list entry.</param>
-        /// <param name="depth">Determines the depth at which the element is rendered.</param>
-        internal void Initialize(GUIListFieldBase parent, GUILayout parentLayout, int seqIndex, int depth)
-        {
-            this.parent = parent;
-            this.seqIndex = seqIndex;
-            this.depth = depth;
-
-            rowLayout = parentLayout.AddLayoutX();
-            contentLayout = rowLayout.AddLayoutY();
-
-            BuildGUI();
-        }
-
-        /// <summary>
-        /// Changes the index of the list element this row represents.
-        /// </summary>
-        /// <param name="seqIndex">Sequential index of the list entry.</param>
-        internal void SetIndex(int seqIndex)
-        {
-            this.seqIndex = seqIndex;
-        }
-
-        /// <summary>
-        /// (Re)creates all row GUI elements.
-        /// </summary>
-        internal protected void BuildGUI()
-        {
-            contentLayout.Clear();
-
-            GUILayoutX externalTitleLayout = CreateGUI(contentLayout);
-            if (localTitleLayout || (titleLayout != null && titleLayout == externalTitleLayout))
-                return;
-
-            if (externalTitleLayout != null)
-            {
-                localTitleLayout = false;
-                titleLayout = externalTitleLayout;
-            }
-            else
-            {
-                GUILayoutY buttonCenter = rowLayout.AddLayoutY();
-                buttonCenter.AddFlexibleSpace();
-                titleLayout = buttonCenter.AddLayoutX();
-                buttonCenter.AddFlexibleSpace();
-
-                localTitleLayout = true;
-            }
-            
-            GUIContent cloneIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Clone));
-            GUIContent deleteIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Delete));
-            GUIContent moveUp = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.MoveUp));
-            GUIContent moveDown = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.MoveDown));
-
-            GUIButton cloneBtn = new GUIButton(cloneIcon, GUIOption.FixedWidth(30));
-            GUIButton deleteBtn = new GUIButton(deleteIcon, GUIOption.FixedWidth(30));
-            GUIButton moveUpBtn = new GUIButton(moveUp, GUIOption.FixedWidth(30));
-            GUIButton moveDownBtn = new GUIButton(moveDown, GUIOption.FixedWidth(30));
-
-            cloneBtn.OnClick += () => parent.OnCloneButtonClicked(seqIndex);
-            deleteBtn.OnClick += () => parent.OnDeleteButtonClicked(seqIndex);
-            moveUpBtn.OnClick += () => parent.OnMoveUpButtonClicked(seqIndex);
-            moveDownBtn.OnClick += () => parent.OnMoveDownButtonClicked(seqIndex);
-
-            titleLayout.AddElement(cloneBtn);
-            titleLayout.AddElement(deleteBtn);
-            titleLayout.AddElement(moveUpBtn);
-            titleLayout.AddElement(moveDownBtn);
-        }
-
-        /// <summary>
-        /// Creates GUI elements specific to type in the array row.
-        /// </summary>
-        /// <param name="layout">Layout to insert the row GUI elements to.</param>
-        /// <returns>An optional title bar layout that the standard array buttons will be appended to.</returns>
-        protected abstract GUILayoutX CreateGUI(GUILayoutY layout);
-        
-        /// <summary>
-        /// Refreshes the GUI for the list row and checks if anything was modified.
-        /// </summary>
-        /// <returns>State representing was anything modified between two last calls to <see cref="Refresh"/>.</returns>
-        internal protected virtual InspectableState Refresh()
-        {
-            InspectableState oldState = modifiedState;
-            if (modifiedState.HasFlag(InspectableState.Modified))
-                modifiedState = InspectableState.NotModified;
-
-            return oldState;
-        }
-
-        /// <summary>
-        /// Marks the contents of the row as modified.
-        /// </summary>
-        protected void MarkAsModified()
-        {
-            modifiedState |= InspectableState.ModifyInProgress;
-        }
-
-        /// <summary>
-        /// Confirms any queued modifications, signaling parent elements.
-        /// </summary>
-        protected void ConfirmModify()
-        {
-            if (modifiedState.HasFlag(InspectableState.ModifyInProgress))
-                modifiedState |= InspectableState.Modified;
-        }
-
-        /// <summary>
-        /// Gets the value contained in this list row.
-        /// </summary>
-        /// <typeparam name="T">Type of the value. Must match the list's element type.</typeparam>
-        /// <returns>Value in this list row.</returns>
-        protected T GetValue<T>()
-        {
-            return (T)parent.GetValue(seqIndex);
-        }
-
-        /// <summary>
-        /// Sets the value contained in this list row.
-        /// </summary>
-        /// <typeparam name="T">Type of the value. Must match the list's element type.</typeparam>
-        /// <param name="value">Value to set.</param>
-        protected void SetValue<T>(T value)
-        {
-            parent.SetValue(seqIndex, value);
-        }
-
-        /// <summary>
-        /// Destroys all row GUI elements.
-        /// </summary>
-        public void Destroy()
-        {
-            if (rowLayout != null)
-            {
-                rowLayout.Destroy();
-                rowLayout = null;
-            }
-
-            contentLayout = null;
-            titleLayout = null;
-            localTitleLayout = false;
-        }
-    }
-}
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Base class for objects that display GUI for a modifyable list of elements. Elements can be added, removed and moved.
+    /// </summary>
+    public abstract class GUIListFieldBase
+    {
+        private const int IndentAmount = 5;
+
+        protected List<GUIListFieldRow> rows = new List<GUIListFieldRow>();
+        protected GUILayoutY guiLayout;
+        protected GUIIntField guiSizeField;
+        protected GUILayoutX guiChildLayout;
+        protected GUILayoutX guiTitleLayout;
+        protected GUILayoutX guiInternalTitleLayout;
+        protected GUILayoutY guiContentLayout;
+
+        protected bool isExpanded;
+        protected int depth;
+        protected LocString title;
+
+        private State state;
+        private bool isModified;
+
+        /// <summary>
+        /// Constructs a new GUI list.
+        /// </summary>
+        /// <param name="title">Label to display on the list GUI title.</param>
+        /// <param name="layout">Layout to which to append the array GUI elements to.</param>
+        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
+        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
+        ///                     depths divisible by two will use an alternate style.</param>
+        protected GUIListFieldBase(LocString title, GUILayout layout, int depth)
+        {
+            this.title = title;
+            this.depth = depth;
+            guiLayout = layout.AddLayoutY();
+            guiTitleLayout = guiLayout.AddLayoutX();
+        }
+
+        /// <summary>
+        /// (Re)builds the list GUI elements. Must be called at least once in order for the contents to be populated.
+        /// </summary>
+        public void BuildGUI()
+        {
+            UpdateHeaderGUI();
+
+            if (!IsNull())
+            {
+                // Hidden dependency: Initialize must be called after all elements are 
+                // in the dictionary so we do it in two steps
+                int numRows = GetNumRows();
+                int oldNumRows = rows.Count;
+
+                for (int i = oldNumRows; i < numRows; i++)
+                {
+                    GUIListFieldRow newRow = CreateRow();
+                    rows.Add(newRow);
+                }
+
+                for (int i = oldNumRows - 1; i >= numRows; i--)
+                {
+                    rows[i].Destroy();
+                    rows.RemoveAt(i);
+                }
+
+                for (int i = oldNumRows; i < numRows; i++)
+                    rows[i].Initialize(this, guiContentLayout, i, depth + 1);
+
+                for (int i = 0; i < rows.Count; i++)
+                    rows[i].SetIndex(i);
+            }
+            else
+            {
+                foreach (var row in rows)
+                    row.Destroy();
+
+                rows.Clear();
+            }
+        }
+
+        /// <summary>
+        /// Rebuilds the GUI list header if needed.
+        /// </summary>
+        protected void UpdateHeaderGUI()
+        {
+            Action BuildEmptyGUI = () =>
+            {
+                guiInternalTitleLayout = guiTitleLayout.InsertLayoutX(0);
+
+                guiInternalTitleLayout.AddElement(new GUILabel(title));
+                guiInternalTitleLayout.AddElement(new GUILabel("Empty", GUIOption.FixedWidth(100)));
+
+                GUIContent createIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Create), 
+                    new LocEdString("Create"));
+                GUIButton createBtn = new GUIButton(createIcon, GUIOption.FixedWidth(30));
+                createBtn.OnClick += OnCreateButtonClicked;
+                guiInternalTitleLayout.AddElement(createBtn);
+            };
+
+            Action BuildFilledGUI = () =>
+            {
+                guiInternalTitleLayout = guiTitleLayout.InsertLayoutX(0);
+
+                GUIToggle guiFoldout = new GUIToggle(title, EditorStyles.Foldout);
+                guiFoldout.Value = isExpanded;
+                guiFoldout.OnToggled += OnFoldoutToggled;
+                guiSizeField = new GUIIntField("", GUIOption.FixedWidth(50));
+                guiSizeField.SetRange(0, int.MaxValue);
+
+                GUIContent resizeIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Resize), 
+                    new LocEdString("Resize"));
+                GUIButton guiResizeBtn = new GUIButton(resizeIcon, GUIOption.FixedWidth(30));
+                guiResizeBtn.OnClick += OnResizeButtonClicked;
+
+                GUIContent clearIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Clear), 
+                    new LocEdString("Clear"));
+                GUIButton guiClearBtn = new GUIButton(clearIcon, GUIOption.FixedWidth(30));
+                guiClearBtn.OnClick += OnClearButtonClicked;
+
+                guiInternalTitleLayout.AddElement(guiFoldout);
+                guiInternalTitleLayout.AddElement(guiSizeField);
+                guiInternalTitleLayout.AddElement(guiResizeBtn);
+                guiInternalTitleLayout.AddElement(guiClearBtn);
+
+                guiSizeField.Value = GetNumRows();
+
+                guiChildLayout = guiLayout.AddLayoutX();
+                guiChildLayout.AddSpace(IndentAmount);
+                guiChildLayout.Active = isExpanded;
+
+                GUIPanel guiContentPanel = guiChildLayout.AddPanel();
+                GUILayoutX guiIndentLayoutX = guiContentPanel.AddLayoutX();
+                guiIndentLayoutX.AddSpace(IndentAmount);
+                GUILayoutY guiIndentLayoutY = guiIndentLayoutX.AddLayoutY();
+                guiIndentLayoutY.AddSpace(IndentAmount);
+                guiContentLayout = guiIndentLayoutY.AddLayoutY();
+                guiIndentLayoutY.AddSpace(IndentAmount);
+                guiIndentLayoutX.AddSpace(IndentAmount);
+                guiChildLayout.AddSpace(IndentAmount);
+
+                short backgroundDepth = (short)(Inspector.START_BACKGROUND_DEPTH - depth - 1);
+                string bgPanelStyle = depth % 2 == 0
+                    ? EditorStyles.InspectorContentBgAlternate
+                    : EditorStyles.InspectorContentBg;
+
+                GUIPanel backgroundPanel = guiContentPanel.AddPanel(backgroundDepth);
+                GUITexture inspectorContentBg = new GUITexture(null, bgPanelStyle);
+                backgroundPanel.AddElement(inspectorContentBg);
+            };
+
+            if (state == State.None)
+            {
+                if (!IsNull())
+                {
+                    BuildFilledGUI();
+                    state = State.Filled;
+                }
+                else
+                {
+                    BuildEmptyGUI();
+
+                    state = State.Empty;
+                }
+            }
+            else if (state == State.Empty)
+            {
+                if (!IsNull())
+                {
+                    guiInternalTitleLayout.Destroy();
+                    BuildFilledGUI();
+                    state = State.Filled;
+                }
+            }
+            else if (state == State.Filled)
+            {
+                if (IsNull())
+                {
+                    guiInternalTitleLayout.Destroy();
+                    guiChildLayout.Destroy();
+                    BuildEmptyGUI();
+
+                    state = State.Empty;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Returns the layout that is used for positioning the elements in the title bar.
+        /// </summary>
+        /// <returns>Horizontal layout for positioning the title bar elements.</returns>
+        public GUILayoutX GetTitleLayout()
+        {
+            return guiTitleLayout;
+        }
+
+        /// <summary>
+        /// Refreshes contents of all list rows and checks if anything was modified.
+        /// </summary>
+        /// <returns>State representing was anything modified between two last calls to <see cref="Refresh"/>.</returns>
+        public virtual InspectableState Refresh()
+        {
+            InspectableState state = InspectableState.NotModified;
+
+            for (int i = 0; i < rows.Count; i++)
+                state |= rows[i].Refresh();
+
+            if (isModified)
+            {
+                state |= InspectableState.Modified;
+                isModified = false;
+            }
+
+            return state;
+        }
+
+        /// <summary>
+        /// Destroys the GUI elements.
+        /// </summary>
+        public void Destroy()
+        {
+            if (guiTitleLayout != null)
+            {
+                guiTitleLayout.Destroy();
+                guiTitleLayout = null;
+            }
+
+            if (guiChildLayout != null)
+            {
+                guiChildLayout.Destroy();
+                guiChildLayout = null;
+            }
+
+            for (int i = 0; i < rows.Count; i++)
+                rows[i].Destroy();
+
+            rows.Clear();
+        }
+
+        /// <summary>
+        /// Creates a new list row GUI.
+        /// </summary>
+        /// <returns>Object containing the list row GUI.</returns>
+        protected abstract GUIListFieldRow CreateRow();
+
+        /// <summary>
+        /// Checks is the list instance not assigned.
+        /// </summary>
+        /// <returns>True if there is not a list instance.</returns>
+        protected abstract bool IsNull();
+
+        /// <summary>
+        /// Returns the number of rows in the list.
+        /// </summary>
+        /// <returns>Number of rows in the list.</returns>
+        protected abstract int GetNumRows();
+
+        /// <summary>
+        /// Gets a value of an element at the specified index in the list.
+        /// </summary>
+        /// <param name="seqIndex">Sequential index of the element whose value to retrieve.</param>
+        /// <returns>Value of the list element at the specified index.</returns>
+        protected internal abstract object GetValue(int seqIndex);
+
+        /// <summary>
+        /// Sets a value of an element at the specified index in the list.
+        /// </summary>
+        /// <param name="seqIndex">Sequential index of the element whose value to set.</param>
+        /// <param name="value">Value to assign to the element. Caller must ensure it is of valid type.</param>
+        protected internal abstract void SetValue(int seqIndex, object value);
+
+        /// <summary>
+        /// Triggered when the user clicks on the expand/collapse toggle in the title bar.
+        /// </summary>
+        /// <param name="expanded">Determines whether the contents were expanded or collapsed.</param>
+        private void OnFoldoutToggled(bool expanded)
+        {
+            isExpanded = expanded;
+
+            if (guiChildLayout != null)
+                guiChildLayout.Active = isExpanded;
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the create button on the title bar. Creates a brand new list with zero
+        /// elements in the place of the current list.
+        /// </summary>
+        protected void OnCreateButtonClicked()
+        {
+            CreateList();
+
+            BuildGUI();
+            isModified = true;
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the resize button on the title bar. Changes the size of the list while
+        /// preserving existing contents.
+        /// </summary>
+        protected void OnResizeButtonClicked()
+        {
+            ResizeList();
+
+            BuildGUI();
+            isModified = true;
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the clear button on the title bar. Deletes the current list object.
+        /// </summary>
+        protected void OnClearButtonClicked()
+        {
+            ClearList();
+
+            BuildGUI();
+            isModified = true;
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the delete button next to a list entry. Deletes an element in the list.
+        /// </summary>
+        /// <param name="index">Sequential index of the element in the list to remove.</param>
+        protected internal void OnDeleteButtonClicked(int index)
+        {
+            DeleteElement(index);
+
+            guiSizeField.Value = GetNumRows();
+            BuildGUI();
+            isModified = true;
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the clone button next to a list entry. Clones the element and adds the clone 
+        /// to the back of the list. 
+        /// </summary>
+        /// <param name="index">Sequential index of the element in the list to clone.</param>
+        protected internal void OnCloneButtonClicked(int index)
+        {
+            CloneElement(index);
+
+            guiSizeField.Value = GetNumRows();
+            BuildGUI();
+            isModified = true;
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the move up button next to a list entry. Moves an element from the current
+        /// list index to the one right before it, if not at zero.
+        /// </summary>
+        /// <param name="index">Sequential index of the element in the list to move.</param>
+        protected internal void OnMoveUpButtonClicked(int index)
+        {
+            MoveUpElement(index);
+
+            BuildGUI();
+            isModified = true;
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the move down button next to a list entry. Moves an element from the current
+        /// list index to the one right after it, if the element isn't already the last element.
+        /// </summary>
+        /// <param name="index">Sequential index of the element in the list to move.</param>
+        protected internal void OnMoveDownButtonClicked(int index)
+        {
+            MoveDownElement(index);
+
+            BuildGUI();
+            isModified = true;
+        }
+
+        /// <summary>
+        /// Creates a brand new list with zero elements in the place of the current list.
+        /// </summary>
+        protected abstract void CreateList();
+
+        /// <summary>
+        /// Changes the size of the list while preserving existing contents.
+        /// </summary>
+        protected abstract void ResizeList();
+
+        /// <summary>
+        /// Deletes the current list object.
+        /// </summary>
+        protected abstract void ClearList();
+
+        /// <summary>
+        /// Deletes an element in the list.
+        /// </summary>
+        /// <param name="index">Sequential index of the element in the list to remove.</param>
+        protected internal abstract void DeleteElement(int index);
+
+        /// <summary>
+        /// Clones the element and adds the clone to the back of the list. 
+        /// </summary>
+        /// <param name="index">Sequential index of the element in the list to clone.</param>
+        protected internal abstract void CloneElement(int index);
+
+        /// <summary>
+        /// Moves an element from the current list index to the one right before it, if not at zero.
+        /// </summary>
+        /// <param name="index">Sequential index of the element in the list to move.</param>
+        protected internal abstract void MoveUpElement(int index);
+
+        /// <summary>
+        /// Moves an element from the current list index to the one right after it, if the element isn't already the last 
+        /// element.
+        /// </summary>
+        /// <param name="index">Sequential index of the element in the list to move.</param>
+        protected internal abstract void MoveDownElement(int index);
+
+        /// <summary>
+        /// Possible states list GUI can be in.
+        /// </summary>
+        private enum State
+        {
+            None,
+            Empty,
+            Filled
+        }
+    }
+
+    /// <summary>
+    /// Creates GUI elements that allow viewing and manipulation of a <see cref="System.Array"/>. When constructing the
+    /// object user can provide a custom type that manages GUI for individual array elements.
+    /// </summary>
+    /// <typeparam name="ElementType">Type of elements stored in the array.</typeparam>
+    /// <typeparam name="RowType">Type of rows that are used to handle GUI for individual array elements.</typeparam>
+    public class GUIArrayField<ElementType, RowType> : GUIListFieldBase where RowType : GUIListFieldRow, new() 
+    {
+        /// <summary>
+        /// Triggered when the reference array has been changed. This does not include changes that only happen to its 
+        /// internal elements.
+        /// </summary>
+        public Action<ElementType[]> OnChanged;
+
+        /// <summary>
+        /// Triggered when an element in the array has been changed.
+        /// </summary>
+        public Action OnValueChanged;
+
+        /// <summary>
+        /// Array object whose contents are displayed.
+        /// </summary>
+        public ElementType[] Array { get { return array; } }
+        protected ElementType[] array;
+
+        /// <summary>
+        /// Constructs a new GUI array field.
+        /// </summary>
+        /// <param name="title">Label to display on the array GUI title.</param>
+        /// <param name="array">Object containing the array data. Can be null.</param>
+        /// <param name="layout">Layout to which to append the array GUI elements to.</param>
+        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
+        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
+        ///                     depths divisible by two will use an alternate style.</param>
+        protected GUIArrayField(LocString title, ElementType[] array, GUILayout layout, int depth = 0)
+            :base(title, layout, depth)
+        {
+            this.array = array;
+        }
+
+        /// <summary>
+        /// Creates a array GUI field containing GUI elements for displaying an array.
+        /// </summary>
+        /// <param name="title">Label to display on the array GUI title.</param>
+        /// <param name="array">Object containing the array data. Can be null.</param>
+        /// <param name="layout">Layout to which to append the array GUI elements to.</param>
+        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
+        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
+        ///                     depths divisible by two will use an alternate style.</param>
+        /// <returns>New instance of an array GUI field.</returns>
+        public static GUIArrayField<ElementType, RowType> Create(LocString title, ElementType[] array, GUILayout layout, 
+            int depth = 0)
+        {
+            GUIArrayField<ElementType, RowType> guiArray = new GUIArrayField<ElementType, RowType>(title, array, layout,
+                depth);
+
+            guiArray.BuildGUI();
+            return guiArray;
+        }
+
+        /// <inheritdoc/>
+        protected override GUIListFieldRow CreateRow()
+        {
+            return new RowType();
+        }
+
+        /// <inheritdoc/>
+        protected override bool IsNull()
+        {
+            return array == null;
+        }
+
+        /// <inheritdoc/>
+        protected override int GetNumRows()
+        {
+            if (array != null)
+                return array.GetLength(0);
+
+            return 0;
+        }
+
+        /// <inheritdoc/>
+        protected internal override object GetValue(int seqIndex)
+        {
+            return array.GetValue(seqIndex);
+        }
+
+        /// <inheritdoc/>
+        protected internal override void SetValue(int seqIndex, object value)
+        {
+            array.SetValue(value, seqIndex);
+
+            if (OnValueChanged != null)
+                OnValueChanged();
+        }
+
+        /// <inheritdoc/>
+        protected override void CreateList()
+        {
+            array = new ElementType[0];
+
+            if (OnChanged != null)
+                OnChanged(array);
+        }
+
+        /// <inheritdoc/>
+        protected override void ResizeList()
+        {
+            int size = guiSizeField.Value;
+
+            ElementType[] newArray = new ElementType[size];
+
+            int maxSize = MathEx.Min(size, array.GetLength(0));
+
+            for (int i = 0; i < maxSize; i++)
+                newArray.SetValue(array.GetValue(i), i);
+
+            array = newArray;
+
+            if(OnChanged != null)
+                OnChanged(array);
+        }
+
+        /// <inheritdoc/>
+        protected override void ClearList()
+        {
+            array = null;
+
+            if (OnChanged != null)
+                OnChanged(array);
+        }
+
+        /// <inheritdoc/>
+        protected internal override void DeleteElement(int index)
+        {
+            int size = MathEx.Max(0, array.GetLength(0) - 1);
+            ElementType[] newArray = new ElementType[size];
+
+            int destIdx = 0;
+            for (int i = 0; i < array.GetLength(0); i++)
+            {
+                if (i == index)
+                    continue;
+
+                newArray.SetValue(array.GetValue(i), destIdx);
+                destIdx++;
+            }
+
+            array = newArray;
+
+            if (OnChanged != null)
+                OnChanged(array);
+        }
+
+        /// <inheritdoc/>
+        protected internal override void CloneElement(int index)
+        {
+            int size = array.GetLength(0) + 1;
+            ElementType[] newArray = new ElementType[size];
+
+            object clonedEntry = null;
+            for (int i = 0; i < array.GetLength(0); i++)
+            {
+                object value = array.GetValue(i);
+                newArray.SetValue(value, i);
+
+                if (i == index)
+                {
+                    if (value == null)
+                        clonedEntry = null;
+                    else
+                        clonedEntry = SerializableUtility.Clone(value);
+                }
+            }
+
+            newArray.SetValue(clonedEntry, size - 1);
+
+            array = newArray;
+
+            if (OnChanged != null)
+                OnChanged(array);
+        }
+
+        /// <inheritdoc/>
+        protected internal override void MoveUpElement(int index)
+        {
+            if ((index - 1) >= 0)
+            {
+                object previousEntry = array.GetValue(index - 1);
+
+                array.SetValue(array.GetValue(index), index - 1);
+                array.SetValue(previousEntry, index);
+
+                if (OnValueChanged != null)
+                    OnValueChanged();
+            }
+        }
+
+        /// <inheritdoc/>
+        protected internal override void MoveDownElement(int index)
+        {
+            if ((index + 1) < array.GetLength(0))
+            {
+                object nextEntry = array.GetValue(index + 1);
+
+                array.SetValue(array.GetValue(index), index + 1);
+                array.SetValue(nextEntry, index);
+
+                if (OnValueChanged != null)
+                    OnValueChanged();
+            }
+        }
+    }
+
+    /// <summary>
+    /// Creates GUI elements that allow viewing and manipulation of a <see cref="List{T}"/>. When constructing the
+    /// object user can provide a custom type that manages GUI for individual list elements.
+    /// </summary>
+    /// <typeparam name="ElementType">Type of elements stored in the list.</typeparam>
+    /// <typeparam name="RowType">Type of rows that are used to handle GUI for individual list elements.</typeparam>
+    public class GUIListField<ElementType, RowType> : GUIListFieldBase where RowType : GUIListFieldRow, new()
+    {
+        /// <summary>
+        /// Triggered when the reference list has been changed. This does not include changes that only happen to its 
+        /// internal elements.
+        /// </summary>
+        public Action<List<ElementType>> OnChanged;
+
+        /// <summary>
+        /// Triggered when an element in the list has been changed.
+        /// </summary>
+        public Action OnValueChanged;
+
+        /// <summary>
+        /// List object whose contents are displayed.
+        /// </summary>
+        public List<ElementType> List { get { return list; } }
+        protected List<ElementType> list;
+
+        /// <summary>
+        /// Constructs a new GUI list field.
+        /// </summary>
+        /// <param name="title">Label to display on the list GUI title.</param>
+        /// <param name="list">Object containing the list data. Can be null.</param>
+        /// <param name="layout">Layout to which to append the list GUI elements to.</param>
+        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
+        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
+        ///                     depths divisible by two will use an alternate style.</param>
+        protected GUIListField(LocString title, List<ElementType> list, GUILayout layout, int depth = 0)
+            : base(title, layout, depth)
+        {
+            this.list = list;
+        }
+
+        /// <summary>
+        /// Creates a list GUI field containing GUI elements for displaying a list.
+        /// </summary>
+        /// <param name="title">Label to display on the list GUI title.</param>
+        /// <param name="list">Object containing the list data. Can be null.</param>
+        /// <param name="layout">Layout to which to append the list GUI elements to.</param>
+        /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
+        ///                     nested containers whose backgrounds are overlaping. Also determines background style,
+        ///                     depths divisible by two will use an alternate style.</param>
+        /// <returns>New instance of a list GUI field.</returns>
+        public static GUIListField<ElementType, RowType> Create(LocString title, List<ElementType> list, GUILayout layout, 
+            int depth = 0)
+        {
+            GUIListField<ElementType, RowType> guiList = new GUIListField<ElementType, RowType>(title, list, layout, depth);
+            guiList.BuildGUI();
+
+            return guiList;
+        }
+
+        /// <inheritdoc/>
+        protected override GUIListFieldRow CreateRow()
+        {
+            return new RowType();
+        }
+
+        /// <inheritdoc/>
+        protected override bool IsNull()
+        {
+            return list == null;
+        }
+
+        /// <inheritdoc/>
+        protected override int GetNumRows()
+        {
+            if (list != null)
+                return list.Count;
+
+            return 0;
+        }
+
+        /// <inheritdoc/>
+        protected internal override object GetValue(int seqIndex)
+        {
+            return list[seqIndex];
+        }
+
+        /// <inheritdoc/>
+        protected internal override void SetValue(int seqIndex, object value)
+        {
+            list[seqIndex] = (ElementType)value;
+
+            if (OnValueChanged != null)
+                OnValueChanged();
+        }
+
+        /// <inheritdoc/>
+        protected override void CreateList()
+        {
+            list = new List<ElementType>();
+
+            if (OnChanged != null)
+                OnChanged(list);
+        }
+
+        /// <inheritdoc/>
+        protected override void ResizeList()
+        {
+            int size = guiSizeField.Value;
+            if(size == list.Count)
+                return;
+
+            if (size < list.Count)
+                list.RemoveRange(size, list.Count - size);
+            else
+            {
+                ElementType[] extraElements = new ElementType[size - list.Count];
+                list.AddRange(extraElements);
+            }
+
+            if (OnValueChanged != null)
+                OnValueChanged();
+        }
+
+        /// <inheritdoc/>
+        protected override void ClearList()
+        {
+            list = null;
+
+            if (OnChanged != null)
+                OnChanged(list);
+        }
+
+        /// <inheritdoc/>
+        protected internal override void DeleteElement(int index)
+        {
+            list.RemoveAt(index);
+
+            if (OnValueChanged != null)
+                OnValueChanged();
+        }
+
+        /// <inheritdoc/>
+        protected internal override void CloneElement(int index)
+        {
+            object clonedEntry = null;
+            if (list[index] != null)
+                clonedEntry = SerializableUtility.Clone(list[index]);
+
+            list.Add((ElementType)clonedEntry);
+
+            if (OnValueChanged != null)
+                OnValueChanged();
+        }
+
+        /// <inheritdoc/>
+        protected internal override void MoveUpElement(int index)
+        {
+            if ((index - 1) >= 0)
+            {
+                ElementType previousEntry = list[index - 1];
+
+                list[index - 1] = list[index];
+                list[index] = previousEntry;
+
+                if (OnValueChanged != null)
+                    OnValueChanged();
+            }
+        }
+
+        /// <inheritdoc/>
+        protected internal override void MoveDownElement(int index)
+        {
+            if ((index + 1) < list.Count)
+            {
+                ElementType nextEntry = list[index + 1];
+
+                list[index + 1] = list[index];
+                list[index] = nextEntry;
+
+                if (OnValueChanged != null)
+                    OnValueChanged();
+            }
+        }
+    }
+
+    /// <summary>
+    /// Contains GUI elements for a single entry in a list.
+    /// </summary>
+    public abstract class GUIListFieldRow
+    {
+        private GUILayoutX rowLayout;
+        private GUILayoutY contentLayout;
+        private GUILayoutX titleLayout;
+        private bool localTitleLayout;
+        private GUIListFieldBase parent;
+        private int seqIndex;
+        private int depth;
+        private InspectableState modifiedState;
+
+        /// <summary>
+        /// Returns the sequential index of the list entry that this row displays.
+        /// </summary>
+        protected int SeqIndex { get { return seqIndex; } }
+
+        /// <summary>
+        /// Returns the depth at which the row is rendered.
+        /// </summary>
+        protected int Depth { get { return depth; } }
+
+        /// <summary>
+        /// Constructs a new list row object.
+        /// </summary>
+        protected GUIListFieldRow()
+        {
+
+        }
+
+        /// <summary>
+        /// Initializes the row and creates row GUI elements.
+        /// </summary>
+        /// <param name="parent">Parent array GUI object that the entry is contained in.</param>
+        /// <param name="parentLayout">Parent layout that row GUI elements will be added to.</param>
+        /// <param name="seqIndex">Sequential index of the list entry.</param>
+        /// <param name="depth">Determines the depth at which the element is rendered.</param>
+        internal void Initialize(GUIListFieldBase parent, GUILayout parentLayout, int seqIndex, int depth)
+        {
+            this.parent = parent;
+            this.seqIndex = seqIndex;
+            this.depth = depth;
+
+            rowLayout = parentLayout.AddLayoutX();
+            contentLayout = rowLayout.AddLayoutY();
+
+            BuildGUI();
+        }
+
+        /// <summary>
+        /// Changes the index of the list element this row represents.
+        /// </summary>
+        /// <param name="seqIndex">Sequential index of the list entry.</param>
+        internal void SetIndex(int seqIndex)
+        {
+            this.seqIndex = seqIndex;
+        }
+
+        /// <summary>
+        /// (Re)creates all row GUI elements.
+        /// </summary>
+        internal protected void BuildGUI()
+        {
+            contentLayout.Clear();
+
+            GUILayoutX externalTitleLayout = CreateGUI(contentLayout);
+            if (localTitleLayout || (titleLayout != null && titleLayout == externalTitleLayout))
+                return;
+
+            if (externalTitleLayout != null)
+            {
+                localTitleLayout = false;
+                titleLayout = externalTitleLayout;
+            }
+            else
+            {
+                GUILayoutY buttonCenter = rowLayout.AddLayoutY();
+                buttonCenter.AddFlexibleSpace();
+                titleLayout = buttonCenter.AddLayoutX();
+                buttonCenter.AddFlexibleSpace();
+
+                localTitleLayout = true;
+            }
+            
+            GUIContent cloneIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Clone), 
+                new LocEdString("Clone"));
+            GUIContent deleteIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Delete), 
+                new LocEdString("Delete"));
+            GUIContent moveUp = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.MoveUp), 
+                new LocEdString("Move up"));
+            GUIContent moveDown = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.MoveDown), 
+                new LocEdString("Move down"));
+
+            GUIButton cloneBtn = new GUIButton(cloneIcon, GUIOption.FixedWidth(30));
+            GUIButton deleteBtn = new GUIButton(deleteIcon, GUIOption.FixedWidth(30));
+            GUIButton moveUpBtn = new GUIButton(moveUp, GUIOption.FixedWidth(30));
+            GUIButton moveDownBtn = new GUIButton(moveDown, GUIOption.FixedWidth(30));
+
+            cloneBtn.OnClick += () => parent.OnCloneButtonClicked(seqIndex);
+            deleteBtn.OnClick += () => parent.OnDeleteButtonClicked(seqIndex);
+            moveUpBtn.OnClick += () => parent.OnMoveUpButtonClicked(seqIndex);
+            moveDownBtn.OnClick += () => parent.OnMoveDownButtonClicked(seqIndex);
+
+            titleLayout.AddElement(cloneBtn);
+            titleLayout.AddElement(deleteBtn);
+            titleLayout.AddElement(moveUpBtn);
+            titleLayout.AddElement(moveDownBtn);
+        }
+
+        /// <summary>
+        /// Creates GUI elements specific to type in the array row.
+        /// </summary>
+        /// <param name="layout">Layout to insert the row GUI elements to.</param>
+        /// <returns>An optional title bar layout that the standard array buttons will be appended to.</returns>
+        protected abstract GUILayoutX CreateGUI(GUILayoutY layout);
+        
+        /// <summary>
+        /// Refreshes the GUI for the list row and checks if anything was modified.
+        /// </summary>
+        /// <returns>State representing was anything modified between two last calls to <see cref="Refresh"/>.</returns>
+        internal protected virtual InspectableState Refresh()
+        {
+            InspectableState oldState = modifiedState;
+            if (modifiedState.HasFlag(InspectableState.Modified))
+                modifiedState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Marks the contents of the row as modified.
+        /// </summary>
+        protected void MarkAsModified()
+        {
+            modifiedState |= InspectableState.ModifyInProgress;
+        }
+
+        /// <summary>
+        /// Confirms any queued modifications, signaling parent elements.
+        /// </summary>
+        protected void ConfirmModify()
+        {
+            if (modifiedState.HasFlag(InspectableState.ModifyInProgress))
+                modifiedState |= InspectableState.Modified;
+        }
+
+        /// <summary>
+        /// Gets the value contained in this list row.
+        /// </summary>
+        /// <typeparam name="T">Type of the value. Must match the list's element type.</typeparam>
+        /// <returns>Value in this list row.</returns>
+        protected T GetValue<T>()
+        {
+            return (T)parent.GetValue(seqIndex);
+        }
+
+        /// <summary>
+        /// Sets the value contained in this list row.
+        /// </summary>
+        /// <typeparam name="T">Type of the value. Must match the list's element type.</typeparam>
+        /// <param name="value">Value to set.</param>
+        protected void SetValue<T>(T value)
+        {
+            parent.SetValue(seqIndex, value);
+        }
+
+        /// <summary>
+        /// Destroys all row GUI elements.
+        /// </summary>
+        public void Destroy()
+        {
+            if (rowLayout != null)
+            {
+                rowLayout.Destroy();
+                rowLayout = null;
+            }
+
+            contentLayout = null;
+            titleLayout = null;
+            localTitleLayout = false;
+        }
+    }
+}

+ 217 - 217
MBansheeEditor/GameWindow.cs

@@ -1,217 +1,217 @@
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Displays in-game viewport in the editor.
-    /// </summary>
-    public class GameWindow : EditorWindow
-    {
-        private const int HeaderHeight = 20;
-        private static readonly Color BG_COLOR = Color.DarkGray;
-        private readonly AspectRatio[] aspectRatios =
-        {
-            new AspectRatio(16, 9), 
-            new AspectRatio(16, 10),
-            new AspectRatio(5, 4),
-            new AspectRatio(4, 3),
-            new AspectRatio(3, 2)
-        };
-
-        private int selectedAspectRatio = 0;
-        private GUIRenderTexture renderTextureGUI;
-        private GUITexture renderTextureBg;
-        private GUILabel noCameraLabel;
-
-        /// <summary>
-        /// Opens the game window.
-        /// </summary>
-        [MenuItem("Windows/Game", ButtonModifier.CtrlAlt, ButtonCode.G, 6000)]
-        private static void OpenGameWindow()
-        {
-            OpenWindow<GameWindow>();
-        }
-
-        /// <summary>
-        /// Starts execution of the game in the game window.
-        /// </summary>
-        [MenuItem("Tools/Play", 9300)]
-        [ToolbarItem("Play", ToolbarIcon.Play, "", 1800, true)]
-        private static void Play()
-        {
-            if (EditorApplication.IsPaused)
-                EditorApplication.IsPaused = false;
-            else
-                EditorApplication.IsPlaying = !EditorApplication.IsPlaying;
-        }
-
-        /// <summary>
-        /// Pauses the execution of the game on the current frame.
-        /// </summary>
-        [MenuItem("Tools/Pause", 9299)]
-        [ToolbarItem("Pause", ToolbarIcon.Pause, "", 1799)]
-        private static void Pause()
-        {
-            EditorApplication.IsPaused = !EditorApplication.IsPaused;
-        }
-
-        /// <summary>
-        /// Moves the execution of the game by one frame forward.
-        /// </summary>
-        [MenuItem("Tools/Step", 9298)]
-        [ToolbarItem("Step", ToolbarIcon.Step, "", 1798)]
-        private static void Step()
-        {
-            EditorApplication.FrameStep();
-        }
-
-        /// <inheritdoc/>
-        protected override LocString GetDisplayName()
-        {
-            return new LocEdString("Game");
-        }
-
-        private void OnInitialize()
-        {
-            GUILayoutY mainLayout = GUI.AddLayoutY();
-
-            string[] aspectRatioTitles = new string[aspectRatios.Length + 1];
-            aspectRatioTitles[0] = "Free";
-
-            for (int i = 0; i < aspectRatios.Length; i++)
-                aspectRatioTitles[i + 1] = aspectRatios[i].width + ":" + aspectRatios[i].height;
-
-            GUIListBoxField aspectField = new GUIListBoxField(aspectRatioTitles, new LocEdString("Aspect ratio"));
-            aspectField.OnSelectionChanged += OnAspectRatioChanged;
-            
-            GUILayoutY buttonLayoutVert = mainLayout.AddLayoutY();
-            GUILayoutX buttonLayout = buttonLayoutVert.AddLayoutX();
-            buttonLayout.AddElement(aspectField);
-            buttonLayout.AddFlexibleSpace();
-            buttonLayoutVert.AddFlexibleSpace();
-
-            renderTextureGUI = new GUIRenderTexture(null);
-            renderTextureBg = new GUITexture(Builtin.WhiteTexture);
-            renderTextureBg.SetTint(BG_COLOR);
-
-            noCameraLabel = new GUILabel(new LocEdString("(No main camera in scene)"));
-
-            GUIPanel rtPanel = mainLayout.AddPanel();
-            rtPanel.AddElement(renderTextureGUI);
-
-            GUIPanel bgPanel = rtPanel.AddPanel(1);
-            bgPanel.AddElement(renderTextureBg);
-
-            GUILayoutY alignLayoutY = rtPanel.AddLayoutY();
-            alignLayoutY.AddFlexibleSpace();
-            GUILayoutX alignLayoutX = alignLayoutY.AddLayoutX();
-            alignLayoutX.AddFlexibleSpace();
-            alignLayoutX.AddElement(noCameraLabel);
-            alignLayoutX.AddFlexibleSpace();
-            alignLayoutY.AddFlexibleSpace();
-
-            UpdateRenderTexture(Width, Height);
-
-            bool hasMainCamera = Scene.Camera != null;
-
-            renderTextureGUI.Active = hasMainCamera;
-            noCameraLabel.Active = !hasMainCamera;
-        }
-
-        private void OnEditorUpdate()
-        {
-            bool hasMainCamera = Scene.Camera != null;
-
-            renderTextureGUI.Active = hasMainCamera;
-            noCameraLabel.Active = !hasMainCamera;
-        }
-
-        private void OnDestroy()
-        {
-            EditorApplication.MainRenderTarget = null;
-        }
-
-        /// <summary>
-        /// Creates or rebuilds the main render texture. Should be called at least once before using the
-        /// game window. Should be called whenever the window is resized.
-        /// </summary>
-        /// <param name="width">Width of the scene render target, in pixels.</param>
-        /// <param name="height">Height of the scene render target, in pixels.</param>
-        private void UpdateRenderTexture(int width, int height)
-        {
-            height = height - HeaderHeight;
-
-            int rtWidth = MathEx.Max(20, width);
-            int rtHeight = MathEx.Max(20, height);
-
-            if (selectedAspectRatio != 0) // 0 is free aspect
-            {
-                AspectRatio aspectRatio = aspectRatios[selectedAspectRatio - 1];
-
-                int visibleAreaHeight = rtHeight;
-
-                float aspectInv = aspectRatio.height/(float)aspectRatio.width;
-                rtHeight = MathEx.RoundToInt(rtWidth*aspectInv);
-
-                if (rtHeight > visibleAreaHeight)
-                {
-                    rtHeight = visibleAreaHeight;
-                    float aspect = aspectRatio.width / (float)aspectRatio.height;
-                    rtWidth = MathEx.RoundToInt(rtHeight * aspect);
-                }
-            }
-
-            RenderTexture2D renderTexture = new RenderTexture2D(PixelFormat.R8G8B8A8, rtWidth, rtHeight) {Priority = 1};
-
-            EditorApplication.MainRenderTarget = renderTexture;
-            renderTextureGUI.RenderTexture = renderTexture;
-
-            int offsetX = (width - rtWidth)/2;
-            int offsetY = (height - rtHeight)/2;
-
-            Rect2I rtBounds = new Rect2I(offsetX, offsetY, rtWidth, rtHeight);
-            renderTextureGUI.Bounds = rtBounds;
-
-            Rect2I bgBounds = new Rect2I(0, 0, width, height);
-            renderTextureBg.Bounds = bgBounds;
-        }
-
-        /// <summary>
-        /// Triggered when the user selects a new aspect ratio from the drop down box.
-        /// </summary>
-        /// <param name="idx">Index of the aspect ratio the user selected.</param>
-        private void OnAspectRatioChanged(int idx)
-        {
-            selectedAspectRatio = idx;
-            UpdateRenderTexture(Width, Height);
-        }
-
-        /// <inheritdoc/>
-        protected override void WindowResized(int width, int height)
-        {
-            UpdateRenderTexture(width, height);
-
-            base.WindowResized(width, height);
-        }
-
-        /// <summary>
-        /// Camera aspect ratio as numerator and denominator.
-        /// </summary>
-        struct AspectRatio
-        {
-            /// <summary>
-            /// Creates a new object that holds the aspect ratio.
-            /// </summary>
-            /// <param name="width">Numerator of the aspect ratio.</param>
-            /// <param name="height">Denominator of the aspect ratio.</param>
-            public AspectRatio(int width, int height)
-            {
-                this.width = width;
-                this.height = height;
-            }
-
-            public int width;
-            public int height;
-        }
-    }
-}
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Displays in-game viewport in the editor.
+    /// </summary>
+    public class GameWindow : EditorWindow
+    {
+        private const int HeaderHeight = 20;
+        private static readonly Color BG_COLOR = Color.DarkGray;
+        private readonly AspectRatio[] aspectRatios =
+        {
+            new AspectRatio(16, 9), 
+            new AspectRatio(16, 10),
+            new AspectRatio(5, 4),
+            new AspectRatio(4, 3),
+            new AspectRatio(3, 2)
+        };
+
+        private int selectedAspectRatio = 0;
+        private GUIRenderTexture renderTextureGUI;
+        private GUITexture renderTextureBg;
+        private GUILabel noCameraLabel;
+
+        /// <summary>
+        /// Opens the game window.
+        /// </summary>
+        [MenuItem("Windows/Game", ButtonModifier.CtrlAlt, ButtonCode.G, 6000)]
+        private static void OpenGameWindow()
+        {
+            OpenWindow<GameWindow>();
+        }
+
+        /// <summary>
+        /// Starts execution of the game in the game window.
+        /// </summary>
+        [MenuItem("Tools/Play", 9300)]
+        [ToolbarItem("Play", ToolbarIcon.Play, "Play", 1800, true)]
+        private static void Play()
+        {
+            if (EditorApplication.IsPaused)
+                EditorApplication.IsPaused = false;
+            else
+                EditorApplication.IsPlaying = !EditorApplication.IsPlaying;
+        }
+
+        /// <summary>
+        /// Pauses the execution of the game on the current frame.
+        /// </summary>
+        [MenuItem("Tools/Pause", 9299)]
+        [ToolbarItem("Pause", ToolbarIcon.Pause, "Pause", 1799)]
+        private static void Pause()
+        {
+            EditorApplication.IsPaused = !EditorApplication.IsPaused;
+        }
+
+        /// <summary>
+        /// Moves the execution of the game by one frame forward.
+        /// </summary>
+        [MenuItem("Tools/Step", 9298)]
+        [ToolbarItem("Step", ToolbarIcon.Step, "Framestep", 1798)]
+        private static void Step()
+        {
+            EditorApplication.FrameStep();
+        }
+
+        /// <inheritdoc/>
+        protected override LocString GetDisplayName()
+        {
+            return new LocEdString("Game");
+        }
+
+        private void OnInitialize()
+        {
+            GUILayoutY mainLayout = GUI.AddLayoutY();
+
+            string[] aspectRatioTitles = new string[aspectRatios.Length + 1];
+            aspectRatioTitles[0] = "Free";
+
+            for (int i = 0; i < aspectRatios.Length; i++)
+                aspectRatioTitles[i + 1] = aspectRatios[i].width + ":" + aspectRatios[i].height;
+
+            GUIListBoxField aspectField = new GUIListBoxField(aspectRatioTitles, new LocEdString("Aspect ratio"));
+            aspectField.OnSelectionChanged += OnAspectRatioChanged;
+            
+            GUILayoutY buttonLayoutVert = mainLayout.AddLayoutY();
+            GUILayoutX buttonLayout = buttonLayoutVert.AddLayoutX();
+            buttonLayout.AddElement(aspectField);
+            buttonLayout.AddFlexibleSpace();
+            buttonLayoutVert.AddFlexibleSpace();
+
+            renderTextureGUI = new GUIRenderTexture(null);
+            renderTextureBg = new GUITexture(Builtin.WhiteTexture);
+            renderTextureBg.SetTint(BG_COLOR);
+
+            noCameraLabel = new GUILabel(new LocEdString("(No main camera in scene)"));
+
+            GUIPanel rtPanel = mainLayout.AddPanel();
+            rtPanel.AddElement(renderTextureGUI);
+
+            GUIPanel bgPanel = rtPanel.AddPanel(1);
+            bgPanel.AddElement(renderTextureBg);
+
+            GUILayoutY alignLayoutY = rtPanel.AddLayoutY();
+            alignLayoutY.AddFlexibleSpace();
+            GUILayoutX alignLayoutX = alignLayoutY.AddLayoutX();
+            alignLayoutX.AddFlexibleSpace();
+            alignLayoutX.AddElement(noCameraLabel);
+            alignLayoutX.AddFlexibleSpace();
+            alignLayoutY.AddFlexibleSpace();
+
+            UpdateRenderTexture(Width, Height);
+
+            bool hasMainCamera = Scene.Camera != null;
+
+            renderTextureGUI.Active = hasMainCamera;
+            noCameraLabel.Active = !hasMainCamera;
+        }
+
+        private void OnEditorUpdate()
+        {
+            bool hasMainCamera = Scene.Camera != null;
+
+            renderTextureGUI.Active = hasMainCamera;
+            noCameraLabel.Active = !hasMainCamera;
+        }
+
+        private void OnDestroy()
+        {
+            EditorApplication.MainRenderTarget = null;
+        }
+
+        /// <summary>
+        /// Creates or rebuilds the main render texture. Should be called at least once before using the
+        /// game window. Should be called whenever the window is resized.
+        /// </summary>
+        /// <param name="width">Width of the scene render target, in pixels.</param>
+        /// <param name="height">Height of the scene render target, in pixels.</param>
+        private void UpdateRenderTexture(int width, int height)
+        {
+            height = height - HeaderHeight;
+
+            int rtWidth = MathEx.Max(20, width);
+            int rtHeight = MathEx.Max(20, height);
+
+            if (selectedAspectRatio != 0) // 0 is free aspect
+            {
+                AspectRatio aspectRatio = aspectRatios[selectedAspectRatio - 1];
+
+                int visibleAreaHeight = rtHeight;
+
+                float aspectInv = aspectRatio.height/(float)aspectRatio.width;
+                rtHeight = MathEx.RoundToInt(rtWidth*aspectInv);
+
+                if (rtHeight > visibleAreaHeight)
+                {
+                    rtHeight = visibleAreaHeight;
+                    float aspect = aspectRatio.width / (float)aspectRatio.height;
+                    rtWidth = MathEx.RoundToInt(rtHeight * aspect);
+                }
+            }
+
+            RenderTexture2D renderTexture = new RenderTexture2D(PixelFormat.R8G8B8A8, rtWidth, rtHeight) {Priority = 1};
+
+            EditorApplication.MainRenderTarget = renderTexture;
+            renderTextureGUI.RenderTexture = renderTexture;
+
+            int offsetX = (width - rtWidth)/2;
+            int offsetY = (height - rtHeight)/2;
+
+            Rect2I rtBounds = new Rect2I(offsetX, offsetY, rtWidth, rtHeight);
+            renderTextureGUI.Bounds = rtBounds;
+
+            Rect2I bgBounds = new Rect2I(0, 0, width, height);
+            renderTextureBg.Bounds = bgBounds;
+        }
+
+        /// <summary>
+        /// Triggered when the user selects a new aspect ratio from the drop down box.
+        /// </summary>
+        /// <param name="idx">Index of the aspect ratio the user selected.</param>
+        private void OnAspectRatioChanged(int idx)
+        {
+            selectedAspectRatio = idx;
+            UpdateRenderTexture(Width, Height);
+        }
+
+        /// <inheritdoc/>
+        protected override void WindowResized(int width, int height)
+        {
+            UpdateRenderTexture(width, height);
+
+            base.WindowResized(width, height);
+        }
+
+        /// <summary>
+        /// Camera aspect ratio as numerator and denominator.
+        /// </summary>
+        struct AspectRatio
+        {
+            /// <summary>
+            /// Creates a new object that holds the aspect ratio.
+            /// </summary>
+            /// <param name="width">Numerator of the aspect ratio.</param>
+            /// <param name="height">Denominator of the aspect ratio.</param>
+            public AspectRatio(int width, int height)
+            {
+                this.width = width;
+                this.height = height;
+            }
+
+            public int width;
+            public int height;
+        }
+    }
+}

+ 262 - 260
MBansheeEditor/Inspector/InspectableObject.cs

@@ -1,260 +1,262 @@
-using System.Collections.Generic;
-using System;
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Displays GUI for a serializable property containing a generic object. Inspectable object fields are displayed
-    /// in separate rows.
-    /// </summary>
-    public class InspectableObject : InspectableField
-    {
-        private const int IndentAmount = 5;
-
-        private object propertyValue;
-        private List<InspectableField> children = new List<InspectableField>();
-
-        private GUILayoutY guiLayout;
-        private GUILayoutX guiChildLayout;
-        private GUILayoutX guiTitleLayout;
-        private GUILayoutX guiInternalTitleLayout;
-        private bool isExpanded;
-        private bool forceUpdate = true;
-        private State state;
-
-        /// <summary>
-        /// Creates a new inspectable array GUI for the specified property.
-        /// </summary>
-        /// <param name="title">Name of the property, or some other value to set as the title.</param>
-        /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field.Some fields may
-        ///                     contain other fields, in which case you should increase this value by one.</param>
-        /// <param name="layout">Parent layout that all the field elements will be added to.</param>
-        /// <param name="property">Serializable property referencing the array whose contents to display.</param>
-        public InspectableObject(string title, int depth, InspectableFieldLayout layout, SerializableProperty property)
-            : base(title, SerializableProperty.FieldType.Object, depth, layout, property)
-        {
-            
-        }
-
-        /// <inheritdoc/>
-        public override GUILayoutX GetTitleLayout()
-        {
-            return guiTitleLayout;
-        }
-
-        /// <inheritdoc/>
-        public override InspectableState Refresh(int layoutIndex)
-        {
-            // Check if modified internally and rebuild if needed
-            object newPropertyValue = property.GetValue<object>();
-            if (forceUpdate)
-            {
-                propertyValue = newPropertyValue;
-                BuildGUI(layoutIndex);
-                
-                forceUpdate = false;
-            }
-            else if (propertyValue == null && newPropertyValue != null)
-            {
-                propertyValue = newPropertyValue;
-                BuildGUI(layoutIndex);
-                
-            }
-            else if (newPropertyValue == null && propertyValue != null)
-            {
-                propertyValue = null;
-                BuildGUI(layoutIndex);
-            }
-
-            InspectableState state = InspectableState.NotModified;
-            int currentIndex = 0;
-            for (int i = 0; i < children.Count; i++)
-            {
-                state |= children[i].Refresh(currentIndex);
-                currentIndex += children[i].GetNumLayoutElements();
-            }
-
-            return state;
-        }
-
-        /// <summary>
-        /// Rebuilds the GUI object header if needed. 
-        /// </summary>
-        /// <param name="layoutIndex">Index at which to insert the GUI elements.</param>
-        protected void BuildGUI(int layoutIndex)
-        {
-            Action BuildEmptyGUI = () =>
-            {
-                guiInternalTitleLayout = guiTitleLayout.InsertLayoutX(0);
-
-                guiInternalTitleLayout.AddElement(new GUILabel(title));
-                guiInternalTitleLayout.AddElement(new GUILabel("Empty", GUIOption.FixedWidth(100)));
-
-                if (!property.IsValueType)
-                {
-                    GUIContent createIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Create));
-                    GUIButton createBtn = new GUIButton(createIcon, GUIOption.FixedWidth(30));
-                    createBtn.OnClick += OnCreateButtonClicked;
-                    guiInternalTitleLayout.AddElement(createBtn);
-                }
-            };
-
-           Action BuildFilledGUI = () =>
-           {
-               guiInternalTitleLayout = guiTitleLayout.InsertLayoutX(0);
-
-               GUIToggle guiFoldout = new GUIToggle(title, EditorStyles.Foldout);
-               guiFoldout.Value = isExpanded;
-               guiFoldout.OnToggled += OnFoldoutToggled;
-               guiInternalTitleLayout.AddElement(guiFoldout);
-
-               GUIContent clearIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Clear));
-               GUIButton clearBtn = new GUIButton(clearIcon, GUIOption.FixedWidth(20));
-               clearBtn.OnClick += OnClearButtonClicked;
-               guiInternalTitleLayout.AddElement(clearBtn);
-
-               if (isExpanded)
-               {
-                   SerializableObject serializableObject = property.GetObject();
-                   SerializableField[] fields = serializableObject.Fields;
-
-                   if (fields.Length > 0)
-                   {
-                       guiChildLayout = guiLayout.AddLayoutX();
-                       guiChildLayout.AddSpace(IndentAmount);
-
-                       GUIPanel guiContentPanel = guiChildLayout.AddPanel();
-                       GUILayoutX guiIndentLayoutX = guiContentPanel.AddLayoutX();
-                       guiIndentLayoutX.AddSpace(IndentAmount);
-                       GUILayoutY guiIndentLayoutY = guiIndentLayoutX.AddLayoutY();
-                       guiIndentLayoutY.AddSpace(IndentAmount);
-                       GUILayoutY guiContentLayout = guiIndentLayoutY.AddLayoutY();
-                       guiIndentLayoutY.AddSpace(IndentAmount);
-                       guiIndentLayoutX.AddSpace(IndentAmount);
-                       guiChildLayout.AddSpace(IndentAmount);
-
-                       short backgroundDepth = (short) (Inspector.START_BACKGROUND_DEPTH - depth - 1);
-                       string bgPanelStyle = depth%2 == 0
-                           ? EditorStyles.InspectorContentBgAlternate
-                           : EditorStyles.InspectorContentBg;
-                       GUIPanel backgroundPanel = guiContentPanel.AddPanel(backgroundDepth);
-                       GUITexture inspectorContentBg = new GUITexture(null, bgPanelStyle);
-                       backgroundPanel.AddElement(inspectorContentBg);
-
-                       int currentIndex = 0;
-                       foreach (var field in fields)
-                       {
-                           if (!field.Inspectable)
-                               continue;
-
-                           InspectableField inspectable = CreateInspectable(field.Name, currentIndex, depth + 1,
-                               new InspectableFieldLayout(guiContentLayout), field.GetProperty());
-
-                           children.Add(inspectable);
-                           currentIndex += inspectable.GetNumLayoutElements();
-                       }
-                   }
-               }
-               else
-                   guiChildLayout = null;
-           };
-
-           if (state == State.None)
-           {
-               if (propertyValue != null)
-               {
-                   BuildFilledGUI();
-                   state = State.Filled;
-               }
-               else
-               {
-                   BuildEmptyGUI();
-
-                   state = State.Empty;
-               }
-           }
-           else if (state == State.Empty)
-           {
-               if (propertyValue != null)
-               {
-                   guiInternalTitleLayout.Destroy();
-                   BuildFilledGUI();
-                   state = State.Filled;
-               }
-           }
-           else if (state == State.Filled)
-           {
-               foreach (var child in children)
-                   child.Destroy();
-
-               children.Clear();
-               guiInternalTitleLayout.Destroy();
-
-               if (guiChildLayout != null)
-               {
-                   guiChildLayout.Destroy();
-                   guiChildLayout = null;
-               }
-
-               if (propertyValue == null)
-               {
-                   BuildEmptyGUI();
-                   state = State.Empty;
-               }
-               else
-               {
-                   BuildFilledGUI();
-               }
-           }
-        }
-
-        /// <inheritdoc/>
-        protected internal override void Initialize(int index)
-        {
-            guiLayout = layout.AddLayoutY(index);
-            guiTitleLayout = guiLayout.AddLayoutX();
-
-            propertyValue = property.GetValue<object>();
-            BuildGUI(index);
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the expand/collapse toggle in the title bar.
-        /// </summary>
-        /// <param name="expanded">Determines whether the contents were expanded or collapsed.</param>
-        private void OnFoldoutToggled(bool expanded)
-        {
-            isExpanded = expanded;
-            forceUpdate = true;
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the create button on the title bar. Creates a brand new object with default
-        /// values in the place of the current array.
-        /// </summary>
-        private void OnCreateButtonClicked()
-        {
-            property.SetValue(property.CreateObjectInstance<object>());
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the clear button on the title bar. Deletes the current object and sets
-        /// the reference to the object in the parent object to null. This is only relevant for objects of reference types.
-        /// </summary>
-        private void OnClearButtonClicked()
-        {
-            property.SetValue<object>(null);
-        }
-
-        /// <summary>
-        /// Possible states object GUI can be in.
-        /// </summary>
-        private enum State
-        {
-            None,
-            Empty,
-            Filled
-        }
-    }
-}
+using System.Collections.Generic;
+using System;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Displays GUI for a serializable property containing a generic object. Inspectable object fields are displayed
+    /// in separate rows.
+    /// </summary>
+    public class InspectableObject : InspectableField
+    {
+        private const int IndentAmount = 5;
+
+        private object propertyValue;
+        private List<InspectableField> children = new List<InspectableField>();
+
+        private GUILayoutY guiLayout;
+        private GUILayoutX guiChildLayout;
+        private GUILayoutX guiTitleLayout;
+        private GUILayoutX guiInternalTitleLayout;
+        private bool isExpanded;
+        private bool forceUpdate = true;
+        private State state;
+
+        /// <summary>
+        /// Creates a new inspectable array GUI for the specified property.
+        /// </summary>
+        /// <param name="title">Name of the property, or some other value to set as the title.</param>
+        /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field.Some fields may
+        ///                     contain other fields, in which case you should increase this value by one.</param>
+        /// <param name="layout">Parent layout that all the field elements will be added to.</param>
+        /// <param name="property">Serializable property referencing the array whose contents to display.</param>
+        public InspectableObject(string title, int depth, InspectableFieldLayout layout, SerializableProperty property)
+            : base(title, SerializableProperty.FieldType.Object, depth, layout, property)
+        {
+            
+        }
+
+        /// <inheritdoc/>
+        public override GUILayoutX GetTitleLayout()
+        {
+            return guiTitleLayout;
+        }
+
+        /// <inheritdoc/>
+        public override InspectableState Refresh(int layoutIndex)
+        {
+            // Check if modified internally and rebuild if needed
+            object newPropertyValue = property.GetValue<object>();
+            if (forceUpdate)
+            {
+                propertyValue = newPropertyValue;
+                BuildGUI(layoutIndex);
+                
+                forceUpdate = false;
+            }
+            else if (propertyValue == null && newPropertyValue != null)
+            {
+                propertyValue = newPropertyValue;
+                BuildGUI(layoutIndex);
+                
+            }
+            else if (newPropertyValue == null && propertyValue != null)
+            {
+                propertyValue = null;
+                BuildGUI(layoutIndex);
+            }
+
+            InspectableState state = InspectableState.NotModified;
+            int currentIndex = 0;
+            for (int i = 0; i < children.Count; i++)
+            {
+                state |= children[i].Refresh(currentIndex);
+                currentIndex += children[i].GetNumLayoutElements();
+            }
+
+            return state;
+        }
+
+        /// <summary>
+        /// Rebuilds the GUI object header if needed. 
+        /// </summary>
+        /// <param name="layoutIndex">Index at which to insert the GUI elements.</param>
+        protected void BuildGUI(int layoutIndex)
+        {
+            Action BuildEmptyGUI = () =>
+            {
+                guiInternalTitleLayout = guiTitleLayout.InsertLayoutX(0);
+
+                guiInternalTitleLayout.AddElement(new GUILabel(title));
+                guiInternalTitleLayout.AddElement(new GUILabel("Empty", GUIOption.FixedWidth(100)));
+
+                if (!property.IsValueType)
+                {
+                    GUIContent createIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Create), 
+                        new LocEdString("Create"));
+                    GUIButton createBtn = new GUIButton(createIcon, GUIOption.FixedWidth(30));
+                    createBtn.OnClick += OnCreateButtonClicked;
+                    guiInternalTitleLayout.AddElement(createBtn);
+                }
+            };
+
+           Action BuildFilledGUI = () =>
+           {
+               guiInternalTitleLayout = guiTitleLayout.InsertLayoutX(0);
+
+               GUIToggle guiFoldout = new GUIToggle(title, EditorStyles.Foldout);
+               guiFoldout.Value = isExpanded;
+               guiFoldout.OnToggled += OnFoldoutToggled;
+               guiInternalTitleLayout.AddElement(guiFoldout);
+
+               GUIContent clearIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Clear), 
+                   new LocEdString("Clear"));
+               GUIButton clearBtn = new GUIButton(clearIcon, GUIOption.FixedWidth(20));
+               clearBtn.OnClick += OnClearButtonClicked;
+               guiInternalTitleLayout.AddElement(clearBtn);
+
+               if (isExpanded)
+               {
+                   SerializableObject serializableObject = property.GetObject();
+                   SerializableField[] fields = serializableObject.Fields;
+
+                   if (fields.Length > 0)
+                   {
+                       guiChildLayout = guiLayout.AddLayoutX();
+                       guiChildLayout.AddSpace(IndentAmount);
+
+                       GUIPanel guiContentPanel = guiChildLayout.AddPanel();
+                       GUILayoutX guiIndentLayoutX = guiContentPanel.AddLayoutX();
+                       guiIndentLayoutX.AddSpace(IndentAmount);
+                       GUILayoutY guiIndentLayoutY = guiIndentLayoutX.AddLayoutY();
+                       guiIndentLayoutY.AddSpace(IndentAmount);
+                       GUILayoutY guiContentLayout = guiIndentLayoutY.AddLayoutY();
+                       guiIndentLayoutY.AddSpace(IndentAmount);
+                       guiIndentLayoutX.AddSpace(IndentAmount);
+                       guiChildLayout.AddSpace(IndentAmount);
+
+                       short backgroundDepth = (short) (Inspector.START_BACKGROUND_DEPTH - depth - 1);
+                       string bgPanelStyle = depth%2 == 0
+                           ? EditorStyles.InspectorContentBgAlternate
+                           : EditorStyles.InspectorContentBg;
+                       GUIPanel backgroundPanel = guiContentPanel.AddPanel(backgroundDepth);
+                       GUITexture inspectorContentBg = new GUITexture(null, bgPanelStyle);
+                       backgroundPanel.AddElement(inspectorContentBg);
+
+                       int currentIndex = 0;
+                       foreach (var field in fields)
+                       {
+                           if (!field.Inspectable)
+                               continue;
+
+                           InspectableField inspectable = CreateInspectable(field.Name, currentIndex, depth + 1,
+                               new InspectableFieldLayout(guiContentLayout), field.GetProperty());
+
+                           children.Add(inspectable);
+                           currentIndex += inspectable.GetNumLayoutElements();
+                       }
+                   }
+               }
+               else
+                   guiChildLayout = null;
+           };
+
+           if (state == State.None)
+           {
+               if (propertyValue != null)
+               {
+                   BuildFilledGUI();
+                   state = State.Filled;
+               }
+               else
+               {
+                   BuildEmptyGUI();
+
+                   state = State.Empty;
+               }
+           }
+           else if (state == State.Empty)
+           {
+               if (propertyValue != null)
+               {
+                   guiInternalTitleLayout.Destroy();
+                   BuildFilledGUI();
+                   state = State.Filled;
+               }
+           }
+           else if (state == State.Filled)
+           {
+               foreach (var child in children)
+                   child.Destroy();
+
+               children.Clear();
+               guiInternalTitleLayout.Destroy();
+
+               if (guiChildLayout != null)
+               {
+                   guiChildLayout.Destroy();
+                   guiChildLayout = null;
+               }
+
+               if (propertyValue == null)
+               {
+                   BuildEmptyGUI();
+                   state = State.Empty;
+               }
+               else
+               {
+                   BuildFilledGUI();
+               }
+           }
+        }
+
+        /// <inheritdoc/>
+        protected internal override void Initialize(int index)
+        {
+            guiLayout = layout.AddLayoutY(index);
+            guiTitleLayout = guiLayout.AddLayoutX();
+
+            propertyValue = property.GetValue<object>();
+            BuildGUI(index);
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the expand/collapse toggle in the title bar.
+        /// </summary>
+        /// <param name="expanded">Determines whether the contents were expanded or collapsed.</param>
+        private void OnFoldoutToggled(bool expanded)
+        {
+            isExpanded = expanded;
+            forceUpdate = true;
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the create button on the title bar. Creates a brand new object with default
+        /// values in the place of the current array.
+        /// </summary>
+        private void OnCreateButtonClicked()
+        {
+            property.SetValue(property.CreateObjectInstance<object>());
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the clear button on the title bar. Deletes the current object and sets
+        /// the reference to the object in the parent object to null. This is only relevant for objects of reference types.
+        /// </summary>
+        private void OnClearButtonClicked()
+        {
+            property.SetValue<object>(null);
+        }
+
+        /// <summary>
+        /// Possible states object GUI can be in.
+        /// </summary>
+        private enum State
+        {
+            None,
+            Empty,
+            Filled
+        }
+    }
+}

+ 181 - 181
MBansheeEditor/Library/LibraryMenu.cs

@@ -1,181 +1,181 @@
-using System.IO;
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Handles main menu and context menu items and callbacks for project library window.
-    /// </summary>
-    internal static class LibraryMenu
-    {
-        /// <summary>
-        /// Creates the context menu used by project library window. New context menu must be created when a new instance
-        /// of the project library window is created.
-        /// </summary>
-        /// <param name="win">Instance of the project library window.</param>
-        /// <returns>Context menu bound to the specified instance of the project library window.</returns>
-        internal static ContextMenu CreateContextMenu(LibraryWindow win)
-        {
-            ContextMenu entryContextMenu = new ContextMenu();
-            entryContextMenu.AddItem("Create", null);
-            entryContextMenu.AddItem("Create/Folder", CreateFolder);
-            entryContextMenu.AddItem("Create/Material", CreateEmptyMaterial);
-            entryContextMenu.AddItem("Create/Shader", CreateEmptyShader);
-            entryContextMenu.AddItem("Create/C# script", CreateEmptyCSScript);
-            entryContextMenu.AddItem("Create/Sprite texture", CreateEmptySpriteTexture);
-            entryContextMenu.AddItem("Create/GUI skin", CreateEmptyGUISkin);
-            entryContextMenu.AddItem("Create/String table", CreateEmptyStringTable);
-            entryContextMenu.AddSeparator("");
-            entryContextMenu.AddItem("Rename", win.RenameSelection, new ShortcutKey(ButtonModifier.None, ButtonCode.F2));
-            entryContextMenu.AddSeparator("");
-            entryContextMenu.AddItem("Cut", win.CutSelection, new ShortcutKey(ButtonModifier.Ctrl, ButtonCode.X));
-            entryContextMenu.AddItem("Copy", win.CopySelection, new ShortcutKey(ButtonModifier.Ctrl, ButtonCode.C));
-            entryContextMenu.AddItem("Duplicate", win.DuplicateSelection, new ShortcutKey(ButtonModifier.Ctrl, ButtonCode.D));
-            entryContextMenu.AddItem("Paste", win.PasteToSelection, new ShortcutKey(ButtonModifier.Ctrl, ButtonCode.V));
-            entryContextMenu.AddSeparator("");
-            entryContextMenu.AddItem("Delete", win.DeleteSelection, new ShortcutKey(ButtonModifier.None, ButtonCode.Delete));
-            entryContextMenu.AddSeparator("");
-            entryContextMenu.AddItem("Open externally", OpenExternally);
-            entryContextMenu.AddItem("Explore location", ExploreLocation);
-
-            entryContextMenu.SetLocalizedName("Rename", new LocEdString("Rename"));
-            entryContextMenu.SetLocalizedName("Cut", new LocEdString("Cut"));
-            entryContextMenu.SetLocalizedName("Copy", new LocEdString("Copy"));
-            entryContextMenu.SetLocalizedName("Duplicate", new LocEdString("Duplicate"));
-            entryContextMenu.SetLocalizedName("Paste", new LocEdString("Paste"));
-            entryContextMenu.SetLocalizedName("Delete", new LocEdString("Delete"));
-
-            return entryContextMenu;
-        }
-
-        /// <summary>
-        /// Queries if a library window is displayed.
-        /// </summary>
-        /// <returns>True if a library window is active, false if not.</returns>
-        internal static bool IsLibraryWindowActive()
-        {
-            return EditorWindow.GetWindow<LibraryWindow>() != null;
-        }
-
-        /// <summary>
-        /// Creates a new material with the default shader in the currently selected project library folder.
-        /// </summary>
-        [MenuItem("Resources/Create/Folder", 9051, false, "IsLibraryWindowActive")]
-        internal static void CreateFolder()
-        {
-            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
-            if (win == null)
-                return;
-
-            LibraryUtility.CreateFolder(win.SelectedFolder);
-        }
-
-        /// <summary>
-        /// Creates a new material with the default shader in the currently selected project library folder.
-        /// </summary>
-        [MenuItem("Resources/Create/Material", 9050, false, "IsLibraryWindowActive")]
-        [ToolbarItem("Material", ToolbarIcon.NewMat, "", 1498)]
-        internal static void CreateEmptyMaterial()
-        {
-            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
-            if(win == null)
-                return;
-
-            LibraryUtility.CreateEmptyMaterial(win.SelectedFolder);
-        }
-
-        /// <summary>
-        /// Creates a new shader containing a rough code outline in the currently selected project library folder.
-        /// </summary>
-        [MenuItem("Resources/Create/Shader", 9049, false, "IsLibraryWindowActive")]
-        [ToolbarItem("Shader", ToolbarIcon.NewShader, "", 1499)]
-        internal static void CreateEmptyShader()
-        {
-            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
-            if (win == null)
-                return;
-
-            LibraryUtility.CreateEmptyShader(win.SelectedFolder);
-        }
-
-        /// <summary>
-        /// Creates a new C# script containing a rough code outline in the currently selected project library folder.
-        /// </summary>
-        [MenuItem("Resources/Create/C# script", 9048, false, "IsLibraryWindowActive")]
-        [ToolbarItem("C# script", ToolbarIcon.NewCSScript, "", 1500, true)]
-        internal static void CreateEmptyCSScript()
-        {
-            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
-            if (win == null)
-                return;
-
-            LibraryUtility.CreateEmptyCSScript(win.SelectedFolder);
-        }
-
-        /// <summary>
-        /// Creates a new empty sprite texture in the currently selected project library folder.
-        /// </summary>
-        [MenuItem("Resources/Create/Sprite texture", 9047, false, "IsLibraryWindowActive")]
-        [ToolbarItem("Sprite texture", ToolbarIcon.NewSpriteTex, "", 1497)]
-        internal static void CreateEmptySpriteTexture()
-        {
-            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
-            if (win == null)
-                return;
-
-            LibraryUtility.CreateEmptySpriteTexture(win.SelectedFolder);
-        }
-
-        /// <summary>
-        /// Creates a new empty GUI skin in the currently selected project library folder.
-        /// </summary>
-        [MenuItem("Resources/Create/GUI skin", 9046, false, "IsLibraryWindowActive")]
-        internal static void CreateEmptyGUISkin()
-        {
-            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
-            if (win == null)
-                return;
-
-            LibraryUtility.CreateEmptyGUISkin(win.SelectedFolder);
-        }
-
-        /// <summary>
-        /// Creates a new empty string table in the currently selected project library folder.
-        /// </summary>
-        [MenuItem("Resources/Create/String table", 9045, false, "IsLibraryWindowActive")]
-        internal static void CreateEmptyStringTable()
-        {
-            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
-            if (win == null)
-                return;
-
-            LibraryUtility.CreateEmptyStringTable(win.SelectedFolder);
-        }
-
-        /// <summary>
-        /// Opens the currently selected project library file or folder in the default external application.
-        /// </summary>
-        [MenuItem("Resources/Open externally", 9040, true, "IsLibraryWindowActive")]
-        internal static void OpenExternally()
-        {
-            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
-            if (win == null)
-                return;
-
-            EditorApplication.OpenExternally(Path.Combine(ProjectLibrary.ResourceFolder, win.SelectedEntry));
-        }
-
-        /// <summary>
-        /// Explores the current project library folder in the external file system explorer.
-        /// </summary>
-        [MenuItem("Resources/Explore location", 9039, false, "IsLibraryWindowActive")]
-        internal static void ExploreLocation()
-        {
-            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
-            if (win == null)
-                return;
-
-            EditorApplication.OpenExternally(Path.Combine(ProjectLibrary.ResourceFolder, win.CurrentFolder));
-        }
-    }
-}
+using System.IO;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Handles main menu and context menu items and callbacks for project library window.
+    /// </summary>
+    internal static class LibraryMenu
+    {
+        /// <summary>
+        /// Creates the context menu used by project library window. New context menu must be created when a new instance
+        /// of the project library window is created.
+        /// </summary>
+        /// <param name="win">Instance of the project library window.</param>
+        /// <returns>Context menu bound to the specified instance of the project library window.</returns>
+        internal static ContextMenu CreateContextMenu(LibraryWindow win)
+        {
+            ContextMenu entryContextMenu = new ContextMenu();
+            entryContextMenu.AddItem("Create", null);
+            entryContextMenu.AddItem("Create/Folder", CreateFolder);
+            entryContextMenu.AddItem("Create/Material", CreateEmptyMaterial);
+            entryContextMenu.AddItem("Create/Shader", CreateEmptyShader);
+            entryContextMenu.AddItem("Create/C# script", CreateEmptyCSScript);
+            entryContextMenu.AddItem("Create/Sprite texture", CreateEmptySpriteTexture);
+            entryContextMenu.AddItem("Create/GUI skin", CreateEmptyGUISkin);
+            entryContextMenu.AddItem("Create/String table", CreateEmptyStringTable);
+            entryContextMenu.AddSeparator("");
+            entryContextMenu.AddItem("Rename", win.RenameSelection, new ShortcutKey(ButtonModifier.None, ButtonCode.F2));
+            entryContextMenu.AddSeparator("");
+            entryContextMenu.AddItem("Cut", win.CutSelection, new ShortcutKey(ButtonModifier.Ctrl, ButtonCode.X));
+            entryContextMenu.AddItem("Copy", win.CopySelection, new ShortcutKey(ButtonModifier.Ctrl, ButtonCode.C));
+            entryContextMenu.AddItem("Duplicate", win.DuplicateSelection, new ShortcutKey(ButtonModifier.Ctrl, ButtonCode.D));
+            entryContextMenu.AddItem("Paste", win.PasteToSelection, new ShortcutKey(ButtonModifier.Ctrl, ButtonCode.V));
+            entryContextMenu.AddSeparator("");
+            entryContextMenu.AddItem("Delete", win.DeleteSelection, new ShortcutKey(ButtonModifier.None, ButtonCode.Delete));
+            entryContextMenu.AddSeparator("");
+            entryContextMenu.AddItem("Open externally", OpenExternally);
+            entryContextMenu.AddItem("Explore location", ExploreLocation);
+
+            entryContextMenu.SetLocalizedName("Rename", new LocEdString("Rename"));
+            entryContextMenu.SetLocalizedName("Cut", new LocEdString("Cut"));
+            entryContextMenu.SetLocalizedName("Copy", new LocEdString("Copy"));
+            entryContextMenu.SetLocalizedName("Duplicate", new LocEdString("Duplicate"));
+            entryContextMenu.SetLocalizedName("Paste", new LocEdString("Paste"));
+            entryContextMenu.SetLocalizedName("Delete", new LocEdString("Delete"));
+
+            return entryContextMenu;
+        }
+
+        /// <summary>
+        /// Queries if a library window is displayed.
+        /// </summary>
+        /// <returns>True if a library window is active, false if not.</returns>
+        internal static bool IsLibraryWindowActive()
+        {
+            return EditorWindow.GetWindow<LibraryWindow>() != null;
+        }
+
+        /// <summary>
+        /// Creates a new material with the default shader in the currently selected project library folder.
+        /// </summary>
+        [MenuItem("Resources/Create/Folder", 9051, false, "IsLibraryWindowActive")]
+        internal static void CreateFolder()
+        {
+            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+            if (win == null)
+                return;
+
+            LibraryUtility.CreateFolder(win.SelectedFolder);
+        }
+
+        /// <summary>
+        /// Creates a new material with the default shader in the currently selected project library folder.
+        /// </summary>
+        [MenuItem("Resources/Create/Material", 9050, false, "IsLibraryWindowActive")]
+        [ToolbarItem("Material", ToolbarIcon.NewMat, "New material.", 1498)]
+        internal static void CreateEmptyMaterial()
+        {
+            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+            if(win == null)
+                return;
+
+            LibraryUtility.CreateEmptyMaterial(win.SelectedFolder);
+        }
+
+        /// <summary>
+        /// Creates a new shader containing a rough code outline in the currently selected project library folder.
+        /// </summary>
+        [MenuItem("Resources/Create/Shader", 9049, false, "IsLibraryWindowActive")]
+        [ToolbarItem("Shader", ToolbarIcon.NewShader, "New shader.", 1499)]
+        internal static void CreateEmptyShader()
+        {
+            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+            if (win == null)
+                return;
+
+            LibraryUtility.CreateEmptyShader(win.SelectedFolder);
+        }
+
+        /// <summary>
+        /// Creates a new C# script containing a rough code outline in the currently selected project library folder.
+        /// </summary>
+        [MenuItem("Resources/Create/C# script", 9048, false, "IsLibraryWindowActive")]
+        [ToolbarItem("C# script", ToolbarIcon.NewCSScript, "New C# script.", 1500, true)]
+        internal static void CreateEmptyCSScript()
+        {
+            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+            if (win == null)
+                return;
+
+            LibraryUtility.CreateEmptyCSScript(win.SelectedFolder);
+        }
+
+        /// <summary>
+        /// Creates a new empty sprite texture in the currently selected project library folder.
+        /// </summary>
+        [MenuItem("Resources/Create/Sprite texture", 9047, false, "IsLibraryWindowActive")]
+        [ToolbarItem("Sprite texture", ToolbarIcon.NewSpriteTex, "New sprite texture.", 1497)]
+        internal static void CreateEmptySpriteTexture()
+        {
+            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+            if (win == null)
+                return;
+
+            LibraryUtility.CreateEmptySpriteTexture(win.SelectedFolder);
+        }
+
+        /// <summary>
+        /// Creates a new empty GUI skin in the currently selected project library folder.
+        /// </summary>
+        [MenuItem("Resources/Create/GUI skin", 9046, false, "IsLibraryWindowActive")]
+        internal static void CreateEmptyGUISkin()
+        {
+            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+            if (win == null)
+                return;
+
+            LibraryUtility.CreateEmptyGUISkin(win.SelectedFolder);
+        }
+
+        /// <summary>
+        /// Creates a new empty string table in the currently selected project library folder.
+        /// </summary>
+        [MenuItem("Resources/Create/String table", 9045, false, "IsLibraryWindowActive")]
+        internal static void CreateEmptyStringTable()
+        {
+            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+            if (win == null)
+                return;
+
+            LibraryUtility.CreateEmptyStringTable(win.SelectedFolder);
+        }
+
+        /// <summary>
+        /// Opens the currently selected project library file or folder in the default external application.
+        /// </summary>
+        [MenuItem("Resources/Open externally", 9040, true, "IsLibraryWindowActive")]
+        internal static void OpenExternally()
+        {
+            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+            if (win == null)
+                return;
+
+            EditorApplication.OpenExternally(Path.Combine(ProjectLibrary.ResourceFolder, win.SelectedEntry));
+        }
+
+        /// <summary>
+        /// Explores the current project library folder in the external file system explorer.
+        /// </summary>
+        [MenuItem("Resources/Explore location", 9039, false, "IsLibraryWindowActive")]
+        internal static void ExploreLocation()
+        {
+            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+            if (win == null)
+                return;
+
+            EditorApplication.OpenExternally(Path.Combine(ProjectLibrary.ResourceFolder, win.CurrentFolder));
+        }
+    }
+}

+ 1476 - 1472
MBansheeEditor/Library/LibraryWindow.cs

@@ -1,1472 +1,1476 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Types of resource tile display in the library window.
-    /// </summary>
-    internal enum ProjectViewType
-    {
-        Grid64, Grid48, Grid32, List16
-    }
-
-    /// <summary>
-    /// Editor window that displays all resources in the project. Resources can be displayed as a grid or list of icons,
-    /// with the ability to move, cut, copy, paste resources and folders, as well as supporting drag and drop and search
-    /// operations.
-    /// </summary>
-    internal sealed class LibraryWindow : EditorWindow
-    {
-        /// <summary>
-        /// Directions the selection cursor in library window can be moved in.
-        /// </summary>
-        internal enum MoveDirection
-        {
-            Up, Down, Left, Right
-        }
-
-        private const int DRAG_SCROLL_HEIGHT = 20;
-        private const int DRAG_SCROLL_AMOUNT_PER_SECOND = 100;
-        private const int FOLDER_BUTTON_WIDTH = 30;
-        private const int FOLDER_SEPARATOR_WIDTH = 10;
-        
-        private bool hasContentFocus = false;
-        private bool HasContentFocus { get { return HasFocus && hasContentFocus; } }
-
-        private string searchQuery;
-        private bool IsSearchActive { get { return !string.IsNullOrEmpty(searchQuery); } }
-
-        private ProjectViewType viewType = ProjectViewType.Grid32;
-
-        private bool requiresRefresh;
-        private string currentDirectory = "";
-        private List<string> selectionPaths = new List<string>();
-        private int selectionAnchorStart = -1;
-        private int selectionAnchorEnd = -1;
-        private string pingPath = "";
-        private string hoverHighlightPath = "";
-
-        private LibraryGUIContent content;
-        private GUIScrollArea contentScrollArea;
-        private GUILayoutX searchBarLayout;
-        private GUIButton optionsButton;
-        private GUILayout folderBarLayout;
-        private GUILayout folderListLayout;
-        private GUITextField searchField;
-        private GUITexture dragSelection;
-
-        private ContextMenu entryContextMenu;
-        private LibraryDropTarget dropTarget;
-
-        private int autoScrollAmount;
-        private bool isDraggingSelection;
-        private Vector2I dragSelectionStart;
-        private Vector2I dragSelectionEnd;
-
-        private LibraryGUIEntry inProgressRenameElement;
-
-        // Cut/Copy/Paste
-        private List<string> copyPaths = new List<string>();
-        private List<string> cutPaths = new List<string>();
-
-        /// <summary>
-        /// Determines how to display resource tiles in the library window.
-        /// </summary>
-        internal ProjectViewType ViewType
-        {
-            get { return viewType; }
-            set { viewType = value; Refresh(); }
-        }
-
-        /// <summary>
-        /// Returns a file or folder currently selected in the library window. If nothing is selected, returns the active
-        /// folder. Returned path is relative to project library resources folder.
-        /// </summary>
-        public string SelectedEntry
-        {
-            get
-            {
-                if (selectionPaths.Count == 1)
-                {
-                    LibraryEntry entry = ProjectLibrary.GetEntry(selectionPaths[0]);
-                    if (entry != null)
-                        return entry.Path;
-                }
-
-                return currentDirectory;
-            }
-        }
-
-        /// <summary>
-        /// Returns a folder currently selected in the library window. If no folder is selected, returns the active
-        /// folder. Returned path is relative to project library resources folder.
-        /// </summary>
-        public string SelectedFolder
-        {
-            get
-            {
-                DirectoryEntry selectedDirectory = null;
-                if (selectionPaths.Count == 1)
-                {
-                    LibraryEntry entry = ProjectLibrary.GetEntry(selectionPaths[0]);
-                    if (entry != null && entry.Type == LibraryEntryType.Directory)
-                        selectedDirectory = (DirectoryEntry) entry;
-                }
-
-                if (selectedDirectory != null)
-                    return selectedDirectory.Path;
-                
-                return currentDirectory;
-            }
-        }
-
-        /// <summary>
-        /// Returns the path to the folder currently displayed in the library window. Returned path is relative to project 
-        /// library resources folder.
-        /// </summary>
-        public string CurrentFolder
-        {
-            get { return currentDirectory; }
-        }
-
-        /// <summary>
-        /// Context menu that should open when user right clicks on the content area.
-        /// </summary>
-        internal ContextMenu ContextMenu
-        {
-            get { return entryContextMenu; }
-        }
-
-        /// <summary>
-        /// Opens the library window if not already open.
-        /// </summary>
-        [MenuItem("Windows/Library", ButtonModifier.CtrlAlt, ButtonCode.L, 6000)]
-        private static void OpenLibraryWindow()
-        {
-            OpenWindow<LibraryWindow>();
-        }
-
-        private void OnInitialize()
-        {
-            ProjectLibrary.OnEntryAdded += OnEntryChanged;
-            ProjectLibrary.OnEntryRemoved += OnEntryChanged;
-
-            GUILayoutY contentLayout = GUI.AddLayoutY();
-
-            searchBarLayout = contentLayout.AddLayoutX();
-            searchField = new GUITextField();
-            searchField.OnChanged += OnSearchChanged;
-
-            GUIContent clearIcon = new GUIContent(EditorBuiltin.GetLibraryWindowIcon(LibraryWindowIcon.Clear));
-            GUIButton clearSearchBtn = new GUIButton(clearIcon);
-            clearSearchBtn.OnClick += ClearSearch;
-            clearSearchBtn.SetWidth(40);
-
-            GUIContent optionsIcon = new GUIContent(EditorBuiltin.GetLibraryWindowIcon(LibraryWindowIcon.Options));
-            optionsButton = new GUIButton(optionsIcon);
-            optionsButton.OnClick += OpenOptionsWindow;
-            optionsButton.SetWidth(40);
-            searchBarLayout.AddElement(searchField);
-            searchBarLayout.AddElement(clearSearchBtn);
-            searchBarLayout.AddElement(optionsButton);
-
-            folderBarLayout = contentLayout.AddLayoutX();
-
-            GUIContent homeIcon = new GUIContent(EditorBuiltin.GetLibraryWindowIcon(LibraryWindowIcon.Home));
-            GUIButton homeButton = new GUIButton(homeIcon, GUIOption.FixedWidth(FOLDER_BUTTON_WIDTH));
-            homeButton.OnClick += OnHomeClicked;
-
-            GUIContent upIcon = new GUIContent(EditorBuiltin.GetLibraryWindowIcon(LibraryWindowIcon.Up));
-            GUIButton upButton = new GUIButton(upIcon, GUIOption.FixedWidth(FOLDER_BUTTON_WIDTH));
-            upButton.OnClick += OnUpClicked;
-
-            folderBarLayout.AddElement(homeButton);
-            folderBarLayout.AddElement(upButton);
-            folderBarLayout.AddSpace(10);
-
-            contentScrollArea = new GUIScrollArea(GUIOption.FlexibleWidth(), GUIOption.FlexibleHeight());
-            contentLayout.AddElement(contentScrollArea);
-            contentLayout.AddFlexibleSpace();
-
-            entryContextMenu = LibraryMenu.CreateContextMenu(this);
-            content = new LibraryGUIContent(this, contentScrollArea);
-            
-            Reset();
-
-            dropTarget = new LibraryDropTarget(this);
-            dropTarget.Bounds = GetScrollAreaBounds();
-            dropTarget.OnStart += OnDragStart;
-            dropTarget.OnDrag += OnDragMove;
-            dropTarget.OnLeave += OnDragLeave;
-            dropTarget.OnDropResource += OnResourceDragDropped;
-            dropTarget.OnDropSceneObject += OnSceneObjectDragDropped;
-            dropTarget.OnEnd += OnDragEnd;
-
-            Selection.OnSelectionChanged += OnSelectionChanged;
-            Selection.OnResourcePing += OnPing;
-        }
-
-        private void OnDestroy()
-        {
-            Selection.OnSelectionChanged -= OnSelectionChanged;
-            Selection.OnResourcePing -= OnPing;
-
-            dropTarget.Destroy();
-        }
-
-        private void OnEditorUpdate()
-        {
-            bool isRenameInProgress = inProgressRenameElement != null;
-
-            if (HasContentFocus)
-            {
-                if (!isRenameInProgress)
-                {
-                    if (Input.IsButtonHeld(ButtonCode.LeftControl) || Input.IsButtonHeld(ButtonCode.RightControl))
-                    {
-                        if (Input.IsButtonUp(ButtonCode.C))
-                        {
-                            CopySelection();
-                        }
-                        else if (Input.IsButtonUp(ButtonCode.X))
-                        {
-                            CutSelection();
-                        }
-                        else if (Input.IsButtonUp(ButtonCode.D))
-                        {
-                            DuplicateSelection();
-                        }
-                        else if (Input.IsButtonUp(ButtonCode.V))
-                        {
-                            PasteToSelection();
-                        }
-                    }
-
-                    if (Input.IsButtonDown(ButtonCode.Return))
-                    {
-                        if (selectionPaths.Count == 1)
-                        {
-                            LibraryEntry entry = ProjectLibrary.GetEntry(selectionPaths[0]);
-                            if (entry != null && entry.Type == LibraryEntryType.Directory)
-                            {
-                                EnterDirectory(entry.Path);
-                            }
-                        }
-                    }
-                    else if (Input.IsButtonDown(ButtonCode.Back))
-                    {
-                        LibraryEntry entry = ProjectLibrary.GetEntry(currentDirectory);
-                        if (entry != null && entry.Parent != null)
-                        {
-                            EnterDirectory(entry.Parent.Path);
-                        }
-                    }
-                    else if (Input.IsButtonDown(ButtonCode.Up))
-                    {
-                        MoveSelection(MoveDirection.Up);
-                    }
-                    else if (Input.IsButtonDown(ButtonCode.Down))
-                    {
-                        MoveSelection(MoveDirection.Down);
-                    }
-                    else if (Input.IsButtonDown(ButtonCode.Left))
-                    {
-                        MoveSelection(MoveDirection.Left);
-                    }
-                    else if (Input.IsButtonDown(ButtonCode.Right))
-                    {
-                        MoveSelection(MoveDirection.Right);
-                    }
-                    else if (Input.IsButtonDown(ButtonCode.F2))
-                    {
-                        RenameSelection();
-                    }
-                    else if (Input.IsButtonDown(ButtonCode.Delete))
-                    {
-                        DeleteSelection();
-                    }
-                }
-                else
-                {
-                    if (Input.IsButtonDown(ButtonCode.Return))
-                    {
-                        string newName = inProgressRenameElement.GetRenamedName();
-
-                        string originalPath = inProgressRenameElement.path;
-                        originalPath = originalPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
-
-                        string newPath = Path.GetDirectoryName(originalPath);
-                        string newNameWithExtension = newName + Path.GetExtension(originalPath);
-                        newPath = Path.Combine(newPath, newNameWithExtension);
-
-                        bool renameOK = true;
-                        if (!PathEx.IsValidFileName(newName))
-                        {
-                            DialogBox.Open(new LocEdString("Error"), new LocEdString("The name you specified is not a valid file name. Try another."), DialogBox.Type.OK);
-                            renameOK = false;
-                        }
-
-                        if (renameOK)
-                        {
-                            // Windows sees paths with dot at the end as if they didn't have it
-                            // so remove the dot to ensure the project library does the same
-                            string trimmedNewPath = newPath.TrimEnd('.');
-
-                            if (originalPath != trimmedNewPath && ProjectLibrary.Exists(trimmedNewPath))
-                            {
-                                DialogBox.Open(new LocEdString("Error"), new LocEdString("File/folder with that name already exists in this folder."), DialogBox.Type.OK);
-                                renameOK = false;
-                            }
-                        }
-
-                        if (renameOK)
-                        {
-                            ProjectLibrary.Rename(originalPath, newNameWithExtension);
-                            StopRename();
-                        }
-                    }
-                    else if (Input.IsButtonDown(ButtonCode.Escape))
-                    {
-                        StopRename();
-                    }
-                }
-            }
-            else
-            {
-                if (isRenameInProgress)
-                    StopRename();
-            }
-
-            if (autoScrollAmount != 0)
-            {
-                Rect2I contentBounds = contentScrollArea.ContentBounds;
-                float scrollPct = autoScrollAmount / (float)contentBounds.height;
-
-                contentScrollArea.VerticalScroll += scrollPct * Time.FrameDelta;
-            }
-
-            if (requiresRefresh)
-                Refresh();
-
-            dropTarget.Update();
-            content.Update();
-        }
-
-        /// <inheritdoc/>
-        protected override LocString GetDisplayName()
-        {
-            return new LocEdString("Library");
-        }
-
-        /// <inheritdoc/>
-        protected override void WindowResized(int width, int height)
-        {
-            base.WindowResized(width, height);
-
-            Refresh();
-
-            dropTarget.Bounds = GetScrollAreaBounds();
-        }
-
-        /// <summary>
-        /// Attempts to find a resource tile element at the specified coordinates.
-        /// </summary>
-        /// <param name="windowPos">Coordinates relative to the window.</param>
-        /// <returns>True if found an entry, false otherwise.</returns>
-        private LibraryGUIEntry FindElementAt(Vector2I windowPos)
-        {
-            Vector2I scrollPos = WindowToScrollAreaCoords(windowPos);
-
-            return content.FindElementAt(scrollPos);
-        }
-
-        /// <summary>
-        /// Clears hover highlight from the currently hovered over element.
-        /// </summary>
-        private void ClearHoverHighlight()
-        {
-            content.MarkAsHovered(hoverHighlightPath, false);
-            hoverHighlightPath = "";
-        }
-
-        /// <summary>
-        /// Pings an element at the specified path, displaying and highlighting it in the window.
-        /// </summary>
-        /// <param name="path">Project library path to the element.</param>
-        public void Ping(string path)
-        {
-            content.MarkAsPinged(pingPath, false);
-            pingPath = path;
-            content.MarkAsPinged(pingPath, true);
-        }
-
-        /// <summary>
-        /// Resets the library window to initial state.
-        /// </summary>
-        public void Reset()
-        {
-            currentDirectory = ProjectLibrary.Root.Path;
-            selectionAnchorStart = -1;
-            selectionAnchorEnd = -1;
-            selectionPaths.Clear();
-            pingPath = "";
-            hoverHighlightPath = "";
-
-            Refresh();
-        }
-
-        /// <summary>
-        /// Deselects all selected elements.
-        /// </summary>
-        /// <param name="onlyInternal">If true, do not update the global <see cref="Selection"/>, instead the operation
-        ///                            will be contained to the library window internally.</param>
-        internal void DeselectAll(bool onlyInternal = false)
-        {
-            SetSelection(new List<string>(), onlyInternal);
-            selectionAnchorStart = -1;
-            selectionAnchorEnd = -1;
-        }
-
-        /// <summary>
-        /// Select an element at the specified path. If control or shift keys are pressed during this operations multiple 
-        /// elements can be selected.
-        /// </summary>
-        /// <param name="path">Project library path to the element.</param>
-        internal void Select(string path)
-        {
-            LibraryGUIEntry entry;
-            if (!content.TryGetEntry(path, out entry))
-                return;
-
-            bool ctrlDown = Input.IsButtonHeld(ButtonCode.LeftControl) || Input.IsButtonHeld(ButtonCode.RightControl);
-            bool shiftDown = Input.IsButtonHeld(ButtonCode.LeftShift) || Input.IsButtonHeld(ButtonCode.RightShift);
-
-            if (shiftDown)
-            {
-                if (selectionAnchorStart != -1 && selectionAnchorStart < content.Entries.Length)
-                {
-                    int start = Math.Min(entry.index, selectionAnchorStart);
-                    int end = Math.Max(entry.index, selectionAnchorStart);
-
-                    List<string> newSelection = new List<string>();
-                    for(int i = start; i <= end; i++)
-                        newSelection.Add(content.Entries[i].path);
-
-                    SetSelection(newSelection);
-                    selectionAnchorEnd = entry.index;
-                }
-                else
-                {
-                    SetSelection(new List<string>() {path});
-                    selectionAnchorStart = entry.index;
-                    selectionAnchorEnd = entry.index;
-                }
-            }
-            else if (ctrlDown)
-            {
-                List<string> newSelection = new List<string>(selectionPaths);
-
-                if (selectionPaths.Contains(path))
-                {
-                    newSelection.Remove(path);
-                    if (newSelection.Count == 0)
-                        DeselectAll();
-                    else
-                    {
-                        if (selectionAnchorStart == entry.index)
-                        {
-                            LibraryGUIEntry newAnchorEntry;
-                            if (!content.TryGetEntry(newSelection[0], out newAnchorEntry))
-                                selectionAnchorStart = -1;
-                            else
-                                selectionAnchorStart = newAnchorEntry.index;
-                        }
-
-                        if (selectionAnchorEnd == entry.index)
-                        {
-                            LibraryGUIEntry newAnchorEntry;
-                            if (!content.TryGetEntry(newSelection[newSelection.Count - 1], out newAnchorEntry))
-                                selectionAnchorEnd = -1;
-                            else
-                                selectionAnchorEnd = newAnchorEntry.index;
-                        }
-
-                        SetSelection(newSelection);
-                    }
-                }
-                else
-                {
-                    newSelection.Add(path);
-                    SetSelection(newSelection);
-                    selectionAnchorEnd = entry.index;
-                }
-            }
-            else
-            {
-                SetSelection(new List<string>() {path});
-
-                selectionAnchorStart = entry.index;
-                selectionAnchorEnd = entry.index;
-            }
-        }
-
-        /// <summary>
-        /// Selects a new element in the specified direction from the currently selected element. If shift or control are
-        /// held during this operation, the selected object will be added to existing selection. If no element is selected
-        /// the first or last element will be selected depending on direction.
-        /// </summary>
-        /// <param name="dir">Direction to move from the currently selected element.</param>
-        internal void MoveSelection(MoveDirection dir)
-        {
-            string newPath = "";
-
-            if (selectionPaths.Count == 0 || selectionAnchorEnd == -1)
-            {
-                // Nothing is selected so we arbitrarily select first or last element
-                if (content.Entries.Length > 0)
-                {
-                    switch (dir)
-                    {
-                        case MoveDirection.Left:
-                        case MoveDirection.Up:
-                            newPath = content.Entries[content.Entries.Length - 1].path;
-                            break;
-                        case MoveDirection.Right:
-                        case MoveDirection.Down:
-                            newPath = content.Entries[0].path;
-                            break;
-                    }
-                }
-            }
-            else
-            {
-                switch (dir)
-                {
-                    case MoveDirection.Left:
-                        if (selectionAnchorEnd - 1 >= 0)
-                            newPath = content.Entries[selectionAnchorEnd - 1].path;
-                        break;
-                    case MoveDirection.Up:
-                        if (selectionAnchorEnd - content.ElementsPerRow >= 0)
-                            newPath = content.Entries[selectionAnchorEnd - content.ElementsPerRow].path;
-                        break;
-                    case MoveDirection.Right:
-                        if (selectionAnchorEnd + 1 < content.Entries.Length)
-                            newPath = content.Entries[selectionAnchorEnd + 1].path;
-                        break;
-                    case MoveDirection.Down:
-                        if (selectionAnchorEnd + content.ElementsPerRow < content.Entries.Length)
-                            newPath = content.Entries[selectionAnchorEnd + content.ElementsPerRow].path;
-                        break;
-                }
-            }
-
-            if (!string.IsNullOrEmpty(newPath))
-            {
-                Select(newPath);
-                ScrollToEntry(newPath);
-            }
-        }
-
-        /// <summary>
-        /// Selects a set of elements based on the provided paths.
-        /// </summary>
-        /// <param name="paths">Project library paths of the elements to select.</param>
-        /// <param name="onlyInternal">If true, do not update the global <see cref="Selection"/>, instead the operation
-        ///                            will be contained to the library window internally.</param>
-        internal void SetSelection(List<string> paths, bool onlyInternal = false)
-        {
-            if (selectionPaths != null)
-            {
-                foreach (var path in selectionPaths)
-                    content.MarkAsSelected(path, false);
-            }
-
-            selectionPaths = paths;
-            Ping("");
-
-            if (selectionPaths != null)
-            {
-                foreach (var path in selectionPaths)
-                    content.MarkAsSelected(path, true);
-            }
-
-            StopRename();
-
-            if (!onlyInternal)
-            {
-                if (selectionPaths != null)
-                    Selection.ResourcePaths = selectionPaths.ToArray();
-                else
-                    Selection.ResourcePaths = new string[0];
-            }
-        }
-
-        /// <summary>
-        /// Changes the active directory to the provided directory. Current contents of the window will be cleared and
-        /// instead contents of the new directory will be displayed.
-        /// </summary>
-        /// <param name="directory">Project library path to the directory.</param>
-        internal void EnterDirectory(string directory)
-        {
-            currentDirectory = directory;
-            DeselectAll(true);
-
-            Refresh();
-        }
-
-        /// <summary>
-        /// Marks the provided set of elements for a cut operation. Cut elements can be moved to a new location by calling
-        /// <see cref="Paste"/>.
-        /// </summary>
-        /// <param name="sourcePaths">Project library paths of the elements to cut.</param>
-        internal void Cut(IEnumerable<string> sourcePaths)
-        {
-            foreach (var path in cutPaths)
-                content.MarkAsCut(path, false);
-
-            cutPaths.Clear();
-            cutPaths.AddRange(sourcePaths);
-
-            foreach (var path in cutPaths)
-                content.MarkAsCut(path, true);
-
-            copyPaths.Clear();
-        }
-
-        /// <summary>
-        /// Marks the provided set of elements for a copy operation. You can copy the elements by calling <see cref="Paste"/>.
-        /// </summary>
-        /// <param name="sourcePaths">Project library paths of the elements to copy.</param>
-        internal void Copy(IEnumerable<string> sourcePaths)
-        {
-            copyPaths.Clear();
-            copyPaths.AddRange(sourcePaths);
-
-            foreach (var path in cutPaths)
-                content.MarkAsCut(path, false);
-
-            cutPaths.Clear();
-        }
-       
-        /// <summary>
-        /// Duplicates the provided set of elements.
-        /// </summary>
-        /// <param name="sourcePaths">Project library paths of the elements to duplicate.</param>
-        internal void Duplicate(IEnumerable<string> sourcePaths)
-        {
-            foreach (var source in sourcePaths)
-            {
-                if (Directory.Exists(source))
-                    DirectoryEx.Copy(source, LibraryUtility.GetUniquePath(source));
-                else if (File.Exists(source))
-                    FileEx.Copy(source, LibraryUtility.GetUniquePath(source));
-
-                ProjectLibrary.Refresh();
-            }
-        }
-
-        /// <summary>
-        /// Performs a cut or copy operations on the elements previously marked by calling <see cref="Cut"/> or
-        /// <see cref="Copy"/>.
-        /// </summary>
-        /// <param name="destinationFolder">Project library folder into which to move/copy the elements.</param>
-        internal void Paste(string destinationFolder)
-        {
-            if (copyPaths.Count > 0)
-            {
-                for (int i = 0; i < copyPaths.Count; i++)
-                {
-                    string destination = Path.Combine(destinationFolder, PathEx.GetTail(copyPaths[i]));
-
-                    if (Directory.Exists(copyPaths[i]))
-                        DirectoryEx.Copy(copyPaths[i], LibraryUtility.GetUniquePath(destination));
-                    else if (File.Exists(copyPaths[i]))
-                        FileEx.Copy(copyPaths[i], LibraryUtility.GetUniquePath(destination));
-                }
-
-                ProjectLibrary.Refresh();
-            }
-            else if (cutPaths.Count > 0)
-            {
-                for (int i = 0; i < cutPaths.Count; i++)
-                {
-                    string destination = Path.Combine(destinationFolder, PathEx.GetTail(cutPaths[i]));
-
-                    if (Directory.Exists(cutPaths[i]))
-                        DirectoryEx.Move(cutPaths[i], LibraryUtility.GetUniquePath(destination));
-                    else if (File.Exists(cutPaths[i]))
-                        FileEx.Move(cutPaths[i], LibraryUtility.GetUniquePath(destination));
-                }
-
-                cutPaths.Clear();
-                ProjectLibrary.Refresh();
-            }
-        }
-
-        /// <summary>
-        /// Scrolls the contents GUI area so that the element at the specified path becomes visible.
-        /// </summary>
-        /// <param name="path">Project library path to the element.</param>
-        private void ScrollToEntry(string path)
-        {
-            LibraryGUIEntry entryGUI;
-            if (!content.TryGetEntry(path, out entryGUI))
-                return;
-
-            Rect2I entryBounds = entryGUI.Bounds;
-
-            Rect2I contentBounds = contentScrollArea.Layout.Bounds;
-            Rect2I windowEntryBounds = entryBounds;
-            windowEntryBounds.x += contentBounds.x;
-            windowEntryBounds.y += contentBounds.y;
-
-            Rect2I scrollAreaBounds = contentScrollArea.Bounds;
-            bool requiresScroll = windowEntryBounds.y < scrollAreaBounds.y ||
-                                  (windowEntryBounds.y + windowEntryBounds.height) > (scrollAreaBounds.y + scrollAreaBounds.height);
-
-            if (!requiresScroll)
-                return;
-
-            int scrollableSize = contentBounds.height - scrollAreaBounds.height;
-            float percent = (((entryBounds.y + entryBounds.height * 0.5f) - scrollAreaBounds.height * 0.5f) / (float)scrollableSize);
-
-            percent = MathEx.Clamp01(percent);
-            contentScrollArea.VerticalScroll = percent;
-        }
-
-        /// <summary>
-        /// Rebuilds the library window GUI. Should be called any time the active folder or contents change.
-        /// </summary>
-        private void Refresh()
-        {
-            requiresRefresh = false;
-
-            LibraryEntry[] entriesToDisplay = new LibraryEntry[0];
-            if (IsSearchActive)
-            {
-                entriesToDisplay = ProjectLibrary.Search("*" + searchQuery + "*");
-            }
-            else
-            {
-                DirectoryEntry entry = ProjectLibrary.GetEntry(currentDirectory) as DirectoryEntry;
-                if (entry == null)
-                {
-                    currentDirectory = ProjectLibrary.Root.Path;
-                    entry = ProjectLibrary.GetEntry(currentDirectory) as DirectoryEntry;
-                }
-
-                if(entry != null)
-                    entriesToDisplay = entry.Children;
-            }
-
-            inProgressRenameElement = null;
-
-            RefreshDirectoryBar();
-
-            SortEntries(entriesToDisplay);
-            content.Refresh(viewType, entriesToDisplay);
-
-            foreach (var path in cutPaths)
-                content.MarkAsCut(path, true);
-
-            foreach (var path in selectionPaths)
-                content.MarkAsSelected(path, true);
-
-            content.MarkAsPinged(pingPath, true);
-
-            Rect2I contentBounds = content.Bounds;
-            Rect2I minimalBounds = GetScrollAreaBounds();
-            contentBounds.height = Math.Max(contentBounds.height, minimalBounds.height);
-
-            GUIButton catchAll = new GUIButton("", EditorStyles.Blank);
-            catchAll.Bounds = contentBounds;
-            catchAll.OnClick += OnCatchAllClicked;
-            catchAll.SetContextMenu(entryContextMenu);
-
-            content.Underlay.AddElement(catchAll);
-
-            Rect2I focusBounds = contentBounds; // Contents + Folder bar
-            Rect2I scrollBounds = contentScrollArea.Bounds;
-            focusBounds.x += scrollBounds.x;
-            focusBounds.y += scrollBounds.y;
-
-            Rect2I folderBarBounds = folderListLayout.Bounds;
-            focusBounds.y -= folderBarBounds.height;
-            focusBounds.height += folderBarBounds.height;
-
-            GUIButton focusCatcher = new GUIButton("", EditorStyles.Blank);
-            focusCatcher.OnFocusGained += () => hasContentFocus = true;
-            focusCatcher.OnFocusLost += () => hasContentFocus = false;
-            focusCatcher.Bounds = focusBounds;
-
-            GUIPanel focusPanel = GUI.AddPanel(3);
-            focusPanel.AddElement(focusCatcher);
-
-            UpdateDragSelection(dragSelectionEnd);
-        }
-
-        /// <summary>
-        /// Converts coordinates relative to the window into coordinates relative to the contents scroll area.
-        /// </summary>
-        /// <param name="windowPos">Coordinates relative to the window.</param>
-        /// <returns>Coordinates relative to the contents scroll area.</returns>
-        private Vector2I WindowToScrollAreaCoords(Vector2I windowPos)
-        {
-            Rect2I scrollBounds = contentScrollArea.Layout.Bounds;
-            Vector2I scrollPos = windowPos;
-            scrollPos.x -= scrollBounds.x;
-            scrollPos.y -= scrollBounds.y;
-
-            return scrollPos;
-        }
-
-        /// <summary>
-        /// Starts a drag operation that displays a selection outline allowing the user to select multiple entries at once.
-        /// </summary>
-        /// <param name="windowPos">Coordinates relative to the window where the drag originated.</param>
-        private void StartDragSelection(Vector2I windowPos)
-        {
-            isDraggingSelection = true;
-            dragSelectionStart = WindowToScrollAreaCoords(windowPos);
-            dragSelectionEnd = dragSelectionStart;
-        }
-
-        /// <summary>
-        /// Updates a selection outline drag operation by expanding the outline to the new location. Elements in the outline
-        /// are selected.
-        /// </summary>
-        /// <param name="windowPos">Coordinates of the pointer relative to the window.</param>
-        /// <returns>True if the selection outline drag is valid and was updated, false otherwise.</returns>
-        private bool UpdateDragSelection(Vector2I windowPos)
-        {
-            if (!isDraggingSelection)
-                return false;
-
-            if (dragSelection == null)
-            {
-                dragSelection = new GUITexture(null, true, EditorStyles.SelectionArea);
-                content.Overlay.AddElement(dragSelection);
-            }
-
-            dragSelectionEnd = WindowToScrollAreaCoords(windowPos);
-
-            Rect2I selectionArea = CalculateSelectionArea();
-            SelectInArea(selectionArea);
-            dragSelection.Bounds = selectionArea;
-
-            return true;
-        }
-
-        /// <summary>
-        /// Ends the selection outline drag operation. Elements in the outline are selected.
-        /// </summary>
-        /// <returns>True if the selection outline drag is valid and was ended, false otherwise.</returns>
-        private bool EndDragSelection()
-        {
-            if (!isDraggingSelection)
-                return false;
-
-            if (dragSelection != null)
-            {
-                dragSelection.Destroy();
-                dragSelection = null;
-            }
-
-            Rect2I selectionArea = CalculateSelectionArea();
-            SelectInArea(selectionArea);
-
-            isDraggingSelection = false;
-            return false;
-        }
-
-        /// <summary>
-        /// Calculates bounds of the selection area used for selection overlay drag operation, depending on drag starting
-        /// point coordinates and current drag coordinates.
-        /// </summary>
-        /// <returns>Bounds of the selection area, relative to the content scroll area.</returns>
-        private Rect2I CalculateSelectionArea()
-        {
-            Rect2I selectionArea = new Rect2I();
-            if (dragSelectionStart.x < dragSelectionEnd.x)
-            {
-                selectionArea.x = dragSelectionStart.x;
-                selectionArea.width = dragSelectionEnd.x - dragSelectionStart.x;
-            }
-            else
-            {
-                selectionArea.x = dragSelectionEnd.x;
-                selectionArea.width = dragSelectionStart.x - dragSelectionEnd.x;
-            }
-
-            if (dragSelectionStart.y < dragSelectionEnd.y)
-            {
-                selectionArea.y = dragSelectionStart.y;
-                selectionArea.height = dragSelectionEnd.y - dragSelectionStart.y;
-            }
-            else
-            {
-                selectionArea.y = dragSelectionEnd.y;
-                selectionArea.height = dragSelectionStart.y - dragSelectionEnd.y;
-            }
-
-            Rect2I maxBounds = contentScrollArea.Layout.Bounds;
-            maxBounds.x = 0;
-            maxBounds.y = 0;
-
-            selectionArea.Clip(maxBounds);
-
-            return selectionArea;
-        }
-
-        /// <summary>
-        /// Selects all elements overlapping the specified bounds.
-        /// </summary>
-        /// <param name="scrollBounds">Bounds relative to the content scroll area.</param>
-        private void SelectInArea(Rect2I scrollBounds)
-        {
-            LibraryGUIEntry[] foundElements = content.FindElementsOverlapping(scrollBounds);
-
-            if (foundElements.Length > 0)
-            {
-                selectionAnchorStart = foundElements[0].index;
-                selectionAnchorEnd = foundElements[foundElements.Length - 1].index;
-            }
-            else
-            {
-                selectionAnchorStart = -1;
-                selectionAnchorEnd = -1;
-            }
-
-            List<string> elementPaths = new List<string>();
-            foreach (var elem in foundElements)
-                elementPaths.Add(elem.path);
-
-            SetSelection(elementPaths);
-        }
-
-        /// <summary>
-        /// Updates GUI for the directory bar. Should be called whenever the active folder changes.
-        /// </summary>
-        private void RefreshDirectoryBar()
-        {
-            if (folderListLayout != null)
-            {
-                folderListLayout.Destroy();
-                folderListLayout = null;
-            }
-
-            folderListLayout = folderBarLayout.AddLayoutX();
-
-            string[] folders = null;
-            string[] fullPaths = null;
-
-            if (IsSearchActive)
-            {
-                folders = new[] {searchQuery};
-                fullPaths = new[] { searchQuery };
-            }
-            else
-            {
-                string currentDir = Path.Combine("Resources", currentDirectory);
-
-                folders = currentDir.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar },
-                    StringSplitOptions.RemoveEmptyEntries);
-
-                fullPaths = new string[folders.Length];
-                for (int i = 0; i < folders.Length; i++)
-                {
-                    if (i == 0)
-                        fullPaths[i] = "";
-                    else
-                        fullPaths[i] = Path.Combine(fullPaths[i - 1], folders[i]);
-                }
-            }
-
-            int availableWidth = folderBarLayout.Bounds.width - FOLDER_BUTTON_WIDTH * 2;
-            int numFolders = 0;
-            for (int i = folders.Length - 1; i >= 0; i--)
-            {
-                GUIButton folderButton = new GUIButton(folders[i]);
-
-                if (!IsSearchActive)
-                {
-                    string fullPath = fullPaths[i];
-                    folderButton.OnClick += () => OnFolderButtonClicked(fullPath);
-                }
-
-                GUIButton separator = new GUIButton("/", GUIOption.FixedWidth(FOLDER_SEPARATOR_WIDTH));
-
-                folderListLayout.InsertElement(0, separator);
-                folderListLayout.InsertElement(0, folderButton);
-                numFolders++;
-
-                Rect2I folderListBounds = folderListLayout.Bounds;
-                if (folderListBounds.width > availableWidth)
-                {
-                    if (numFolders > 2)
-                    {
-                        separator.Destroy();
-                        folderButton.Destroy();
-                        break;
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// Performs <see cref="Cut"/> operation on the currently selected elements.
-        /// </summary>
-        internal void CutSelection()
-        {
-            if (selectionPaths.Count > 0)
-                Cut(selectionPaths);
-        }
-
-        /// <summary>
-        /// Performs <see cref="Copy"/> operation on the currently selected elements.
-        /// </summary>
-        internal void CopySelection()
-        {
-            if (selectionPaths.Count > 0)
-                Copy(selectionPaths);
-        }
-
-        /// <summary>
-        /// Performs <see cref="Duplicate"/> operation on the currently selected elements.
-        /// </summary>
-        internal void DuplicateSelection()
-        {
-            if (selectionPaths.Count > 0)
-                Duplicate(selectionPaths);
-        }
-
-        /// <summary>
-        /// Performs <see cref="Paste"/> operation. Elements will be pasted in the currently selected directory (if any), or
-        /// the active directory otherwise.
-        /// </summary>
-        internal void PasteToSelection()
-        {
-            Paste(SelectedFolder);
-        }
-
-        /// <summary>
-        /// Starts a rename operation on the currently selected elements. If more than one elements are selected only the
-        /// first one will be affected.
-        /// </summary>
-        internal void RenameSelection()
-        {
-            if (selectionPaths.Count == 0)
-                return;
-
-            if (selectionPaths.Count > 1)
-            {
-                DeselectAll();
-                Select(selectionPaths[0]);
-            }
-
-            LibraryGUIEntry entry;
-            if (content.TryGetEntry(selectionPaths[0], out entry))
-            {
-                entry.StartRename();
-                inProgressRenameElement = entry;
-            }
-        }
-
-        /// <summary>
-        /// Deletes currently selected elements. User will be asked to confirm deletion via a dialog box.
-        /// </summary>
-        internal void DeleteSelection()
-        {
-            if (selectionPaths.Count == 0)
-                return;
-
-            DialogBox.Open(new LocEdString("Confirm deletion"), new LocEdString("Are you sure you want to delete the selected object(s)?"),
-                DialogBox.Type.YesNo,
-                type =>
-                {
-                    if (type == DialogBox.ResultType.Yes)
-                    {
-                        foreach (var path in selectionPaths)
-                        {
-                            ProjectLibrary.Delete(path);
-                        }
-
-                        DeselectAll();
-                        Refresh();
-                    }
-                });
-        }
-
-        /// <summary>
-        /// Stops the rename operation, if one is in progress on any element.
-        /// </summary>
-        internal void StopRename()
-        {
-            if (inProgressRenameElement != null)
-            {
-                inProgressRenameElement.StopRename();
-                inProgressRenameElement = null;
-            }
-        }
-
-        /// <summary>
-        /// Clears the search bar and refreshes the content area to display contents of the current directory.
-        /// </summary>
-        private void ClearSearch()
-        {
-            searchField.Value = "";
-            searchQuery = "";
-            Refresh();
-        }
-
-        /// <summary>
-        /// Opens the drop down options window that allows you to customize library window look and feel.
-        /// </summary>
-        private void OpenOptionsWindow()
-        {
-            Vector2I openPosition;
-            Rect2I buttonBounds = GUILayoutUtility.CalculateBounds(optionsButton, GUI);
-
-            openPosition.x = buttonBounds.x + buttonBounds.width / 2;
-            openPosition.y = buttonBounds.y + buttonBounds.height / 2;
-
-            LibraryDropDown dropDown = DropDownWindow.Open<LibraryDropDown>(this, openPosition);
-            dropDown.Initialize(this);
-        }
-
-        /// <summary>
-        /// Returns the content scroll area bounds.
-        /// </summary>
-        /// <returns>Bounds of the content scroll area, relative to the window.</returns>
-        private Rect2I GetScrollAreaBounds()
-        {
-            Rect2I bounds = GUI.Bounds;
-            Rect2I folderListBounds = folderListLayout.Bounds;
-            Rect2I searchBarBounds = searchBarLayout.Bounds;
-
-            bounds.y = folderListBounds.height + searchBarBounds.height;
-            bounds.height -= folderListBounds.height + searchBarBounds.height;
-
-            return bounds;
-        }
-
-        /// <summary>
-        /// Triggered when a project library entry was changed (added, modified, deleted).
-        /// </summary>
-        /// <param name="entry">Project library path of the changed entry.</param>
-        private void OnEntryChanged(string entry)
-        {
-            requiresRefresh = true;
-        }
-
-        /// <summary>
-        /// Triggered when the drag and drop operation is starting while over the content area. If drag operation is over
-        /// an element, element will be dragged.
-        /// </summary>
-        /// <param name="windowPos">Coordinates where the drag operation started, relative to the window.</param>
-        private void OnDragStart(Vector2I windowPos)
-        {
-            bool isRenameInProgress = inProgressRenameElement != null;
-            if (isRenameInProgress)
-                return;
-
-            LibraryGUIEntry underCursorElem = FindElementAt(windowPos);
-            if (underCursorElem == null)
-            {
-                StartDragSelection(windowPos);
-                return;
-            }
-
-            string resourceDir = ProjectLibrary.ResourceFolder;
-
-            string[] dragPaths = null;
-            if (selectionPaths.Count > 0)
-            {
-                foreach (var path in selectionPaths)
-                {
-                    if (path == underCursorElem.path)
-                    {
-                        dragPaths = new string[selectionPaths.Count];
-                        for (int i = 0; i < selectionPaths.Count; i++)
-                        {
-                            dragPaths[i] = Path.Combine(resourceDir, selectionPaths[i]);
-                        }
-
-                        break;
-                    }
-                }
-            }
-
-            if (dragPaths == null)
-                dragPaths = new[] { Path.Combine(resourceDir, underCursorElem.path) };
-
-            ResourceDragDropData dragDropData = new ResourceDragDropData(dragPaths);
-            DragDrop.StartDrag(dragDropData);
-        }
-
-        /// <summary>
-        /// Triggered when a pointer is moved while a drag operation is in progress.
-        /// </summary>
-        ///  <param name="windowPos">Coordinates of the pointer relative to the window.</param>
-        private void OnDragMove(Vector2I windowPos)
-        {
-            // Auto-scroll
-            Rect2I scrollAreaBounds = contentScrollArea.Bounds;
-            int scrollAreaTop = scrollAreaBounds.y;
-            int scrollAreaBottom = scrollAreaBounds.y + scrollAreaBounds.height;
-
-            if (windowPos.y > scrollAreaTop && windowPos.y <= (scrollAreaTop + DRAG_SCROLL_HEIGHT))
-                autoScrollAmount = -DRAG_SCROLL_AMOUNT_PER_SECOND;
-            else if (windowPos.y >= (scrollAreaBottom - DRAG_SCROLL_HEIGHT) && windowPos.y < scrollAreaBottom)
-                autoScrollAmount = DRAG_SCROLL_AMOUNT_PER_SECOND;
-            else
-                autoScrollAmount = 0;
-
-            // Selection box
-            if (UpdateDragSelection(windowPos))
-                return;
-
-            // Drag and drop (hover element under cursor)
-            LibraryGUIEntry underCursorElem = FindElementAt(windowPos);
-
-            if (underCursorElem == null)
-            {
-                ClearHoverHighlight();
-            }
-            else
-            {
-                if (underCursorElem.path != hoverHighlightPath)
-                {
-                    ClearHoverHighlight();
-
-                    hoverHighlightPath = underCursorElem.path;
-                    underCursorElem.MarkAsHovered(true);
-                }
-            }
-        }
-
-        /// <summary>
-        /// Triggered when a pointer leaves the drop targer while a drag operation is in progress.
-        /// </summary>
-        private void OnDragLeave()
-        {
-            ClearHoverHighlight();
-            autoScrollAmount = 0;
-        }
-
-        /// <summary>
-        /// Triggered when a resource drop operation finishes over the content area.
-        /// </summary>
-        /// <param name="windowPos">Coordinates of the pointer relative to the window where the drop operation finished
-        ///                         .</param>
-        /// <param name="paths">Paths of the dropped resources.</param>
-        private void OnResourceDragDropped(Vector2I windowPos, string[] paths)
-        {
-            ClearHoverHighlight();
-            autoScrollAmount = 0;
-
-            if (EndDragSelection())
-                return;
-
-            string resourceDir = ProjectLibrary.ResourceFolder;
-            string destinationFolder = Path.Combine(resourceDir, currentDirectory);
-
-            LibraryGUIEntry underCursorElement = FindElementAt(windowPos);
-            if (underCursorElement != null)
-            {
-                LibraryEntry entry = ProjectLibrary.GetEntry(underCursorElement.path);
-                if (entry != null && entry.Type == LibraryEntryType.Directory)
-                    destinationFolder = Path.Combine(resourceDir, entry.Path);
-            }
-
-            if (paths != null)
-            {
-                foreach (var path in paths)
-                {
-                    if (path == null)
-                        continue;
-
-                    string absolutePath = path;
-                    if (!Path.IsPathRooted(absolutePath))
-                        absolutePath = Path.Combine(resourceDir, path);
-
-                    if (string.IsNullOrEmpty(absolutePath))
-                        continue;
-
-                    if (PathEx.IsPartOf(destinationFolder, absolutePath) || PathEx.Compare(absolutePath, destinationFolder))
-                        continue;
-
-                    string pathTail = PathEx.GetTail(absolutePath);
-                    string destination = Path.Combine(destinationFolder, pathTail);
-
-                    if (PathEx.Compare(absolutePath, destination))
-                        continue;
-
-                    bool doCopy = !ProjectLibrary.Exists(absolutePath);
-
-                    if (Directory.Exists(path))
-                    {
-                        if (doCopy)
-                            DirectoryEx.Copy(absolutePath, LibraryUtility.GetUniquePath(destination));
-                        else
-                            DirectoryEx.Move(absolutePath, LibraryUtility.GetUniquePath(destination));
-                    }
-                    else if (File.Exists(path))
-                    {
-                        if (doCopy)
-                            FileEx.Copy(absolutePath, LibraryUtility.GetUniquePath(destination));
-                        else
-                            ProjectLibrary.Move(absolutePath, LibraryUtility.GetUniquePath(destination));
-                    }
-
-                    ProjectLibrary.Refresh();
-                }
-            }
-        }
-
-        /// <summary>
-        /// Triggered when a scene object drop operation finishes over the content area.
-        /// </summary>
-        /// <param name="windowPos">Coordinates of the pointer relative to the window where the drop operation finished
-        ///                         .</param>
-        /// <param name="objects">Dropped scene objects.</param>
-        private void OnSceneObjectDragDropped(Vector2I windowPos, SceneObject[] objects)
-        {
-            ClearHoverHighlight();
-            autoScrollAmount = 0;
-
-            if (EndDragSelection())
-                return;
-
-            string destinationFolder = currentDirectory;
-
-            LibraryGUIEntry underCursorElement = FindElementAt(windowPos);
-            if (underCursorElement != null)
-            {
-                LibraryEntry entry = ProjectLibrary.GetEntry(underCursorElement.path);
-                if (entry != null && entry.Type == LibraryEntryType.Directory)
-                    destinationFolder = entry.Path;
-            }
-
-            if (objects != null)
-            {
-                foreach (var so in objects)
-                {
-                    if (so == null)
-                        continue;
-
-                    Prefab newPrefab = new Prefab(so);
-
-                    string destination = LibraryUtility.GetUniquePath(Path.Combine(destinationFolder, so.Name + ".prefab"));
-                    ProjectLibrary.Create(newPrefab, destination);
-
-                    ProjectLibrary.Refresh();
-                }
-            }
-        }
-
-        /// <summary>
-        /// Triggered when a drag operation that originated from this window ends.
-        /// </summary>
-        /// <param name="windowPos">Coordinates of the pointer where the drag ended relative to the window </param>
-        private void OnDragEnd(Vector2I windowPos)
-        {
-            EndDragSelection();
-            autoScrollAmount = 0;
-        }
-
-        /// <summary>
-        /// Triggered when the global selection changes.
-        /// </summary>
-        /// <param name="sceneObjects">A set of newly selected scene objects.</param>
-        /// <param name="resourcePaths">A set of paths for newly selected resources.</param>
-        private void OnSelectionChanged(SceneObject[] sceneObjects, string[] resourcePaths)
-        {
-            if(sceneObjects.Length > 0)
-                DeselectAll(true);
-        }
-
-        /// <summary>
-        /// Triggered when a ping operation was triggered externally.
-        /// </summary>
-        /// <param name="path">Path to the resource to highlight.</param>
-        private void OnPing(string path)
-        {
-            Ping(path);
-        }
-
-        /// <summary>
-        /// Triggered when a folder on the directory bar was selected.
-        /// </summary>
-        /// <param name="path">Project library path to the folder to enter.</param>
-        private void OnFolderButtonClicked(string path)
-        {
-            EnterDirectory(path);
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on empty space between elements.
-        /// </summary>
-        private void OnCatchAllClicked()
-        {
-            DeselectAll();
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the home button on the directory bar, changing the active directory to
-        /// project library root.
-        /// </summary>
-        private void OnHomeClicked()
-        {
-            currentDirectory = ProjectLibrary.Root.Path;
-            Refresh();
-        }
-
-        /// <summary>
-        /// Triggered when the user clicks on the up button on the directory bar, changing the active directory to the
-        /// parent directory, unless already at project library root.
-        /// </summary>
-        private void OnUpClicked()
-        {
-            currentDirectory = currentDirectory.Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
-
-            if (!string.IsNullOrEmpty(currentDirectory))
-            {
-                string parent = Path.GetDirectoryName(currentDirectory);
-
-                currentDirectory = parent;
-                Refresh();
-            }
-        }
-
-        /// <summary>
-        /// Triggered when the user inputs new values into the search input box. Refreshes the contents so they display
-        /// elements matching the search text.
-        /// </summary>
-        /// <param name="newValue">Search box text.</param>
-        private void OnSearchChanged(string newValue)
-        {
-            searchQuery = newValue;
-            Refresh();
-        }
-
-        /// <summary>
-        /// Sorts the specified set of project library entries by type (folder or resource), followed by name.
-        /// </summary>
-        /// <param name="input">Set of project library entries to sort.</param>
-        private static void SortEntries(LibraryEntry[] input)
-        {
-            Array.Sort(input, (x, y) =>
-            {
-                if (x.Type == y.Type)
-                    return x.Name.CompareTo(y.Name);
-                else
-                    return x.Type == LibraryEntryType.File ? 1 : -1;
-            });
-        }
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.IO;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Types of resource tile display in the library window.
+    /// </summary>
+    internal enum ProjectViewType
+    {
+        Grid64, Grid48, Grid32, List16
+    }
+
+    /// <summary>
+    /// Editor window that displays all resources in the project. Resources can be displayed as a grid or list of icons,
+    /// with the ability to move, cut, copy, paste resources and folders, as well as supporting drag and drop and search
+    /// operations.
+    /// </summary>
+    internal sealed class LibraryWindow : EditorWindow
+    {
+        /// <summary>
+        /// Directions the selection cursor in library window can be moved in.
+        /// </summary>
+        internal enum MoveDirection
+        {
+            Up, Down, Left, Right
+        }
+
+        private const int DRAG_SCROLL_HEIGHT = 20;
+        private const int DRAG_SCROLL_AMOUNT_PER_SECOND = 100;
+        private const int FOLDER_BUTTON_WIDTH = 30;
+        private const int FOLDER_SEPARATOR_WIDTH = 10;
+        
+        private bool hasContentFocus = false;
+        private bool HasContentFocus { get { return HasFocus && hasContentFocus; } }
+
+        private string searchQuery;
+        private bool IsSearchActive { get { return !string.IsNullOrEmpty(searchQuery); } }
+
+        private ProjectViewType viewType = ProjectViewType.Grid32;
+
+        private bool requiresRefresh;
+        private string currentDirectory = "";
+        private List<string> selectionPaths = new List<string>();
+        private int selectionAnchorStart = -1;
+        private int selectionAnchorEnd = -1;
+        private string pingPath = "";
+        private string hoverHighlightPath = "";
+
+        private LibraryGUIContent content;
+        private GUIScrollArea contentScrollArea;
+        private GUILayoutX searchBarLayout;
+        private GUIButton optionsButton;
+        private GUILayout folderBarLayout;
+        private GUILayout folderListLayout;
+        private GUITextField searchField;
+        private GUITexture dragSelection;
+
+        private ContextMenu entryContextMenu;
+        private LibraryDropTarget dropTarget;
+
+        private int autoScrollAmount;
+        private bool isDraggingSelection;
+        private Vector2I dragSelectionStart;
+        private Vector2I dragSelectionEnd;
+
+        private LibraryGUIEntry inProgressRenameElement;
+
+        // Cut/Copy/Paste
+        private List<string> copyPaths = new List<string>();
+        private List<string> cutPaths = new List<string>();
+
+        /// <summary>
+        /// Determines how to display resource tiles in the library window.
+        /// </summary>
+        internal ProjectViewType ViewType
+        {
+            get { return viewType; }
+            set { viewType = value; Refresh(); }
+        }
+
+        /// <summary>
+        /// Returns a file or folder currently selected in the library window. If nothing is selected, returns the active
+        /// folder. Returned path is relative to project library resources folder.
+        /// </summary>
+        public string SelectedEntry
+        {
+            get
+            {
+                if (selectionPaths.Count == 1)
+                {
+                    LibraryEntry entry = ProjectLibrary.GetEntry(selectionPaths[0]);
+                    if (entry != null)
+                        return entry.Path;
+                }
+
+                return currentDirectory;
+            }
+        }
+
+        /// <summary>
+        /// Returns a folder currently selected in the library window. If no folder is selected, returns the active
+        /// folder. Returned path is relative to project library resources folder.
+        /// </summary>
+        public string SelectedFolder
+        {
+            get
+            {
+                DirectoryEntry selectedDirectory = null;
+                if (selectionPaths.Count == 1)
+                {
+                    LibraryEntry entry = ProjectLibrary.GetEntry(selectionPaths[0]);
+                    if (entry != null && entry.Type == LibraryEntryType.Directory)
+                        selectedDirectory = (DirectoryEntry) entry;
+                }
+
+                if (selectedDirectory != null)
+                    return selectedDirectory.Path;
+                
+                return currentDirectory;
+            }
+        }
+
+        /// <summary>
+        /// Returns the path to the folder currently displayed in the library window. Returned path is relative to project 
+        /// library resources folder.
+        /// </summary>
+        public string CurrentFolder
+        {
+            get { return currentDirectory; }
+        }
+
+        /// <summary>
+        /// Context menu that should open when user right clicks on the content area.
+        /// </summary>
+        internal ContextMenu ContextMenu
+        {
+            get { return entryContextMenu; }
+        }
+
+        /// <summary>
+        /// Opens the library window if not already open.
+        /// </summary>
+        [MenuItem("Windows/Library", ButtonModifier.CtrlAlt, ButtonCode.L, 6000)]
+        private static void OpenLibraryWindow()
+        {
+            OpenWindow<LibraryWindow>();
+        }
+
+        private void OnInitialize()
+        {
+            ProjectLibrary.OnEntryAdded += OnEntryChanged;
+            ProjectLibrary.OnEntryRemoved += OnEntryChanged;
+
+            GUILayoutY contentLayout = GUI.AddLayoutY();
+
+            searchBarLayout = contentLayout.AddLayoutX();
+            searchField = new GUITextField();
+            searchField.OnChanged += OnSearchChanged;
+
+            GUIContent clearIcon = new GUIContent(EditorBuiltin.GetLibraryWindowIcon(LibraryWindowIcon.Clear), 
+                new LocEdString("Clear"));
+            GUIButton clearSearchBtn = new GUIButton(clearIcon);
+            clearSearchBtn.OnClick += ClearSearch;
+            clearSearchBtn.SetWidth(40);
+
+            GUIContent optionsIcon = new GUIContent(EditorBuiltin.GetLibraryWindowIcon(LibraryWindowIcon.Options), 
+                new LocEdString("Options"));
+            optionsButton = new GUIButton(optionsIcon);
+            optionsButton.OnClick += OpenOptionsWindow;
+            optionsButton.SetWidth(40);
+            searchBarLayout.AddElement(searchField);
+            searchBarLayout.AddElement(clearSearchBtn);
+            searchBarLayout.AddElement(optionsButton);
+
+            folderBarLayout = contentLayout.AddLayoutX();
+
+            GUIContent homeIcon = new GUIContent(EditorBuiltin.GetLibraryWindowIcon(LibraryWindowIcon.Home), 
+                new LocEdString("Home"));
+            GUIButton homeButton = new GUIButton(homeIcon, GUIOption.FixedWidth(FOLDER_BUTTON_WIDTH));
+            homeButton.OnClick += OnHomeClicked;
+
+            GUIContent upIcon = new GUIContent(EditorBuiltin.GetLibraryWindowIcon(LibraryWindowIcon.Up), 
+                new LocEdString("Up"));
+            GUIButton upButton = new GUIButton(upIcon, GUIOption.FixedWidth(FOLDER_BUTTON_WIDTH));
+            upButton.OnClick += OnUpClicked;
+
+            folderBarLayout.AddElement(homeButton);
+            folderBarLayout.AddElement(upButton);
+            folderBarLayout.AddSpace(10);
+
+            contentScrollArea = new GUIScrollArea(GUIOption.FlexibleWidth(), GUIOption.FlexibleHeight());
+            contentLayout.AddElement(contentScrollArea);
+            contentLayout.AddFlexibleSpace();
+
+            entryContextMenu = LibraryMenu.CreateContextMenu(this);
+            content = new LibraryGUIContent(this, contentScrollArea);
+            
+            Reset();
+
+            dropTarget = new LibraryDropTarget(this);
+            dropTarget.Bounds = GetScrollAreaBounds();
+            dropTarget.OnStart += OnDragStart;
+            dropTarget.OnDrag += OnDragMove;
+            dropTarget.OnLeave += OnDragLeave;
+            dropTarget.OnDropResource += OnResourceDragDropped;
+            dropTarget.OnDropSceneObject += OnSceneObjectDragDropped;
+            dropTarget.OnEnd += OnDragEnd;
+
+            Selection.OnSelectionChanged += OnSelectionChanged;
+            Selection.OnResourcePing += OnPing;
+        }
+
+        private void OnDestroy()
+        {
+            Selection.OnSelectionChanged -= OnSelectionChanged;
+            Selection.OnResourcePing -= OnPing;
+
+            dropTarget.Destroy();
+        }
+
+        private void OnEditorUpdate()
+        {
+            bool isRenameInProgress = inProgressRenameElement != null;
+
+            if (HasContentFocus)
+            {
+                if (!isRenameInProgress)
+                {
+                    if (Input.IsButtonHeld(ButtonCode.LeftControl) || Input.IsButtonHeld(ButtonCode.RightControl))
+                    {
+                        if (Input.IsButtonUp(ButtonCode.C))
+                        {
+                            CopySelection();
+                        }
+                        else if (Input.IsButtonUp(ButtonCode.X))
+                        {
+                            CutSelection();
+                        }
+                        else if (Input.IsButtonUp(ButtonCode.D))
+                        {
+                            DuplicateSelection();
+                        }
+                        else if (Input.IsButtonUp(ButtonCode.V))
+                        {
+                            PasteToSelection();
+                        }
+                    }
+
+                    if (Input.IsButtonDown(ButtonCode.Return))
+                    {
+                        if (selectionPaths.Count == 1)
+                        {
+                            LibraryEntry entry = ProjectLibrary.GetEntry(selectionPaths[0]);
+                            if (entry != null && entry.Type == LibraryEntryType.Directory)
+                            {
+                                EnterDirectory(entry.Path);
+                            }
+                        }
+                    }
+                    else if (Input.IsButtonDown(ButtonCode.Back))
+                    {
+                        LibraryEntry entry = ProjectLibrary.GetEntry(currentDirectory);
+                        if (entry != null && entry.Parent != null)
+                        {
+                            EnterDirectory(entry.Parent.Path);
+                        }
+                    }
+                    else if (Input.IsButtonDown(ButtonCode.Up))
+                    {
+                        MoveSelection(MoveDirection.Up);
+                    }
+                    else if (Input.IsButtonDown(ButtonCode.Down))
+                    {
+                        MoveSelection(MoveDirection.Down);
+                    }
+                    else if (Input.IsButtonDown(ButtonCode.Left))
+                    {
+                        MoveSelection(MoveDirection.Left);
+                    }
+                    else if (Input.IsButtonDown(ButtonCode.Right))
+                    {
+                        MoveSelection(MoveDirection.Right);
+                    }
+                    else if (Input.IsButtonDown(ButtonCode.F2))
+                    {
+                        RenameSelection();
+                    }
+                    else if (Input.IsButtonDown(ButtonCode.Delete))
+                    {
+                        DeleteSelection();
+                    }
+                }
+                else
+                {
+                    if (Input.IsButtonDown(ButtonCode.Return))
+                    {
+                        string newName = inProgressRenameElement.GetRenamedName();
+
+                        string originalPath = inProgressRenameElement.path;
+                        originalPath = originalPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
+
+                        string newPath = Path.GetDirectoryName(originalPath);
+                        string newNameWithExtension = newName + Path.GetExtension(originalPath);
+                        newPath = Path.Combine(newPath, newNameWithExtension);
+
+                        bool renameOK = true;
+                        if (!PathEx.IsValidFileName(newName))
+                        {
+                            DialogBox.Open(new LocEdString("Error"), new LocEdString("The name you specified is not a valid file name. Try another."), DialogBox.Type.OK);
+                            renameOK = false;
+                        }
+
+                        if (renameOK)
+                        {
+                            // Windows sees paths with dot at the end as if they didn't have it
+                            // so remove the dot to ensure the project library does the same
+                            string trimmedNewPath = newPath.TrimEnd('.');
+
+                            if (originalPath != trimmedNewPath && ProjectLibrary.Exists(trimmedNewPath))
+                            {
+                                DialogBox.Open(new LocEdString("Error"), new LocEdString("File/folder with that name already exists in this folder."), DialogBox.Type.OK);
+                                renameOK = false;
+                            }
+                        }
+
+                        if (renameOK)
+                        {
+                            ProjectLibrary.Rename(originalPath, newNameWithExtension);
+                            StopRename();
+                        }
+                    }
+                    else if (Input.IsButtonDown(ButtonCode.Escape))
+                    {
+                        StopRename();
+                    }
+                }
+            }
+            else
+            {
+                if (isRenameInProgress)
+                    StopRename();
+            }
+
+            if (autoScrollAmount != 0)
+            {
+                Rect2I contentBounds = contentScrollArea.ContentBounds;
+                float scrollPct = autoScrollAmount / (float)contentBounds.height;
+
+                contentScrollArea.VerticalScroll += scrollPct * Time.FrameDelta;
+            }
+
+            if (requiresRefresh)
+                Refresh();
+
+            dropTarget.Update();
+            content.Update();
+        }
+
+        /// <inheritdoc/>
+        protected override LocString GetDisplayName()
+        {
+            return new LocEdString("Library");
+        }
+
+        /// <inheritdoc/>
+        protected override void WindowResized(int width, int height)
+        {
+            base.WindowResized(width, height);
+
+            Refresh();
+
+            dropTarget.Bounds = GetScrollAreaBounds();
+        }
+
+        /// <summary>
+        /// Attempts to find a resource tile element at the specified coordinates.
+        /// </summary>
+        /// <param name="windowPos">Coordinates relative to the window.</param>
+        /// <returns>True if found an entry, false otherwise.</returns>
+        private LibraryGUIEntry FindElementAt(Vector2I windowPos)
+        {
+            Vector2I scrollPos = WindowToScrollAreaCoords(windowPos);
+
+            return content.FindElementAt(scrollPos);
+        }
+
+        /// <summary>
+        /// Clears hover highlight from the currently hovered over element.
+        /// </summary>
+        private void ClearHoverHighlight()
+        {
+            content.MarkAsHovered(hoverHighlightPath, false);
+            hoverHighlightPath = "";
+        }
+
+        /// <summary>
+        /// Pings an element at the specified path, displaying and highlighting it in the window.
+        /// </summary>
+        /// <param name="path">Project library path to the element.</param>
+        public void Ping(string path)
+        {
+            content.MarkAsPinged(pingPath, false);
+            pingPath = path;
+            content.MarkAsPinged(pingPath, true);
+        }
+
+        /// <summary>
+        /// Resets the library window to initial state.
+        /// </summary>
+        public void Reset()
+        {
+            currentDirectory = ProjectLibrary.Root.Path;
+            selectionAnchorStart = -1;
+            selectionAnchorEnd = -1;
+            selectionPaths.Clear();
+            pingPath = "";
+            hoverHighlightPath = "";
+
+            Refresh();
+        }
+
+        /// <summary>
+        /// Deselects all selected elements.
+        /// </summary>
+        /// <param name="onlyInternal">If true, do not update the global <see cref="Selection"/>, instead the operation
+        ///                            will be contained to the library window internally.</param>
+        internal void DeselectAll(bool onlyInternal = false)
+        {
+            SetSelection(new List<string>(), onlyInternal);
+            selectionAnchorStart = -1;
+            selectionAnchorEnd = -1;
+        }
+
+        /// <summary>
+        /// Select an element at the specified path. If control or shift keys are pressed during this operations multiple 
+        /// elements can be selected.
+        /// </summary>
+        /// <param name="path">Project library path to the element.</param>
+        internal void Select(string path)
+        {
+            LibraryGUIEntry entry;
+            if (!content.TryGetEntry(path, out entry))
+                return;
+
+            bool ctrlDown = Input.IsButtonHeld(ButtonCode.LeftControl) || Input.IsButtonHeld(ButtonCode.RightControl);
+            bool shiftDown = Input.IsButtonHeld(ButtonCode.LeftShift) || Input.IsButtonHeld(ButtonCode.RightShift);
+
+            if (shiftDown)
+            {
+                if (selectionAnchorStart != -1 && selectionAnchorStart < content.Entries.Length)
+                {
+                    int start = Math.Min(entry.index, selectionAnchorStart);
+                    int end = Math.Max(entry.index, selectionAnchorStart);
+
+                    List<string> newSelection = new List<string>();
+                    for(int i = start; i <= end; i++)
+                        newSelection.Add(content.Entries[i].path);
+
+                    SetSelection(newSelection);
+                    selectionAnchorEnd = entry.index;
+                }
+                else
+                {
+                    SetSelection(new List<string>() {path});
+                    selectionAnchorStart = entry.index;
+                    selectionAnchorEnd = entry.index;
+                }
+            }
+            else if (ctrlDown)
+            {
+                List<string> newSelection = new List<string>(selectionPaths);
+
+                if (selectionPaths.Contains(path))
+                {
+                    newSelection.Remove(path);
+                    if (newSelection.Count == 0)
+                        DeselectAll();
+                    else
+                    {
+                        if (selectionAnchorStart == entry.index)
+                        {
+                            LibraryGUIEntry newAnchorEntry;
+                            if (!content.TryGetEntry(newSelection[0], out newAnchorEntry))
+                                selectionAnchorStart = -1;
+                            else
+                                selectionAnchorStart = newAnchorEntry.index;
+                        }
+
+                        if (selectionAnchorEnd == entry.index)
+                        {
+                            LibraryGUIEntry newAnchorEntry;
+                            if (!content.TryGetEntry(newSelection[newSelection.Count - 1], out newAnchorEntry))
+                                selectionAnchorEnd = -1;
+                            else
+                                selectionAnchorEnd = newAnchorEntry.index;
+                        }
+
+                        SetSelection(newSelection);
+                    }
+                }
+                else
+                {
+                    newSelection.Add(path);
+                    SetSelection(newSelection);
+                    selectionAnchorEnd = entry.index;
+                }
+            }
+            else
+            {
+                SetSelection(new List<string>() {path});
+
+                selectionAnchorStart = entry.index;
+                selectionAnchorEnd = entry.index;
+            }
+        }
+
+        /// <summary>
+        /// Selects a new element in the specified direction from the currently selected element. If shift or control are
+        /// held during this operation, the selected object will be added to existing selection. If no element is selected
+        /// the first or last element will be selected depending on direction.
+        /// </summary>
+        /// <param name="dir">Direction to move from the currently selected element.</param>
+        internal void MoveSelection(MoveDirection dir)
+        {
+            string newPath = "";
+
+            if (selectionPaths.Count == 0 || selectionAnchorEnd == -1)
+            {
+                // Nothing is selected so we arbitrarily select first or last element
+                if (content.Entries.Length > 0)
+                {
+                    switch (dir)
+                    {
+                        case MoveDirection.Left:
+                        case MoveDirection.Up:
+                            newPath = content.Entries[content.Entries.Length - 1].path;
+                            break;
+                        case MoveDirection.Right:
+                        case MoveDirection.Down:
+                            newPath = content.Entries[0].path;
+                            break;
+                    }
+                }
+            }
+            else
+            {
+                switch (dir)
+                {
+                    case MoveDirection.Left:
+                        if (selectionAnchorEnd - 1 >= 0)
+                            newPath = content.Entries[selectionAnchorEnd - 1].path;
+                        break;
+                    case MoveDirection.Up:
+                        if (selectionAnchorEnd - content.ElementsPerRow >= 0)
+                            newPath = content.Entries[selectionAnchorEnd - content.ElementsPerRow].path;
+                        break;
+                    case MoveDirection.Right:
+                        if (selectionAnchorEnd + 1 < content.Entries.Length)
+                            newPath = content.Entries[selectionAnchorEnd + 1].path;
+                        break;
+                    case MoveDirection.Down:
+                        if (selectionAnchorEnd + content.ElementsPerRow < content.Entries.Length)
+                            newPath = content.Entries[selectionAnchorEnd + content.ElementsPerRow].path;
+                        break;
+                }
+            }
+
+            if (!string.IsNullOrEmpty(newPath))
+            {
+                Select(newPath);
+                ScrollToEntry(newPath);
+            }
+        }
+
+        /// <summary>
+        /// Selects a set of elements based on the provided paths.
+        /// </summary>
+        /// <param name="paths">Project library paths of the elements to select.</param>
+        /// <param name="onlyInternal">If true, do not update the global <see cref="Selection"/>, instead the operation
+        ///                            will be contained to the library window internally.</param>
+        internal void SetSelection(List<string> paths, bool onlyInternal = false)
+        {
+            if (selectionPaths != null)
+            {
+                foreach (var path in selectionPaths)
+                    content.MarkAsSelected(path, false);
+            }
+
+            selectionPaths = paths;
+            Ping("");
+
+            if (selectionPaths != null)
+            {
+                foreach (var path in selectionPaths)
+                    content.MarkAsSelected(path, true);
+            }
+
+            StopRename();
+
+            if (!onlyInternal)
+            {
+                if (selectionPaths != null)
+                    Selection.ResourcePaths = selectionPaths.ToArray();
+                else
+                    Selection.ResourcePaths = new string[0];
+            }
+        }
+
+        /// <summary>
+        /// Changes the active directory to the provided directory. Current contents of the window will be cleared and
+        /// instead contents of the new directory will be displayed.
+        /// </summary>
+        /// <param name="directory">Project library path to the directory.</param>
+        internal void EnterDirectory(string directory)
+        {
+            currentDirectory = directory;
+            DeselectAll(true);
+
+            Refresh();
+        }
+
+        /// <summary>
+        /// Marks the provided set of elements for a cut operation. Cut elements can be moved to a new location by calling
+        /// <see cref="Paste"/>.
+        /// </summary>
+        /// <param name="sourcePaths">Project library paths of the elements to cut.</param>
+        internal void Cut(IEnumerable<string> sourcePaths)
+        {
+            foreach (var path in cutPaths)
+                content.MarkAsCut(path, false);
+
+            cutPaths.Clear();
+            cutPaths.AddRange(sourcePaths);
+
+            foreach (var path in cutPaths)
+                content.MarkAsCut(path, true);
+
+            copyPaths.Clear();
+        }
+
+        /// <summary>
+        /// Marks the provided set of elements for a copy operation. You can copy the elements by calling <see cref="Paste"/>.
+        /// </summary>
+        /// <param name="sourcePaths">Project library paths of the elements to copy.</param>
+        internal void Copy(IEnumerable<string> sourcePaths)
+        {
+            copyPaths.Clear();
+            copyPaths.AddRange(sourcePaths);
+
+            foreach (var path in cutPaths)
+                content.MarkAsCut(path, false);
+
+            cutPaths.Clear();
+        }
+       
+        /// <summary>
+        /// Duplicates the provided set of elements.
+        /// </summary>
+        /// <param name="sourcePaths">Project library paths of the elements to duplicate.</param>
+        internal void Duplicate(IEnumerable<string> sourcePaths)
+        {
+            foreach (var source in sourcePaths)
+            {
+                if (Directory.Exists(source))
+                    DirectoryEx.Copy(source, LibraryUtility.GetUniquePath(source));
+                else if (File.Exists(source))
+                    FileEx.Copy(source, LibraryUtility.GetUniquePath(source));
+
+                ProjectLibrary.Refresh();
+            }
+        }
+
+        /// <summary>
+        /// Performs a cut or copy operations on the elements previously marked by calling <see cref="Cut"/> or
+        /// <see cref="Copy"/>.
+        /// </summary>
+        /// <param name="destinationFolder">Project library folder into which to move/copy the elements.</param>
+        internal void Paste(string destinationFolder)
+        {
+            if (copyPaths.Count > 0)
+            {
+                for (int i = 0; i < copyPaths.Count; i++)
+                {
+                    string destination = Path.Combine(destinationFolder, PathEx.GetTail(copyPaths[i]));
+
+                    if (Directory.Exists(copyPaths[i]))
+                        DirectoryEx.Copy(copyPaths[i], LibraryUtility.GetUniquePath(destination));
+                    else if (File.Exists(copyPaths[i]))
+                        FileEx.Copy(copyPaths[i], LibraryUtility.GetUniquePath(destination));
+                }
+
+                ProjectLibrary.Refresh();
+            }
+            else if (cutPaths.Count > 0)
+            {
+                for (int i = 0; i < cutPaths.Count; i++)
+                {
+                    string destination = Path.Combine(destinationFolder, PathEx.GetTail(cutPaths[i]));
+
+                    if (Directory.Exists(cutPaths[i]))
+                        DirectoryEx.Move(cutPaths[i], LibraryUtility.GetUniquePath(destination));
+                    else if (File.Exists(cutPaths[i]))
+                        FileEx.Move(cutPaths[i], LibraryUtility.GetUniquePath(destination));
+                }
+
+                cutPaths.Clear();
+                ProjectLibrary.Refresh();
+            }
+        }
+
+        /// <summary>
+        /// Scrolls the contents GUI area so that the element at the specified path becomes visible.
+        /// </summary>
+        /// <param name="path">Project library path to the element.</param>
+        private void ScrollToEntry(string path)
+        {
+            LibraryGUIEntry entryGUI;
+            if (!content.TryGetEntry(path, out entryGUI))
+                return;
+
+            Rect2I entryBounds = entryGUI.Bounds;
+
+            Rect2I contentBounds = contentScrollArea.Layout.Bounds;
+            Rect2I windowEntryBounds = entryBounds;
+            windowEntryBounds.x += contentBounds.x;
+            windowEntryBounds.y += contentBounds.y;
+
+            Rect2I scrollAreaBounds = contentScrollArea.Bounds;
+            bool requiresScroll = windowEntryBounds.y < scrollAreaBounds.y ||
+                                  (windowEntryBounds.y + windowEntryBounds.height) > (scrollAreaBounds.y + scrollAreaBounds.height);
+
+            if (!requiresScroll)
+                return;
+
+            int scrollableSize = contentBounds.height - scrollAreaBounds.height;
+            float percent = (((entryBounds.y + entryBounds.height * 0.5f) - scrollAreaBounds.height * 0.5f) / (float)scrollableSize);
+
+            percent = MathEx.Clamp01(percent);
+            contentScrollArea.VerticalScroll = percent;
+        }
+
+        /// <summary>
+        /// Rebuilds the library window GUI. Should be called any time the active folder or contents change.
+        /// </summary>
+        private void Refresh()
+        {
+            requiresRefresh = false;
+
+            LibraryEntry[] entriesToDisplay = new LibraryEntry[0];
+            if (IsSearchActive)
+            {
+                entriesToDisplay = ProjectLibrary.Search("*" + searchQuery + "*");
+            }
+            else
+            {
+                DirectoryEntry entry = ProjectLibrary.GetEntry(currentDirectory) as DirectoryEntry;
+                if (entry == null)
+                {
+                    currentDirectory = ProjectLibrary.Root.Path;
+                    entry = ProjectLibrary.GetEntry(currentDirectory) as DirectoryEntry;
+                }
+
+                if(entry != null)
+                    entriesToDisplay = entry.Children;
+            }
+
+            inProgressRenameElement = null;
+
+            RefreshDirectoryBar();
+
+            SortEntries(entriesToDisplay);
+            content.Refresh(viewType, entriesToDisplay);
+
+            foreach (var path in cutPaths)
+                content.MarkAsCut(path, true);
+
+            foreach (var path in selectionPaths)
+                content.MarkAsSelected(path, true);
+
+            content.MarkAsPinged(pingPath, true);
+
+            Rect2I contentBounds = content.Bounds;
+            Rect2I minimalBounds = GetScrollAreaBounds();
+            contentBounds.height = Math.Max(contentBounds.height, minimalBounds.height);
+
+            GUIButton catchAll = new GUIButton("", EditorStyles.Blank);
+            catchAll.Bounds = contentBounds;
+            catchAll.OnClick += OnCatchAllClicked;
+            catchAll.SetContextMenu(entryContextMenu);
+
+            content.Underlay.AddElement(catchAll);
+
+            Rect2I focusBounds = contentBounds; // Contents + Folder bar
+            Rect2I scrollBounds = contentScrollArea.Bounds;
+            focusBounds.x += scrollBounds.x;
+            focusBounds.y += scrollBounds.y;
+
+            Rect2I folderBarBounds = folderListLayout.Bounds;
+            focusBounds.y -= folderBarBounds.height;
+            focusBounds.height += folderBarBounds.height;
+
+            GUIButton focusCatcher = new GUIButton("", EditorStyles.Blank);
+            focusCatcher.OnFocusGained += () => hasContentFocus = true;
+            focusCatcher.OnFocusLost += () => hasContentFocus = false;
+            focusCatcher.Bounds = focusBounds;
+
+            GUIPanel focusPanel = GUI.AddPanel(3);
+            focusPanel.AddElement(focusCatcher);
+
+            UpdateDragSelection(dragSelectionEnd);
+        }
+
+        /// <summary>
+        /// Converts coordinates relative to the window into coordinates relative to the contents scroll area.
+        /// </summary>
+        /// <param name="windowPos">Coordinates relative to the window.</param>
+        /// <returns>Coordinates relative to the contents scroll area.</returns>
+        private Vector2I WindowToScrollAreaCoords(Vector2I windowPos)
+        {
+            Rect2I scrollBounds = contentScrollArea.Layout.Bounds;
+            Vector2I scrollPos = windowPos;
+            scrollPos.x -= scrollBounds.x;
+            scrollPos.y -= scrollBounds.y;
+
+            return scrollPos;
+        }
+
+        /// <summary>
+        /// Starts a drag operation that displays a selection outline allowing the user to select multiple entries at once.
+        /// </summary>
+        /// <param name="windowPos">Coordinates relative to the window where the drag originated.</param>
+        private void StartDragSelection(Vector2I windowPos)
+        {
+            isDraggingSelection = true;
+            dragSelectionStart = WindowToScrollAreaCoords(windowPos);
+            dragSelectionEnd = dragSelectionStart;
+        }
+
+        /// <summary>
+        /// Updates a selection outline drag operation by expanding the outline to the new location. Elements in the outline
+        /// are selected.
+        /// </summary>
+        /// <param name="windowPos">Coordinates of the pointer relative to the window.</param>
+        /// <returns>True if the selection outline drag is valid and was updated, false otherwise.</returns>
+        private bool UpdateDragSelection(Vector2I windowPos)
+        {
+            if (!isDraggingSelection)
+                return false;
+
+            if (dragSelection == null)
+            {
+                dragSelection = new GUITexture(null, true, EditorStyles.SelectionArea);
+                content.Overlay.AddElement(dragSelection);
+            }
+
+            dragSelectionEnd = WindowToScrollAreaCoords(windowPos);
+
+            Rect2I selectionArea = CalculateSelectionArea();
+            SelectInArea(selectionArea);
+            dragSelection.Bounds = selectionArea;
+
+            return true;
+        }
+
+        /// <summary>
+        /// Ends the selection outline drag operation. Elements in the outline are selected.
+        /// </summary>
+        /// <returns>True if the selection outline drag is valid and was ended, false otherwise.</returns>
+        private bool EndDragSelection()
+        {
+            if (!isDraggingSelection)
+                return false;
+
+            if (dragSelection != null)
+            {
+                dragSelection.Destroy();
+                dragSelection = null;
+            }
+
+            Rect2I selectionArea = CalculateSelectionArea();
+            SelectInArea(selectionArea);
+
+            isDraggingSelection = false;
+            return false;
+        }
+
+        /// <summary>
+        /// Calculates bounds of the selection area used for selection overlay drag operation, depending on drag starting
+        /// point coordinates and current drag coordinates.
+        /// </summary>
+        /// <returns>Bounds of the selection area, relative to the content scroll area.</returns>
+        private Rect2I CalculateSelectionArea()
+        {
+            Rect2I selectionArea = new Rect2I();
+            if (dragSelectionStart.x < dragSelectionEnd.x)
+            {
+                selectionArea.x = dragSelectionStart.x;
+                selectionArea.width = dragSelectionEnd.x - dragSelectionStart.x;
+            }
+            else
+            {
+                selectionArea.x = dragSelectionEnd.x;
+                selectionArea.width = dragSelectionStart.x - dragSelectionEnd.x;
+            }
+
+            if (dragSelectionStart.y < dragSelectionEnd.y)
+            {
+                selectionArea.y = dragSelectionStart.y;
+                selectionArea.height = dragSelectionEnd.y - dragSelectionStart.y;
+            }
+            else
+            {
+                selectionArea.y = dragSelectionEnd.y;
+                selectionArea.height = dragSelectionStart.y - dragSelectionEnd.y;
+            }
+
+            Rect2I maxBounds = contentScrollArea.Layout.Bounds;
+            maxBounds.x = 0;
+            maxBounds.y = 0;
+
+            selectionArea.Clip(maxBounds);
+
+            return selectionArea;
+        }
+
+        /// <summary>
+        /// Selects all elements overlapping the specified bounds.
+        /// </summary>
+        /// <param name="scrollBounds">Bounds relative to the content scroll area.</param>
+        private void SelectInArea(Rect2I scrollBounds)
+        {
+            LibraryGUIEntry[] foundElements = content.FindElementsOverlapping(scrollBounds);
+
+            if (foundElements.Length > 0)
+            {
+                selectionAnchorStart = foundElements[0].index;
+                selectionAnchorEnd = foundElements[foundElements.Length - 1].index;
+            }
+            else
+            {
+                selectionAnchorStart = -1;
+                selectionAnchorEnd = -1;
+            }
+
+            List<string> elementPaths = new List<string>();
+            foreach (var elem in foundElements)
+                elementPaths.Add(elem.path);
+
+            SetSelection(elementPaths);
+        }
+
+        /// <summary>
+        /// Updates GUI for the directory bar. Should be called whenever the active folder changes.
+        /// </summary>
+        private void RefreshDirectoryBar()
+        {
+            if (folderListLayout != null)
+            {
+                folderListLayout.Destroy();
+                folderListLayout = null;
+            }
+
+            folderListLayout = folderBarLayout.AddLayoutX();
+
+            string[] folders = null;
+            string[] fullPaths = null;
+
+            if (IsSearchActive)
+            {
+                folders = new[] {searchQuery};
+                fullPaths = new[] { searchQuery };
+            }
+            else
+            {
+                string currentDir = Path.Combine("Resources", currentDirectory);
+
+                folders = currentDir.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar },
+                    StringSplitOptions.RemoveEmptyEntries);
+
+                fullPaths = new string[folders.Length];
+                for (int i = 0; i < folders.Length; i++)
+                {
+                    if (i == 0)
+                        fullPaths[i] = "";
+                    else
+                        fullPaths[i] = Path.Combine(fullPaths[i - 1], folders[i]);
+                }
+            }
+
+            int availableWidth = folderBarLayout.Bounds.width - FOLDER_BUTTON_WIDTH * 2;
+            int numFolders = 0;
+            for (int i = folders.Length - 1; i >= 0; i--)
+            {
+                GUIButton folderButton = new GUIButton(folders[i]);
+
+                if (!IsSearchActive)
+                {
+                    string fullPath = fullPaths[i];
+                    folderButton.OnClick += () => OnFolderButtonClicked(fullPath);
+                }
+
+                GUIButton separator = new GUIButton("/", GUIOption.FixedWidth(FOLDER_SEPARATOR_WIDTH));
+
+                folderListLayout.InsertElement(0, separator);
+                folderListLayout.InsertElement(0, folderButton);
+                numFolders++;
+
+                Rect2I folderListBounds = folderListLayout.Bounds;
+                if (folderListBounds.width > availableWidth)
+                {
+                    if (numFolders > 2)
+                    {
+                        separator.Destroy();
+                        folderButton.Destroy();
+                        break;
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Performs <see cref="Cut"/> operation on the currently selected elements.
+        /// </summary>
+        internal void CutSelection()
+        {
+            if (selectionPaths.Count > 0)
+                Cut(selectionPaths);
+        }
+
+        /// <summary>
+        /// Performs <see cref="Copy"/> operation on the currently selected elements.
+        /// </summary>
+        internal void CopySelection()
+        {
+            if (selectionPaths.Count > 0)
+                Copy(selectionPaths);
+        }
+
+        /// <summary>
+        /// Performs <see cref="Duplicate"/> operation on the currently selected elements.
+        /// </summary>
+        internal void DuplicateSelection()
+        {
+            if (selectionPaths.Count > 0)
+                Duplicate(selectionPaths);
+        }
+
+        /// <summary>
+        /// Performs <see cref="Paste"/> operation. Elements will be pasted in the currently selected directory (if any), or
+        /// the active directory otherwise.
+        /// </summary>
+        internal void PasteToSelection()
+        {
+            Paste(SelectedFolder);
+        }
+
+        /// <summary>
+        /// Starts a rename operation on the currently selected elements. If more than one elements are selected only the
+        /// first one will be affected.
+        /// </summary>
+        internal void RenameSelection()
+        {
+            if (selectionPaths.Count == 0)
+                return;
+
+            if (selectionPaths.Count > 1)
+            {
+                DeselectAll();
+                Select(selectionPaths[0]);
+            }
+
+            LibraryGUIEntry entry;
+            if (content.TryGetEntry(selectionPaths[0], out entry))
+            {
+                entry.StartRename();
+                inProgressRenameElement = entry;
+            }
+        }
+
+        /// <summary>
+        /// Deletes currently selected elements. User will be asked to confirm deletion via a dialog box.
+        /// </summary>
+        internal void DeleteSelection()
+        {
+            if (selectionPaths.Count == 0)
+                return;
+
+            DialogBox.Open(new LocEdString("Confirm deletion"), new LocEdString("Are you sure you want to delete the selected object(s)?"),
+                DialogBox.Type.YesNo,
+                type =>
+                {
+                    if (type == DialogBox.ResultType.Yes)
+                    {
+                        foreach (var path in selectionPaths)
+                        {
+                            ProjectLibrary.Delete(path);
+                        }
+
+                        DeselectAll();
+                        Refresh();
+                    }
+                });
+        }
+
+        /// <summary>
+        /// Stops the rename operation, if one is in progress on any element.
+        /// </summary>
+        internal void StopRename()
+        {
+            if (inProgressRenameElement != null)
+            {
+                inProgressRenameElement.StopRename();
+                inProgressRenameElement = null;
+            }
+        }
+
+        /// <summary>
+        /// Clears the search bar and refreshes the content area to display contents of the current directory.
+        /// </summary>
+        private void ClearSearch()
+        {
+            searchField.Value = "";
+            searchQuery = "";
+            Refresh();
+        }
+
+        /// <summary>
+        /// Opens the drop down options window that allows you to customize library window look and feel.
+        /// </summary>
+        private void OpenOptionsWindow()
+        {
+            Vector2I openPosition;
+            Rect2I buttonBounds = GUILayoutUtility.CalculateBounds(optionsButton, GUI);
+
+            openPosition.x = buttonBounds.x + buttonBounds.width / 2;
+            openPosition.y = buttonBounds.y + buttonBounds.height / 2;
+
+            LibraryDropDown dropDown = DropDownWindow.Open<LibraryDropDown>(this, openPosition);
+            dropDown.Initialize(this);
+        }
+
+        /// <summary>
+        /// Returns the content scroll area bounds.
+        /// </summary>
+        /// <returns>Bounds of the content scroll area, relative to the window.</returns>
+        private Rect2I GetScrollAreaBounds()
+        {
+            Rect2I bounds = GUI.Bounds;
+            Rect2I folderListBounds = folderListLayout.Bounds;
+            Rect2I searchBarBounds = searchBarLayout.Bounds;
+
+            bounds.y = folderListBounds.height + searchBarBounds.height;
+            bounds.height -= folderListBounds.height + searchBarBounds.height;
+
+            return bounds;
+        }
+
+        /// <summary>
+        /// Triggered when a project library entry was changed (added, modified, deleted).
+        /// </summary>
+        /// <param name="entry">Project library path of the changed entry.</param>
+        private void OnEntryChanged(string entry)
+        {
+            requiresRefresh = true;
+        }
+
+        /// <summary>
+        /// Triggered when the drag and drop operation is starting while over the content area. If drag operation is over
+        /// an element, element will be dragged.
+        /// </summary>
+        /// <param name="windowPos">Coordinates where the drag operation started, relative to the window.</param>
+        private void OnDragStart(Vector2I windowPos)
+        {
+            bool isRenameInProgress = inProgressRenameElement != null;
+            if (isRenameInProgress)
+                return;
+
+            LibraryGUIEntry underCursorElem = FindElementAt(windowPos);
+            if (underCursorElem == null)
+            {
+                StartDragSelection(windowPos);
+                return;
+            }
+
+            string resourceDir = ProjectLibrary.ResourceFolder;
+
+            string[] dragPaths = null;
+            if (selectionPaths.Count > 0)
+            {
+                foreach (var path in selectionPaths)
+                {
+                    if (path == underCursorElem.path)
+                    {
+                        dragPaths = new string[selectionPaths.Count];
+                        for (int i = 0; i < selectionPaths.Count; i++)
+                        {
+                            dragPaths[i] = Path.Combine(resourceDir, selectionPaths[i]);
+                        }
+
+                        break;
+                    }
+                }
+            }
+
+            if (dragPaths == null)
+                dragPaths = new[] { Path.Combine(resourceDir, underCursorElem.path) };
+
+            ResourceDragDropData dragDropData = new ResourceDragDropData(dragPaths);
+            DragDrop.StartDrag(dragDropData);
+        }
+
+        /// <summary>
+        /// Triggered when a pointer is moved while a drag operation is in progress.
+        /// </summary>
+        ///  <param name="windowPos">Coordinates of the pointer relative to the window.</param>
+        private void OnDragMove(Vector2I windowPos)
+        {
+            // Auto-scroll
+            Rect2I scrollAreaBounds = contentScrollArea.Bounds;
+            int scrollAreaTop = scrollAreaBounds.y;
+            int scrollAreaBottom = scrollAreaBounds.y + scrollAreaBounds.height;
+
+            if (windowPos.y > scrollAreaTop && windowPos.y <= (scrollAreaTop + DRAG_SCROLL_HEIGHT))
+                autoScrollAmount = -DRAG_SCROLL_AMOUNT_PER_SECOND;
+            else if (windowPos.y >= (scrollAreaBottom - DRAG_SCROLL_HEIGHT) && windowPos.y < scrollAreaBottom)
+                autoScrollAmount = DRAG_SCROLL_AMOUNT_PER_SECOND;
+            else
+                autoScrollAmount = 0;
+
+            // Selection box
+            if (UpdateDragSelection(windowPos))
+                return;
+
+            // Drag and drop (hover element under cursor)
+            LibraryGUIEntry underCursorElem = FindElementAt(windowPos);
+
+            if (underCursorElem == null)
+            {
+                ClearHoverHighlight();
+            }
+            else
+            {
+                if (underCursorElem.path != hoverHighlightPath)
+                {
+                    ClearHoverHighlight();
+
+                    hoverHighlightPath = underCursorElem.path;
+                    underCursorElem.MarkAsHovered(true);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Triggered when a pointer leaves the drop targer while a drag operation is in progress.
+        /// </summary>
+        private void OnDragLeave()
+        {
+            ClearHoverHighlight();
+            autoScrollAmount = 0;
+        }
+
+        /// <summary>
+        /// Triggered when a resource drop operation finishes over the content area.
+        /// </summary>
+        /// <param name="windowPos">Coordinates of the pointer relative to the window where the drop operation finished
+        ///                         .</param>
+        /// <param name="paths">Paths of the dropped resources.</param>
+        private void OnResourceDragDropped(Vector2I windowPos, string[] paths)
+        {
+            ClearHoverHighlight();
+            autoScrollAmount = 0;
+
+            if (EndDragSelection())
+                return;
+
+            string resourceDir = ProjectLibrary.ResourceFolder;
+            string destinationFolder = Path.Combine(resourceDir, currentDirectory);
+
+            LibraryGUIEntry underCursorElement = FindElementAt(windowPos);
+            if (underCursorElement != null)
+            {
+                LibraryEntry entry = ProjectLibrary.GetEntry(underCursorElement.path);
+                if (entry != null && entry.Type == LibraryEntryType.Directory)
+                    destinationFolder = Path.Combine(resourceDir, entry.Path);
+            }
+
+            if (paths != null)
+            {
+                foreach (var path in paths)
+                {
+                    if (path == null)
+                        continue;
+
+                    string absolutePath = path;
+                    if (!Path.IsPathRooted(absolutePath))
+                        absolutePath = Path.Combine(resourceDir, path);
+
+                    if (string.IsNullOrEmpty(absolutePath))
+                        continue;
+
+                    if (PathEx.IsPartOf(destinationFolder, absolutePath) || PathEx.Compare(absolutePath, destinationFolder))
+                        continue;
+
+                    string pathTail = PathEx.GetTail(absolutePath);
+                    string destination = Path.Combine(destinationFolder, pathTail);
+
+                    if (PathEx.Compare(absolutePath, destination))
+                        continue;
+
+                    bool doCopy = !ProjectLibrary.Exists(absolutePath);
+
+                    if (Directory.Exists(path))
+                    {
+                        if (doCopy)
+                            DirectoryEx.Copy(absolutePath, LibraryUtility.GetUniquePath(destination));
+                        else
+                            DirectoryEx.Move(absolutePath, LibraryUtility.GetUniquePath(destination));
+                    }
+                    else if (File.Exists(path))
+                    {
+                        if (doCopy)
+                            FileEx.Copy(absolutePath, LibraryUtility.GetUniquePath(destination));
+                        else
+                            ProjectLibrary.Move(absolutePath, LibraryUtility.GetUniquePath(destination));
+                    }
+
+                    ProjectLibrary.Refresh();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Triggered when a scene object drop operation finishes over the content area.
+        /// </summary>
+        /// <param name="windowPos">Coordinates of the pointer relative to the window where the drop operation finished
+        ///                         .</param>
+        /// <param name="objects">Dropped scene objects.</param>
+        private void OnSceneObjectDragDropped(Vector2I windowPos, SceneObject[] objects)
+        {
+            ClearHoverHighlight();
+            autoScrollAmount = 0;
+
+            if (EndDragSelection())
+                return;
+
+            string destinationFolder = currentDirectory;
+
+            LibraryGUIEntry underCursorElement = FindElementAt(windowPos);
+            if (underCursorElement != null)
+            {
+                LibraryEntry entry = ProjectLibrary.GetEntry(underCursorElement.path);
+                if (entry != null && entry.Type == LibraryEntryType.Directory)
+                    destinationFolder = entry.Path;
+            }
+
+            if (objects != null)
+            {
+                foreach (var so in objects)
+                {
+                    if (so == null)
+                        continue;
+
+                    Prefab newPrefab = new Prefab(so);
+
+                    string destination = LibraryUtility.GetUniquePath(Path.Combine(destinationFolder, so.Name + ".prefab"));
+                    ProjectLibrary.Create(newPrefab, destination);
+
+                    ProjectLibrary.Refresh();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Triggered when a drag operation that originated from this window ends.
+        /// </summary>
+        /// <param name="windowPos">Coordinates of the pointer where the drag ended relative to the window </param>
+        private void OnDragEnd(Vector2I windowPos)
+        {
+            EndDragSelection();
+            autoScrollAmount = 0;
+        }
+
+        /// <summary>
+        /// Triggered when the global selection changes.
+        /// </summary>
+        /// <param name="sceneObjects">A set of newly selected scene objects.</param>
+        /// <param name="resourcePaths">A set of paths for newly selected resources.</param>
+        private void OnSelectionChanged(SceneObject[] sceneObjects, string[] resourcePaths)
+        {
+            if(sceneObjects.Length > 0)
+                DeselectAll(true);
+        }
+
+        /// <summary>
+        /// Triggered when a ping operation was triggered externally.
+        /// </summary>
+        /// <param name="path">Path to the resource to highlight.</param>
+        private void OnPing(string path)
+        {
+            Ping(path);
+        }
+
+        /// <summary>
+        /// Triggered when a folder on the directory bar was selected.
+        /// </summary>
+        /// <param name="path">Project library path to the folder to enter.</param>
+        private void OnFolderButtonClicked(string path)
+        {
+            EnterDirectory(path);
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on empty space between elements.
+        /// </summary>
+        private void OnCatchAllClicked()
+        {
+            DeselectAll();
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the home button on the directory bar, changing the active directory to
+        /// project library root.
+        /// </summary>
+        private void OnHomeClicked()
+        {
+            currentDirectory = ProjectLibrary.Root.Path;
+            Refresh();
+        }
+
+        /// <summary>
+        /// Triggered when the user clicks on the up button on the directory bar, changing the active directory to the
+        /// parent directory, unless already at project library root.
+        /// </summary>
+        private void OnUpClicked()
+        {
+            currentDirectory = currentDirectory.Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
+
+            if (!string.IsNullOrEmpty(currentDirectory))
+            {
+                string parent = Path.GetDirectoryName(currentDirectory);
+
+                currentDirectory = parent;
+                Refresh();
+            }
+        }
+
+        /// <summary>
+        /// Triggered when the user inputs new values into the search input box. Refreshes the contents so they display
+        /// elements matching the search text.
+        /// </summary>
+        /// <param name="newValue">Search box text.</param>
+        private void OnSearchChanged(string newValue)
+        {
+            searchQuery = newValue;
+            Refresh();
+        }
+
+        /// <summary>
+        /// Sorts the specified set of project library entries by type (folder or resource), followed by name.
+        /// </summary>
+        /// <param name="input">Set of project library entries to sort.</param>
+        private static void SortEntries(LibraryEntry[] input)
+        {
+            Array.Sort(input, (x, y) =>
+            {
+                if (x.Type == y.Type)
+                    return x.Name.CompareTo(y.Name);
+                else
+                    return x.Type == LibraryEntryType.File ? 1 : -1;
+            });
+        }
+    }
+}

+ 256 - 256
MBansheeEditor/MenuItems.cs

@@ -1,256 +1,256 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Contains various menu item callbacks for the main editor menu bar.
-    /// </summary>
-    static class MenuItems
-    {
-        /// <summary>
-        /// Adds a camera component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Camera", 7050)]
-        private static void AddCamera()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                return;
-
-            UndoRedo.RecordSO(so, "Added a Camera component");
-            Camera cam = so.AddComponent<Camera>();
-            cam.Main = true;
-
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a renderable component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Renderable", 7049)]
-        private static void AddRenderable()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                return;
-
-            UndoRedo.RecordSO(so, "Added a Renderable component");
-            so.AddComponent<Renderable>();
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a point light component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Point light", 7048)]
-        private static void AddPointLight()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                return;
-
-            UndoRedo.RecordSO(so, "Added a Light component");
-            Light light = so.AddComponent<Light>();
-            light.Type = LightType.Point;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a spot light component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Spot light", 7047)]
-        private static void AddSpotLight()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                return;
-
-            UndoRedo.RecordSO(so, "Added a Light component");
-            Light light = so.AddComponent<Light>();
-            light.Type = LightType.Spot;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Adds a directional light component to the currently selected scene object.
-        /// </summary>
-        [MenuItem("Components/Directional light", 7046)]
-        private static void AddDirectionalLight()
-        {
-            SceneObject so = Selection.SceneObject;
-            if (so == null)
-                return;
-
-            UndoRedo.RecordSO(so, "Added a Light component");
-            Light light = so.AddComponent<Light>();
-            light.Type = LightType.Directional;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new empty scene object.
-        /// </summary>
-        [MenuItem("Scene Objects/Scene Object", 8051)]
-        [ToolbarItem("SceneObject", ToolbarIcon.NewSceneObject, "", 1601, true)]
-        private static void AddEmptySO()
-        {
-            SceneObject so = UndoRedo.CreateSO("SceneObject", "Created an empty SceneObject");
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a camera component.
-        /// </summary>
-        [MenuItem("Scene Objects/Camera", 8050)]
-        [ToolbarItem("Camera", ToolbarIcon.NewCamera, "", 1600, false)]
-        private static void AddCameraSO()
-        {
-            SceneObject so = UndoRedo.CreateSO("Camera", "Created a Camera");
-            Camera cam = so.AddComponent<Camera>();
-            cam.Main = true;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a renderable component.
-        /// </summary>
-        [MenuItem("Scene Objects/Renderable", 8049)]
-        [ToolbarItem("Renderable", ToolbarIcon.NewRenderable, "", 1599)]
-        private static void AddRenderableSO()
-        {
-            SceneObject so = UndoRedo.CreateSO("Renderable", "Created a Renderable");
-            so.AddComponent<Renderable>();
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a point light component.
-        /// </summary>
-        [MenuItem("Scene Objects/Point light", 8048)]
-        [ToolbarItem("Point light", ToolbarIcon.NewPointLight, "", 1598)]
-        private static void AddPointLightSO()
-        {
-            SceneObject so = UndoRedo.CreateSO("Point light", "Created a Light");
-            Light light = so.AddComponent<Light>();
-            light.Type = LightType.Point;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a spot light component.
-        /// </summary>
-        [MenuItem("Scene Objects/Spot light", 8047)]
-        [ToolbarItem("Spot light", ToolbarIcon.NewSpotLight, "", 1597)]
-        private static void AddSpotLightSO()
-        {
-            SceneObject so = UndoRedo.CreateSO("Spot light", "Created a Light");
-            Light light = so.AddComponent<Light>();
-            light.Type = LightType.Spot;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a directional light component.
-        /// </summary>
-        [MenuItem("Scene Objects/Directional light", 8046)]
-        [ToolbarItem("Directional light", ToolbarIcon.NewDirLight, "", 1596)]
-        private static void AddDirectionalLightSO()
-        {
-            SceneObject so = UndoRedo.CreateSO("Directional light", "Created a Light");
-            Light light = so.AddComponent<Light>();
-            light.Type = LightType.Directional;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a box primitive.
-        /// </summary>
-        [MenuItem("Scene Objects/3D primitives/Box", 8100)]
-        [ToolbarItem("Cube", ToolbarIcon.NewCube, "", 1700, true)]
-        private static void Add3DBox()
-        {
-            SceneObject so = UndoRedo.CreateSO("Box", "Created a box");
-            Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Box;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a sphere primitive.
-        /// </summary>
-        [MenuItem("Scene Objects/3D primitives/Sphere", 8099)]
-        [ToolbarItem("Sphere", ToolbarIcon.NewSphere, "", 1699)]
-        private static void Add3DSphere()
-        {
-            SceneObject so = UndoRedo.CreateSO("Sphere", "Created a sphere");
-            Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Sphere;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a cone primitive.
-        /// </summary>
-        [MenuItem("Scene Objects/3D primitives/Cone", 8098)]
-        [ToolbarItem("Cone", ToolbarIcon.NewCone, "", 1698)]
-        private static void Add3DCone()
-        {
-            SceneObject so = UndoRedo.CreateSO("Cone", "Created a cone");
-            Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Cone;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a quad primitive.
-        /// </summary>
-        [MenuItem("Scene Objects/3D primitives/Quad", 8097)]
-        [ToolbarItem("Quad", ToolbarIcon.NewQuad, "", 1697)]
-        private static void Add3DQuad()
-        {
-            SceneObject so = UndoRedo.CreateSO("Quad", "Created a quad");
-            Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Quad;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-
-        /// <summary>
-        /// Creates a new scene object with a disc primitive.
-        /// </summary>
-        [MenuItem("Scene Objects/3D primitives/Disc", 8096)]
-        private static void Add3DDisc()
-        {
-            SceneObject so = UndoRedo.CreateSO("Disc", "Created a disc");
-            Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Disc;
-
-            Selection.SceneObject = so;
-            EditorApplication.SetSceneDirty();
-        }
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Contains various menu item callbacks for the main editor menu bar.
+    /// </summary>
+    static class MenuItems
+    {
+        /// <summary>
+        /// Adds a camera component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Camera", 7050)]
+        private static void AddCamera()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            UndoRedo.RecordSO(so, "Added a Camera component");
+            Camera cam = so.AddComponent<Camera>();
+            cam.Main = true;
+
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a renderable component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Renderable", 7049)]
+        private static void AddRenderable()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            UndoRedo.RecordSO(so, "Added a Renderable component");
+            so.AddComponent<Renderable>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a point light component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Point light", 7048)]
+        private static void AddPointLight()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            UndoRedo.RecordSO(so, "Added a Light component");
+            Light light = so.AddComponent<Light>();
+            light.Type = LightType.Point;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a spot light component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Spot light", 7047)]
+        private static void AddSpotLight()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            UndoRedo.RecordSO(so, "Added a Light component");
+            Light light = so.AddComponent<Light>();
+            light.Type = LightType.Spot;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a directional light component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Directional light", 7046)]
+        private static void AddDirectionalLight()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                return;
+
+            UndoRedo.RecordSO(so, "Added a Light component");
+            Light light = so.AddComponent<Light>();
+            light.Type = LightType.Directional;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new empty scene object.
+        /// </summary>
+        [MenuItem("Scene Objects/Scene Object", 8051)]
+        [ToolbarItem("SceneObject", ToolbarIcon.NewSceneObject, "Creates a new empty scene object.", 1601, true)]
+        private static void AddEmptySO()
+        {
+            SceneObject so = UndoRedo.CreateSO("SceneObject", "New scene object");
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a camera component.
+        /// </summary>
+        [MenuItem("Scene Objects/Camera", 8050)]
+        [ToolbarItem("Camera", ToolbarIcon.NewCamera, "New camera", 1600, false)]
+        private static void AddCameraSO()
+        {
+            SceneObject so = UndoRedo.CreateSO("Camera", "Created a Camera");
+            Camera cam = so.AddComponent<Camera>();
+            cam.Main = true;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a renderable component.
+        /// </summary>
+        [MenuItem("Scene Objects/Renderable", 8049)]
+        [ToolbarItem("Renderable", ToolbarIcon.NewRenderable, "New renderable", 1599)]
+        private static void AddRenderableSO()
+        {
+            SceneObject so = UndoRedo.CreateSO("Renderable", "Created a Renderable");
+            so.AddComponent<Renderable>();
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a point light component.
+        /// </summary>
+        [MenuItem("Scene Objects/Point light", 8048)]
+        [ToolbarItem("Point light", ToolbarIcon.NewPointLight, "New point light", 1598)]
+        private static void AddPointLightSO()
+        {
+            SceneObject so = UndoRedo.CreateSO("Point light", "Created a Light");
+            Light light = so.AddComponent<Light>();
+            light.Type = LightType.Point;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a spot light component.
+        /// </summary>
+        [MenuItem("Scene Objects/Spot light", 8047)]
+        [ToolbarItem("Spot light", ToolbarIcon.NewSpotLight, "New spot light", 1597)]
+        private static void AddSpotLightSO()
+        {
+            SceneObject so = UndoRedo.CreateSO("Spot light", "Created a Light");
+            Light light = so.AddComponent<Light>();
+            light.Type = LightType.Spot;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a directional light component.
+        /// </summary>
+        [MenuItem("Scene Objects/Directional light", 8046)]
+        [ToolbarItem("Directional light", ToolbarIcon.NewDirLight, "New directional light.", 1596)]
+        private static void AddDirectionalLightSO()
+        {
+            SceneObject so = UndoRedo.CreateSO("Directional light", "Created a Light");
+            Light light = so.AddComponent<Light>();
+            light.Type = LightType.Directional;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a box primitive.
+        /// </summary>
+        [MenuItem("Scene Objects/3D primitives/Box", 8100)]
+        [ToolbarItem("Cube", ToolbarIcon.NewCube, "Creates a scene object with a box primitive.", 1700, true)]
+        private static void Add3DBox()
+        {
+            SceneObject so = UndoRedo.CreateSO("Box", "Created a box");
+            Renderable renderable = so.AddComponent<Renderable>();
+            renderable.Mesh = Builtin.Box;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a sphere primitive.
+        /// </summary>
+        [MenuItem("Scene Objects/3D primitives/Sphere", 8099)]
+        [ToolbarItem("Sphere", ToolbarIcon.NewSphere, "Creates a scene object with a sphere primitive.", 1699)]
+        private static void Add3DSphere()
+        {
+            SceneObject so = UndoRedo.CreateSO("Sphere", "Created a sphere");
+            Renderable renderable = so.AddComponent<Renderable>();
+            renderable.Mesh = Builtin.Sphere;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a cone primitive.
+        /// </summary>
+        [MenuItem("Scene Objects/3D primitives/Cone", 8098)]
+        [ToolbarItem("Cone", ToolbarIcon.NewCone, "Creates a scene object with a cone primitive.", 1698)]
+        private static void Add3DCone()
+        {
+            SceneObject so = UndoRedo.CreateSO("Cone", "Created a cone");
+            Renderable renderable = so.AddComponent<Renderable>();
+            renderable.Mesh = Builtin.Cone;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a quad primitive.
+        /// </summary>
+        [MenuItem("Scene Objects/3D primitives/Quad", 8097)]
+        [ToolbarItem("Quad", ToolbarIcon.NewQuad, "Creates a scene object with a quad primitive.", 1697)]
+        private static void Add3DQuad()
+        {
+            SceneObject so = UndoRedo.CreateSO("Quad", "Created a quad");
+            Renderable renderable = so.AddComponent<Renderable>();
+            renderable.Mesh = Builtin.Quad;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Creates a new scene object with a disc primitive.
+        /// </summary>
+        [MenuItem("Scene Objects/3D primitives/Disc", 8096)]
+        private static void Add3DDisc()
+        {
+            SceneObject so = UndoRedo.CreateSO("Disc", "Created a disc");
+            Renderable renderable = so.AddComponent<Renderable>();
+            renderable.Mesh = Builtin.Disc;
+
+            Selection.SceneObject = so;
+            EditorApplication.SetSceneDirty();
+        }
+    }
+}

+ 23 - 13
MBansheeEditor/Scene/SceneWindow.cs

@@ -118,19 +118,29 @@ namespace BansheeEditor
         {
             mainLayout = GUI.AddLayoutY();
 
-            GUIContent viewIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.View));
-            GUIContent moveIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.Move));
-            GUIContent rotateIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.Rotate));
-            GUIContent scaleIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.Scale));
-
-            GUIContent localIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.Local));
-            GUIContent worldIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.World));
-
-            GUIContent pivotIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.Pivot));
-            GUIContent centerIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.Center));
-
-            GUIContent moveSnapIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.MoveSnap));
-            GUIContent rotateSnapIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.RotateSnap));
+            GUIContent viewIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.View), 
+                new LocEdString("View"));
+            GUIContent moveIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.Move), 
+                new LocEdString("Move"));
+            GUIContent rotateIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.Rotate), 
+                new LocEdString("Rotate"));
+            GUIContent scaleIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.Scale), 
+                new LocEdString("Scale"));
+
+            GUIContent localIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.Local), 
+                new LocEdString("Local"));
+            GUIContent worldIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.World), 
+                new LocEdString("World"));
+
+            GUIContent pivotIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.Pivot), 
+                new LocEdString("Pivot"));
+            GUIContent centerIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.Center), 
+                new LocEdString("Center"));
+
+            GUIContent moveSnapIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.MoveSnap), 
+                new LocEdString("Move snap"));
+            GUIContent rotateSnapIcon = new GUIContent(EditorBuiltin.GetSceneWindowIcon(SceneWindowIcon.RotateSnap), 
+                new LocEdString("Rotate snap"));
 
             GUIToggleGroup handlesTG = new GUIToggleGroup();
             viewButton = new GUIToggle(viewIcon, handlesTG, EditorStyles.Button, GUIOption.FlexibleWidth(35));

+ 245 - 245
MBansheeEditor/UndoRedo.cs

@@ -1,245 +1,245 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Text;
-using System.Threading.Tasks;
-using BansheeEngine;
-
-namespace BansheeEditor
-{
-    /// <summary>
-    /// Provides functionality to undo or redo recently performed operations in the editor.
-    /// </summary>
-    public static class UndoRedo
-    {
-        /// <summary>
-        /// Returns the unique identifier of the command currently at the top of the undo stack.
-        /// </summary>
-        public static int TopCommandId
-        {
-            get { return Internal_GetTopCommandId(); }
-        }
-
-        /// <summary>
-        /// Executes the last command on the undo stack, undoing its operations.
-        /// </summary>
-        [MenuItem("Edit/Undo", 9500, true)]
-        [ToolbarItem("Undo", ToolbarIcon.Undo, "", 1900, true)]
-        public static void Undo()
-        {
-            Internal_Undo();
-        }
-
-        /// <summary>
-        /// Executes the last command on the redo stack (last command we called undo on), re-applying its operation.
-        /// </summary>
-        [MenuItem("Edit/Redo", 9499, true)]
-        [ToolbarItem("Redo", ToolbarIcon.Redo, "", 1899)]
-        public static void Redo()
-        {
-            Internal_Redo();
-        }
-
-        /// <summary>
-        /// Records a state of the entire scene object at a specific point and allows you to restore it to its original 
-        /// values as needed.
-        /// </summary>
-        /// <param name="so">Scene object to record.</param>
-        /// <param name="description">Optional description of what exactly the command does.</param>
-        public static void RecordSO(SceneObject so, string description = "")
-        {
-            if (so != null)
-                Internal_RecordSO(so.GetCachedPtr(), description);
-        }
-
-        /// <summary>
-        /// Creates new scene object(s) by cloning existing objects.
-        /// </summary>
-        /// <param name="so">Scene object(s) to clone.</param>
-        /// <param name="description">Optional description of what exactly the command does.</param>
-        /// <returns>Cloned scene objects.</returns>
-        public static SceneObject[] CloneSO(SceneObject[] so, string description = "")
-        {
-            if (so != null)
-            {
-                List<IntPtr> soPtrs = new List<IntPtr>();
-                for (int i = 0; i < so.Length; i++)
-                {
-                    if(so[i] != null)
-                        soPtrs.Add(so[i].GetCachedPtr());
-                }
-
-                return Internal_CloneSOMulti(soPtrs.ToArray(), description);
-            }
-
-            return new SceneObject[0];
-        }
-
-        /// <summary>
-        /// Creates new a scene object by cloning an existing object.
-        /// </summary>
-        /// <param name="so">Scene object to clone.</param>
-        /// <param name="description">Optional description of what exactly the command does.</param>
-        /// <returns>Cloned scene object.</returns>
-        public static SceneObject CloneSO(SceneObject so, string description = "")
-        {
-            if (so != null)
-                return Internal_CloneSO(so.GetCachedPtr(), description);
-
-            return null;
-        }
-
-        /// <summary>
-        /// Instantiates scene object(s) from a prefab.
-        /// </summary>
-        /// <param name="prefab">Prefab to instantiate.</param>
-        /// <param name="description">Optional description of what exactly the command does.</param>
-        /// <returns>Instantiated scene object.</returns>
-        public static SceneObject Instantiate(Prefab prefab, string description = "")
-        {
-            if (prefab != null)
-                return Internal_Instantiate(prefab.GetCachedPtr(), description);
-
-            return null;
-        }
-
-        /// <summary>
-        /// Creates a new scene object.
-        /// </summary>
-        /// <param name="name">Name of the scene object.</param>
-        /// <param name="description">Optional description of what exactly the command does.</param>
-        /// <returns>Newly created scene object.</returns>
-        public static SceneObject CreateSO(string name, string description = "")
-        {
-            return Internal_CreateSO(name, description);
-        }
-
-        /// <summary>
-        /// Deletes a scene object.
-        /// </summary>
-        /// <param name="so">Scene object to delete.</param>
-        /// <param name="description">Optional description of what exactly the command does.</param>
-        public static void DeleteSO(SceneObject so, string description = "")
-        {
-            if (so != null)
-                Internal_DeleteSO(so.GetCachedPtr(), description);
-        }
-
-        /// <summary>
-        /// Changes the parent of the scene object.
-        /// </summary>
-        /// <param name="so">Scene object to change the parent of.</param>
-        /// <param name="parent">New parent.</param>
-        /// <param name="description">Optional description of what exactly the command does.</param>
-        public static void ReparentSO(SceneObject so, SceneObject parent, string description = "")
-        {
-            if (so != null)
-            {
-                IntPtr parentPtr = IntPtr.Zero;
-                if (parent != null)
-                    parentPtr = parent.GetCachedPtr();
-
-                Internal_ReparentSO(so.GetCachedPtr(), parentPtr, description);
-            }
-        }
-
-        /// <summary>
-        /// Changes the parent of a set of scene objects.
-        /// </summary>
-        /// <param name="so">Scene objects to change the parent of.</param>
-        /// <param name="parent">New parent.</param>
-        /// <param name="description">Optional description of what exactly the command does.</param>
-        public static void ReparentSO(SceneObject[] so, SceneObject parent, string description = "")
-        {
-            if (so != null)
-            {
-                List<IntPtr> soPtrs = new List<IntPtr>();
-                for (int i = 0; i < so.Length; i++)
-                {
-                    if (so[i] != null)
-                        soPtrs.Add(so[i].GetCachedPtr());
-                }
-
-                if (soPtrs.Count > 0)
-                {
-                    IntPtr parentPtr = IntPtr.Zero;
-                    if (parent != null)
-                        parentPtr = parent.GetCachedPtr();
-
-                    Internal_ReparentSOMulti(soPtrs.ToArray(), parentPtr, description);
-                }
-            }
-        }
-
-        /// <summary>
-        /// Creates a new undo/redo group. All new commands will be registered to this group. You may remove the group and 
-        /// all of its commands by calling <see cref="PopGroup"/>.
-        /// </summary>
-        /// <param name="name">Unique name of the group.</param>
-        public static void PushGroup(string name)
-        {
-            Internal_PushGroup(name);
-        }
-
-        /// <summary>
-        /// Removes all the command registered to the current undo/redo group.
-        /// </summary>
-        /// <param name="name">Unique name of the group.</param>
-        public static void PopGroup(string name)
-        {
-            Internal_PopGroup(name);
-        }
-
-        /// <summary>
-        /// Removes a command with the specified identifier from undo/redo stack without executing it.
-        /// </summary>
-        /// <param name="id">Identifier of the command as returned by <see cref="GetTopCommandId"/></param>
-        public static void PopCommand(int id)
-        {
-            Internal_PopCommand(id);
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern void Internal_Undo();
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern void Internal_Redo();
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern void Internal_PushGroup(string name);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern void Internal_PopGroup(string name);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern void Internal_PopCommand(int id);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern int Internal_GetTopCommandId();
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern void Internal_RecordSO(IntPtr soPtr, string description);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern SceneObject Internal_CloneSO(IntPtr soPtr, string description);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern SceneObject[] Internal_CloneSOMulti(IntPtr[] soPtr, string description);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern SceneObject Internal_Instantiate(IntPtr prefabPtr, string description);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern SceneObject Internal_CreateSO(string name, string description);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern void Internal_DeleteSO(IntPtr soPtr, string description);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern void Internal_ReparentSO(IntPtr soPtr, IntPtr parentSOPtr, string description);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        internal static extern void Internal_ReparentSOMulti(IntPtr[] soPtr, IntPtr parentSOPtr, string description);
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading.Tasks;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Provides functionality to undo or redo recently performed operations in the editor.
+    /// </summary>
+    public static class UndoRedo
+    {
+        /// <summary>
+        /// Returns the unique identifier of the command currently at the top of the undo stack.
+        /// </summary>
+        public static int TopCommandId
+        {
+            get { return Internal_GetTopCommandId(); }
+        }
+
+        /// <summary>
+        /// Executes the last command on the undo stack, undoing its operations.
+        /// </summary>
+        [MenuItem("Edit/Undo", 9500, true)]
+        [ToolbarItem("Undo", ToolbarIcon.Undo, "Undo (Ctrl + Z)", 1900, true)]
+        public static void Undo()
+        {
+            Internal_Undo();
+        }
+
+        /// <summary>
+        /// Executes the last command on the redo stack (last command we called undo on), re-applying its operation.
+        /// </summary>
+        [MenuItem("Edit/Redo", 9499, true)]
+        [ToolbarItem("Redo", ToolbarIcon.Redo, "Redo (Ctrl + Y)", 1899)]
+        public static void Redo()
+        {
+            Internal_Redo();
+        }
+
+        /// <summary>
+        /// Records a state of the entire scene object at a specific point and allows you to restore it to its original 
+        /// values as needed.
+        /// </summary>
+        /// <param name="so">Scene object to record.</param>
+        /// <param name="description">Optional description of what exactly the command does.</param>
+        public static void RecordSO(SceneObject so, string description = "")
+        {
+            if (so != null)
+                Internal_RecordSO(so.GetCachedPtr(), description);
+        }
+
+        /// <summary>
+        /// Creates new scene object(s) by cloning existing objects.
+        /// </summary>
+        /// <param name="so">Scene object(s) to clone.</param>
+        /// <param name="description">Optional description of what exactly the command does.</param>
+        /// <returns>Cloned scene objects.</returns>
+        public static SceneObject[] CloneSO(SceneObject[] so, string description = "")
+        {
+            if (so != null)
+            {
+                List<IntPtr> soPtrs = new List<IntPtr>();
+                for (int i = 0; i < so.Length; i++)
+                {
+                    if(so[i] != null)
+                        soPtrs.Add(so[i].GetCachedPtr());
+                }
+
+                return Internal_CloneSOMulti(soPtrs.ToArray(), description);
+            }
+
+            return new SceneObject[0];
+        }
+
+        /// <summary>
+        /// Creates new a scene object by cloning an existing object.
+        /// </summary>
+        /// <param name="so">Scene object to clone.</param>
+        /// <param name="description">Optional description of what exactly the command does.</param>
+        /// <returns>Cloned scene object.</returns>
+        public static SceneObject CloneSO(SceneObject so, string description = "")
+        {
+            if (so != null)
+                return Internal_CloneSO(so.GetCachedPtr(), description);
+
+            return null;
+        }
+
+        /// <summary>
+        /// Instantiates scene object(s) from a prefab.
+        /// </summary>
+        /// <param name="prefab">Prefab to instantiate.</param>
+        /// <param name="description">Optional description of what exactly the command does.</param>
+        /// <returns>Instantiated scene object.</returns>
+        public static SceneObject Instantiate(Prefab prefab, string description = "")
+        {
+            if (prefab != null)
+                return Internal_Instantiate(prefab.GetCachedPtr(), description);
+
+            return null;
+        }
+
+        /// <summary>
+        /// Creates a new scene object.
+        /// </summary>
+        /// <param name="name">Name of the scene object.</param>
+        /// <param name="description">Optional description of what exactly the command does.</param>
+        /// <returns>Newly created scene object.</returns>
+        public static SceneObject CreateSO(string name, string description = "")
+        {
+            return Internal_CreateSO(name, description);
+        }
+
+        /// <summary>
+        /// Deletes a scene object.
+        /// </summary>
+        /// <param name="so">Scene object to delete.</param>
+        /// <param name="description">Optional description of what exactly the command does.</param>
+        public static void DeleteSO(SceneObject so, string description = "")
+        {
+            if (so != null)
+                Internal_DeleteSO(so.GetCachedPtr(), description);
+        }
+
+        /// <summary>
+        /// Changes the parent of the scene object.
+        /// </summary>
+        /// <param name="so">Scene object to change the parent of.</param>
+        /// <param name="parent">New parent.</param>
+        /// <param name="description">Optional description of what exactly the command does.</param>
+        public static void ReparentSO(SceneObject so, SceneObject parent, string description = "")
+        {
+            if (so != null)
+            {
+                IntPtr parentPtr = IntPtr.Zero;
+                if (parent != null)
+                    parentPtr = parent.GetCachedPtr();
+
+                Internal_ReparentSO(so.GetCachedPtr(), parentPtr, description);
+            }
+        }
+
+        /// <summary>
+        /// Changes the parent of a set of scene objects.
+        /// </summary>
+        /// <param name="so">Scene objects to change the parent of.</param>
+        /// <param name="parent">New parent.</param>
+        /// <param name="description">Optional description of what exactly the command does.</param>
+        public static void ReparentSO(SceneObject[] so, SceneObject parent, string description = "")
+        {
+            if (so != null)
+            {
+                List<IntPtr> soPtrs = new List<IntPtr>();
+                for (int i = 0; i < so.Length; i++)
+                {
+                    if (so[i] != null)
+                        soPtrs.Add(so[i].GetCachedPtr());
+                }
+
+                if (soPtrs.Count > 0)
+                {
+                    IntPtr parentPtr = IntPtr.Zero;
+                    if (parent != null)
+                        parentPtr = parent.GetCachedPtr();
+
+                    Internal_ReparentSOMulti(soPtrs.ToArray(), parentPtr, description);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Creates a new undo/redo group. All new commands will be registered to this group. You may remove the group and 
+        /// all of its commands by calling <see cref="PopGroup"/>.
+        /// </summary>
+        /// <param name="name">Unique name of the group.</param>
+        public static void PushGroup(string name)
+        {
+            Internal_PushGroup(name);
+        }
+
+        /// <summary>
+        /// Removes all the command registered to the current undo/redo group.
+        /// </summary>
+        /// <param name="name">Unique name of the group.</param>
+        public static void PopGroup(string name)
+        {
+            Internal_PopGroup(name);
+        }
+
+        /// <summary>
+        /// Removes a command with the specified identifier from undo/redo stack without executing it.
+        /// </summary>
+        /// <param name="id">Identifier of the command as returned by <see cref="GetTopCommandId"/></param>
+        public static void PopCommand(int id)
+        {
+            Internal_PopCommand(id);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern void Internal_Undo();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern void Internal_Redo();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern void Internal_PushGroup(string name);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern void Internal_PopGroup(string name);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern void Internal_PopCommand(int id);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern int Internal_GetTopCommandId();
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern void Internal_RecordSO(IntPtr soPtr, string description);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern SceneObject Internal_CloneSO(IntPtr soPtr, string description);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern SceneObject[] Internal_CloneSOMulti(IntPtr[] soPtr, string description);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern SceneObject Internal_Instantiate(IntPtr prefabPtr, string description);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern SceneObject Internal_CreateSO(string name, string description);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern void Internal_DeleteSO(IntPtr soPtr, string description);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern void Internal_ReparentSO(IntPtr soPtr, IntPtr parentSOPtr, string description);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        internal static extern void Internal_ReparentSOMulti(IntPtr[] soPtr, IntPtr parentSOPtr, string description);
+    }
+}