├── assets ├── Editor │ ├── Skin │ │ ├── Textures │ │ │ ├── UnderlineBackground.png │ │ │ ├── TrailingTipBackground.png │ │ │ ├── TrailingTipBackground_Light.png │ │ │ ├── UnderlineBackground.png.meta │ │ │ ├── TrailingTipBackground.png.meta │ │ │ └── TrailingTipBackground_Light.png.meta │ │ ├── ExtraEditorStyles.asset.meta │ │ ├── Textures.meta │ │ └── ExtraEditorStyles.asset │ ├── _assembly.asmdef.meta │ ├── Skin.meta │ ├── UnityEditorExtensions.meta │ ├── UnityEditorExtensions │ │ ├── AssetUtility.cs.meta │ │ ├── ControlContent.cs.meta │ │ ├── ExtraEditorGUI.cs.meta │ │ ├── IEditorSingleton.cs.meta │ │ ├── ExtraEditorStyles.cs.meta │ │ ├── EditorSingletonUtility.cs.meta │ │ ├── SerializedPropertyUtility.cs.meta │ │ ├── EditorSingletonScriptableObject.cs.meta │ │ ├── IEditorSingleton.cs │ │ ├── EditorSingletonScriptableObject.cs │ │ ├── EditorSingletonUtility.cs │ │ ├── AssetUtility.cs │ │ ├── SerializedPropertyUtility.cs │ │ ├── ExtraEditorStyles.cs │ │ ├── ControlContent.cs │ │ └── ExtraEditorGUI.cs │ └── _assembly.asmdef ├── Source │ ├── _assembly.asmdef │ ├── _assembly.asmdef.meta │ ├── DontDestroyOnLoad.cs.meta │ ├── UnityExceptionUtility.cs.meta │ ├── DontDestroyOnLoad.cs │ └── UnityExceptionUtility.cs ├── Editor.meta └── Source.meta ├── index.js ├── .editorconfig ├── package.json ├── .gitignore ├── LICENSE ├── README.md └── .gitattributes /assets/Editor/Skin/Textures/UnderlineBackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rotorz/unity3d-utils/HEAD/assets/Editor/Skin/Textures/UnderlineBackground.png -------------------------------------------------------------------------------- /assets/Editor/Skin/Textures/TrailingTipBackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rotorz/unity3d-utils/HEAD/assets/Editor/Skin/Textures/TrailingTipBackground.png -------------------------------------------------------------------------------- /assets/Source/_assembly.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rotorz.unity3d-utils", 3 | "references": [ 4 | "rotorz.dotnet-exception-utils" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /assets/Editor/Skin/Textures/TrailingTipBackground_Light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rotorz/unity3d-utils/HEAD/assets/Editor/Skin/Textures/TrailingTipBackground_Light.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | throw new Error("This package is not supposed to be used directly."); 5 | -------------------------------------------------------------------------------- /assets/Editor/_assembly.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7924fa1e731ad6a43a51882a962b3b50 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /assets/Source/_assembly.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 952f74ef81a2e0c45b07f705f37cfdcd 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /assets/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 109cf8d5cc2d79b4aa9e8000457d6d37 3 | folderAsset: yes 4 | timeCreated: 1483574931 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /assets/Editor/Skin/ExtraEditorStyles.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4b2b1e4ebd65e0f4fa107d1dc5ca4132 3 | timeCreated: 1483733082 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /assets/Source.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c92c3d1a23d9d7d4899f3745f3ec20e5 3 | folderAsset: yes 4 | timeCreated: 1487017945 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /assets/Editor/Skin.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 694a951105f33da418e32667c2190275 3 | folderAsset: yes 4 | timeCreated: 1487390048 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /assets/Editor/Skin/Textures.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5ba86e455b0c42f47be1feca90133e6d 3 | folderAsset: yes 4 | timeCreated: 1487390232 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b20d8b0ca8d084c4ea213f65bddd7458 3 | folderAsset: yes 4 | timeCreated: 1483670225 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /assets/Source/DontDestroyOnLoad.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e9276542313286940b06cf281c5f097d 3 | timeCreated: 1497536920 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /assets/Source/UnityExceptionUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3483c657d68500847b2fb6ad0a76b74b 3 | timeCreated: 1487487195 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/AssetUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2b1627b072dbd4842ac7cba60ae871e2 3 | timeCreated: 1483670225 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/ControlContent.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ebe37e4cdc1491e4295673da6af85a27 3 | timeCreated: 1503365270 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/ExtraEditorGUI.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b95d60e63861e924b92801be40bbf545 3 | timeCreated: 1483670225 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/IEditorSingleton.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 90fc41b9b74ee26488e40eb564f8e2c0 3 | timeCreated: 1487198688 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/ExtraEditorStyles.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 694e7ff2cc8d680419bad1683981a5de 3 | timeCreated: 1483670225 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /assets/Editor/_assembly.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rotorz.unity3d-utils.editor", 3 | "references": [ 4 | "rotorz.unity3d-utils", 5 | "rotorz.dotnet-exception-utils" 6 | ], 7 | "optionalUnityReferences": [], 8 | "includePlatforms": [ 9 | "Editor" 10 | ], 11 | "excludePlatforms": [], 12 | "allowUnsafeCode": false 13 | } 14 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/EditorSingletonUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2f511cf35a46bc84da0fd252a813b115 3 | timeCreated: 1487198688 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/SerializedPropertyUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5cf2268642ccb6842ab11b851e41f5a7 3 | timeCreated: 1487023991 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/EditorSingletonScriptableObject.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7c91d5f06be6de548928a2bdf206aabf 3 | timeCreated: 1487198688 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /assets/Source/DontDestroyOnLoad.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | using UnityEngine; 5 | 6 | namespace Rotorz.Games 7 | { 8 | /// 9 | /// Marks a game object upon awakening so that it is not destroyed between scenes. 10 | /// 11 | public sealed class DontDestroyOnLoad : MonoBehaviour 12 | { 13 | private void Awake() 14 | { 15 | DontDestroyOnLoad(this); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; Grab the EditorConfig extension for Visual Studio: 2 | ; https://visualstudiogallery.msdn.microsoft.com/c8bccfe2-650c-4b42-bc5c-845e21f96328 3 | 4 | ; Top-most EditorConfig file 5 | root = true 6 | 7 | ; Unix-style newlines with a newline ending every file 8 | [*] 9 | end_of_line = LF 10 | insert_final_newline = true 11 | indent_style = space 12 | indent_size = 4 13 | trim_trailing_whitespace = true 14 | 15 | [*.{md,yaml}] 16 | trim_trailing_whitespace = false 17 | 18 | [*.{js,json,yaml,html,css,styl}] 19 | indent_size = 2 20 | 21 | [Makefile] 22 | indent_style = tab 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rotorz/unity3d-utils", 3 | "version": "1.0.1", 4 | "description": "Common utility functionality for Unity game projects.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/rotorz/unity3d-utils" 12 | }, 13 | "author": "Rotorz Limited", 14 | "license": "MIT", 15 | "keywords": [ 16 | "unity3d", 17 | "unity3d-package" 18 | ], 19 | "dependencies": { 20 | "@rotorz/dotnet-exception-utils": "github:rotorz/dotnet-exception-utils#semver:^1.0.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/IEditorSingleton.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | namespace Rotorz.Games.UnityEditorExtensions 5 | { 6 | /// 7 | /// Interface of a Unity editor extension singleton. 8 | /// 9 | public interface IEditorSingleton 10 | { 11 | /// 12 | /// Gets a value indicating whether the singleton has already been initialized. 13 | /// 14 | bool HasInitialized { get; } 15 | 16 | 17 | /// 18 | /// Invoked to initialize the singleton. 19 | /// 20 | /// 21 | /// If the has already been initialized. 22 | /// 23 | void Initialize(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Derived From: 2 | # http://kleber-swf.com/the-definitive-gitignore-for-unity-projects/ 3 | 4 | # ============= # 5 | # Working Files # 6 | # ============= # 7 | node_modules/ 8 | npm-debug.log 9 | 10 | # ===================== # 11 | # Working Files - Unity # 12 | # ===================== # 13 | /Temp/ 14 | /Library/ 15 | /Packages/ 16 | /ProjectSettings/ 17 | /assets/Plugins/ 18 | /assets/Plugins.meta 19 | /*.csproj 20 | /*.sln 21 | 22 | # ===================================== # 23 | # Visual Studio / MonoDevelop generated # 24 | # ===================================== # 25 | /.vs/ 26 | bin 27 | obj 28 | ExportedObj/ 29 | *.svd 30 | *.userprefs 31 | *.pidb 32 | *.suo 33 | *.user 34 | *.unityproj 35 | *.booproj 36 | *.pdb 37 | *.pdb.meta 38 | 39 | # ============ # 40 | # OS generated # 41 | # ============ # 42 | .DS_Store 43 | .DS_Store? 44 | *~ 45 | ._* 46 | .Spotlight-V100 47 | .Trashes 48 | Icon? 49 | ehthumbs.db 50 | Thumbs.db 51 | -------------------------------------------------------------------------------- /assets/Source/UnityExceptionUtility.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | using System; 5 | using Object = UnityEngine.Object; 6 | 7 | namespace Rotorz.Games 8 | { 9 | /// 10 | /// Utility functionality for exceptions. 11 | /// 12 | public static class UnityExceptionUtility 13 | { 14 | /// 15 | /// Checks that an object argument is non-null and in the case of Unity objects 16 | /// that they haven't been destroyed. 17 | /// 18 | /// The argument. 19 | /// Name of the parameter 20 | public static void CheckArgumentObjectValid(Object arg, string paramName) 21 | { 22 | if (ReferenceEquals(arg, null)) { 23 | throw new ArgumentNullException(paramName); 24 | } 25 | if (arg == null) { 26 | throw new ArgumentException("Object has been destroyed.", paramName); 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2017 Rotorz Limited 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # unity3d-utils 2 | 3 | Common utility functionality for Unity game projects. 4 | 5 | ```sh 6 | $ yarn add rotorz/unity3d-utils 7 | ``` 8 | 9 | This package is compatible with the [unity3d-package-syncer][tool] tool. Refer to the 10 | tools' [README][tool] for information on syncing packages into a Unity project. 11 | 12 | [tool]: https://github.com/rotorz/unity3d-package-syncer 13 | 14 | 15 | ## Contribution Agreement 16 | 17 | This project is licensed under the MIT license (see LICENSE). To be in the best 18 | position to enforce these licenses the copyright status of this project needs to 19 | be as simple as possible. To achieve this the following terms and conditions 20 | must be met: 21 | 22 | - All contributed content (including but not limited to source code, text, 23 | image, videos, bug reports, suggestions, ideas, etc.) must be the 24 | contributors own work. 25 | 26 | - The contributor disclaims all copyright and accepts that their contributed 27 | content will be released to the public domain. 28 | 29 | - The act of submitting a contribution indicates that the contributor agrees 30 | with this agreement. This includes (but is not limited to) pull requests, issues, 31 | tickets, e-mails, newsgroups, blogs, forums, etc. 32 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/EditorSingletonScriptableObject.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | using System; 5 | using UnityEngine; 6 | 7 | namespace Rotorz.Games.UnityEditorExtensions 8 | { 9 | /// 10 | /// Base class of a Unity editor extension singleton. 11 | /// 12 | public abstract class EditorSingletonScriptableObject : ScriptableObject, IEditorSingleton 13 | { 14 | /// 15 | public bool HasInitialized { get; private set; } 16 | 17 | 18 | /// 19 | /// Occurs when the is initialized. 20 | /// 21 | protected virtual void OnInitialize() 22 | { 23 | } 24 | 25 | 26 | /// 27 | public void Initialize() 28 | { 29 | if (this.HasInitialized) { 30 | throw new InvalidOperationException("Already initialized!"); 31 | } 32 | 33 | this.HasInitialized = true; 34 | this.OnInitialize(); 35 | } 36 | 37 | /// 38 | /// Reinitializes the singleton. 39 | /// 40 | public void Reinitialize() 41 | { 42 | this.HasInitialized = true; 43 | this.OnInitialize(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/EditorSingletonUtility.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | using System.Linq; 5 | using UnityEditor; 6 | 7 | namespace Rotorz.Games.UnityEditorExtensions 8 | { 9 | /// 10 | /// Singleton utility functions for custom Unity editor extensions. 11 | /// 12 | public static class EditorSingletonUtility 13 | { 14 | /// 15 | /// Gets the one-and-only instance for a custom 16 | /// implementation. 17 | /// 18 | /// Implementation type. 19 | /// Reference for the one-and-only shared instance of the 20 | /// specified implementation type. 21 | /// Indicates if singleton should be 22 | /// initialized again when Unity reloads it's assemblies. 23 | public static void GetAssetInstance(ref T instance, bool reinitializeOnReload = true) 24 | where T : EditorSingletonScriptableObject 25 | { 26 | if (instance == null) { 27 | string assetGuid = AssetDatabase.FindAssets("t:" + typeof(T).FullName).FirstOrDefault(); 28 | if (!string.IsNullOrEmpty(assetGuid)) { 29 | string assetPath = AssetDatabase.GUIDToAssetPath(assetGuid); 30 | instance = AssetDatabase.LoadAssetAtPath(assetPath); 31 | if (reinitializeOnReload && instance.HasInitialized) { 32 | instance.Reinitialize(); 33 | } 34 | } 35 | } 36 | 37 | if (!instance.HasInitialized) { 38 | instance.Initialize(); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /assets/Editor/Skin/ExtraEditorStyles.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_PrefabParentObject: {fileID: 0} 7 | m_PrefabInternal: {fileID: 0} 8 | m_GameObject: {fileID: 0} 9 | m_Enabled: 1 10 | m_EditorHideFlags: 0 11 | m_Script: {fileID: 11500000, guid: 694e7ff2cc8d680419bad1683981a5de, type: 3} 12 | m_Name: ExtraEditorStyles 13 | m_EditorClassIdentifier: 14 | darkSkin: 15 | windowBackgroundColor: {r: 0.21960784, g: 0.21960784, b: 0.21960784, a: 1} 16 | separatorColor: {r: 0.11, g: 0.11, b: 0.11, a: 1} 17 | separatorLightColor: {r: 0.16, g: 0.16, b: 0.16, a: 1} 18 | groupLabelColor: {r: 0.44313726, g: 0.44313726, b: 0.44313726, a: 1} 19 | metaLabelColor: {r: 0.13333334, g: 0.13333334, b: 0.13333334, a: 1} 20 | linkColor: {r: 0.89411765, g: 1, b: 0, a: 1} 21 | selectedHighlightColor: {r: 0.23921569, g: 0.5019608, b: 0.8745098, a: 1} 22 | selectedHighlightStrongColor: {r: 0, g: 0.5019608, b: 1, a: 1} 23 | texTrailingTipBackground: {fileID: 2800000, guid: 977519d8d10188a40aaa10ce2428793a, 24 | type: 3} 25 | underlineBackground: {fileID: 2800000, guid: 6e64644c351cbd74b836d58939eca055, 26 | type: 3} 27 | lightSkin: 28 | windowBackgroundColor: {r: 0.7607843, g: 0.7607843, b: 0.7607843, a: 1} 29 | separatorColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 30 | separatorLightColor: {r: 0.65, g: 0.65, b: 0.65, a: 1} 31 | groupLabelColor: {r: 0.36862746, g: 0.36862746, b: 0.36862746, a: 1} 32 | metaLabelColor: {r: 0.54901963, g: 0.54901963, b: 0.54901963, a: 1} 33 | linkColor: {r: 0, g: 0.5411765, b: 1, a: 1} 34 | selectedHighlightColor: {r: 0.23921569, g: 0.5019608, b: 0.8745098, a: 1} 35 | selectedHighlightStrongColor: {r: 0, g: 0.5019608, b: 1, a: 1} 36 | texTrailingTipBackground: {fileID: 2800000, guid: eb83234ffb5b22742953bb99b1d56ffa, 37 | type: 3} 38 | underlineBackground: {fileID: 2800000, guid: 6e64644c351cbd74b836d58939eca055, 39 | type: 3} 40 | -------------------------------------------------------------------------------- /assets/Editor/Skin/Textures/UnderlineBackground.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6e64644c351cbd74b836d58939eca055 3 | timeCreated: 1483733165 4 | licenseType: Pro 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 0 11 | sRGBTexture: 0 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapFadeDistanceStart: 1 16 | mipMapFadeDistanceEnd: 3 17 | bumpmap: 18 | convertToNormalMap: 0 19 | externalNormalMap: 0 20 | heightScale: 0.25 21 | normalMapFilter: 0 22 | isReadable: 0 23 | grayScaleToAlpha: 0 24 | generateCubemap: 6 25 | cubemapConvolution: 0 26 | seamlessCubemap: 0 27 | textureFormat: 1 28 | maxTextureSize: 2048 29 | textureSettings: 30 | filterMode: 0 31 | aniso: 1 32 | mipBias: -1 33 | wrapMode: 1 34 | nPOTScale: 0 35 | lightmap: 0 36 | compressionQuality: 50 37 | spriteMode: 1 38 | spriteExtrude: 1 39 | spriteMeshType: 1 40 | alignment: 0 41 | spritePivot: {x: 0.5, y: 0.5} 42 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 43 | spritePixelsToUnits: 100 44 | alphaUsage: 1 45 | alphaIsTransparency: 1 46 | spriteTessellationDetail: -1 47 | textureType: 2 48 | textureShape: 1 49 | maxTextureSizeSet: 0 50 | compressionQualitySet: 0 51 | textureFormatSet: 0 52 | platformSettings: 53 | - buildTarget: DefaultTexturePlatform 54 | maxTextureSize: 2048 55 | textureFormat: -1 56 | textureCompression: 1 57 | compressionQuality: 50 58 | crunchedCompression: 0 59 | allowsAlphaSplitting: 0 60 | overridden: 0 61 | - buildTarget: Standalone 62 | maxTextureSize: 2048 63 | textureFormat: -1 64 | textureCompression: 1 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | - buildTarget: iPhone 70 | maxTextureSize: 2048 71 | textureFormat: -1 72 | textureCompression: 1 73 | compressionQuality: 50 74 | crunchedCompression: 0 75 | allowsAlphaSplitting: 0 76 | overridden: 0 77 | - buildTarget: Android 78 | maxTextureSize: 2048 79 | textureFormat: -1 80 | textureCompression: 1 81 | compressionQuality: 50 82 | crunchedCompression: 0 83 | allowsAlphaSplitting: 0 84 | overridden: 0 85 | - buildTarget: Windows Store Apps 86 | maxTextureSize: 2048 87 | textureFormat: -1 88 | textureCompression: 1 89 | compressionQuality: 50 90 | crunchedCompression: 0 91 | allowsAlphaSplitting: 0 92 | overridden: 0 93 | - buildTarget: WebGL 94 | maxTextureSize: 2048 95 | textureFormat: -1 96 | textureCompression: 1 97 | compressionQuality: 50 98 | crunchedCompression: 0 99 | allowsAlphaSplitting: 0 100 | overridden: 0 101 | spriteSheet: 102 | serializedVersion: 2 103 | sprites: [] 104 | outline: [] 105 | spritePackingTag: 106 | userData: 107 | assetBundleName: 108 | assetBundleVariant: 109 | -------------------------------------------------------------------------------- /assets/Editor/Skin/Textures/TrailingTipBackground.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 977519d8d10188a40aaa10ce2428793a 3 | timeCreated: 1497111931 4 | licenseType: Pro 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 0 11 | sRGBTexture: 0 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapFadeDistanceStart: 1 16 | mipMapFadeDistanceEnd: 3 17 | bumpmap: 18 | convertToNormalMap: 0 19 | externalNormalMap: 0 20 | heightScale: 0.25 21 | normalMapFilter: 0 22 | isReadable: 0 23 | grayScaleToAlpha: 0 24 | generateCubemap: 6 25 | cubemapConvolution: 0 26 | seamlessCubemap: 0 27 | textureFormat: 1 28 | maxTextureSize: 2048 29 | textureSettings: 30 | filterMode: 0 31 | aniso: 1 32 | mipBias: -1 33 | wrapMode: 1 34 | nPOTScale: 0 35 | lightmap: 0 36 | compressionQuality: 50 37 | spriteMode: 0 38 | spriteExtrude: 1 39 | spriteMeshType: 1 40 | alignment: 0 41 | spritePivot: {x: 0.5, y: 0.5} 42 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 43 | spritePixelsToUnits: 100 44 | alphaUsage: 1 45 | alphaIsTransparency: 1 46 | spriteTessellationDetail: -1 47 | textureType: 2 48 | textureShape: 1 49 | maxTextureSizeSet: 0 50 | compressionQualitySet: 0 51 | textureFormatSet: 0 52 | platformSettings: 53 | - buildTarget: DefaultTexturePlatform 54 | maxTextureSize: 2048 55 | textureFormat: -1 56 | textureCompression: 0 57 | compressionQuality: 50 58 | crunchedCompression: 0 59 | allowsAlphaSplitting: 0 60 | overridden: 0 61 | - buildTarget: Standalone 62 | maxTextureSize: 2048 63 | textureFormat: -1 64 | textureCompression: 0 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | - buildTarget: iPhone 70 | maxTextureSize: 2048 71 | textureFormat: -1 72 | textureCompression: 0 73 | compressionQuality: 50 74 | crunchedCompression: 0 75 | allowsAlphaSplitting: 0 76 | overridden: 0 77 | - buildTarget: Android 78 | maxTextureSize: 2048 79 | textureFormat: -1 80 | textureCompression: 0 81 | compressionQuality: 50 82 | crunchedCompression: 0 83 | allowsAlphaSplitting: 0 84 | overridden: 0 85 | - buildTarget: Windows Store Apps 86 | maxTextureSize: 2048 87 | textureFormat: -1 88 | textureCompression: 0 89 | compressionQuality: 50 90 | crunchedCompression: 0 91 | allowsAlphaSplitting: 0 92 | overridden: 0 93 | - buildTarget: WebGL 94 | maxTextureSize: 2048 95 | textureFormat: -1 96 | textureCompression: 0 97 | compressionQuality: 50 98 | crunchedCompression: 0 99 | allowsAlphaSplitting: 0 100 | overridden: 0 101 | spriteSheet: 102 | serializedVersion: 2 103 | sprites: [] 104 | outline: [] 105 | spritePackingTag: 106 | userData: 107 | assetBundleName: 108 | assetBundleVariant: 109 | -------------------------------------------------------------------------------- /assets/Editor/Skin/Textures/TrailingTipBackground_Light.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eb83234ffb5b22742953bb99b1d56ffa 3 | timeCreated: 1497111933 4 | licenseType: Pro 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 0 11 | sRGBTexture: 0 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapFadeDistanceStart: 1 16 | mipMapFadeDistanceEnd: 3 17 | bumpmap: 18 | convertToNormalMap: 0 19 | externalNormalMap: 0 20 | heightScale: 0.25 21 | normalMapFilter: 0 22 | isReadable: 0 23 | grayScaleToAlpha: 0 24 | generateCubemap: 6 25 | cubemapConvolution: 0 26 | seamlessCubemap: 0 27 | textureFormat: 1 28 | maxTextureSize: 2048 29 | textureSettings: 30 | filterMode: 0 31 | aniso: 1 32 | mipBias: -1 33 | wrapMode: 1 34 | nPOTScale: 0 35 | lightmap: 0 36 | compressionQuality: 50 37 | spriteMode: 0 38 | spriteExtrude: 1 39 | spriteMeshType: 1 40 | alignment: 0 41 | spritePivot: {x: 0.5, y: 0.5} 42 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 43 | spritePixelsToUnits: 100 44 | alphaUsage: 1 45 | alphaIsTransparency: 1 46 | spriteTessellationDetail: -1 47 | textureType: 2 48 | textureShape: 1 49 | maxTextureSizeSet: 0 50 | compressionQualitySet: 0 51 | textureFormatSet: 0 52 | platformSettings: 53 | - buildTarget: DefaultTexturePlatform 54 | maxTextureSize: 2048 55 | textureFormat: -1 56 | textureCompression: 0 57 | compressionQuality: 50 58 | crunchedCompression: 0 59 | allowsAlphaSplitting: 0 60 | overridden: 0 61 | - buildTarget: Standalone 62 | maxTextureSize: 2048 63 | textureFormat: -1 64 | textureCompression: 0 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | - buildTarget: iPhone 70 | maxTextureSize: 2048 71 | textureFormat: -1 72 | textureCompression: 0 73 | compressionQuality: 50 74 | crunchedCompression: 0 75 | allowsAlphaSplitting: 0 76 | overridden: 0 77 | - buildTarget: Android 78 | maxTextureSize: 2048 79 | textureFormat: -1 80 | textureCompression: 0 81 | compressionQuality: 50 82 | crunchedCompression: 0 83 | allowsAlphaSplitting: 0 84 | overridden: 0 85 | - buildTarget: Windows Store Apps 86 | maxTextureSize: 2048 87 | textureFormat: -1 88 | textureCompression: 0 89 | compressionQuality: 50 90 | crunchedCompression: 0 91 | allowsAlphaSplitting: 0 92 | overridden: 0 93 | - buildTarget: WebGL 94 | maxTextureSize: 2048 95 | textureFormat: -1 96 | textureCompression: 0 97 | compressionQuality: 50 98 | crunchedCompression: 0 99 | allowsAlphaSplitting: 0 100 | overridden: 0 101 | spriteSheet: 102 | serializedVersion: 2 103 | sprites: [] 104 | outline: [] 105 | spritePackingTag: 106 | userData: 107 | assetBundleName: 108 | assetBundleVariant: 109 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Apply native OS line-endings on checkout of these files... 2 | *.boo text 3 | *.c text 4 | *.cginc text 5 | *.config text 6 | *.contentproj text 7 | *.cpp text 8 | *.cs text 9 | *.css text 10 | *.dae text 11 | *.DAE text 12 | *.dtd text 13 | *.fx text 14 | *.glsl text 15 | *.h text 16 | *.htm text 17 | *.html text 18 | *.inc text 19 | *.ini text 20 | *.js text 21 | *.JSFL text 22 | *.jsfl text 23 | *.json text 24 | *.log text 25 | *.md text 26 | *.mel text 27 | *.php text 28 | *.po text 29 | *.shader text 30 | *.txt text 31 | *.TXT text 32 | *.xaml text 33 | *.xml text 34 | *.xsd text 35 | .gitattributes text 36 | .gitignore text 37 | COPYING text 38 | INSTALL* text 39 | KEYS* text 40 | LICENSE* text 41 | NEWS* text 42 | NOTICE* text 43 | README* text 44 | TODO* text 45 | WHATSNEW* text 46 | 47 | # Apply Unix-style LF line-endings on checkout for these files since Unity 48 | # project has been configured to force text output for them... 49 | *.anim text eol=lf 50 | *.asset text eol=lf 51 | *.controller text eol=lf 52 | *.cubemap text eol=lf 53 | *.guiskin text eol=lf 54 | *.mat text eol=lf 55 | *.prefab text eol=lf 56 | *.physicMaterial text eol=lf 57 | *.physicmaterial text eol=lf 58 | *.unity text eol=lf 59 | 60 | # Apply Unix-style LF line-endings on checkout of these files... 61 | *.meta text eol=lf 62 | *.sh text eol=lf 63 | *.vspscc text eol=lf 64 | .htaccess text eol=lf 65 | 66 | # Apply Windows/DOS-style CR-LF line-endings on checkout of these files... 67 | *.bat text eol=crlf 68 | *.cmd text eol=crlf 69 | *.csproj text eol=crlf 70 | *.sln text eol=crlf 71 | *.user text eol=crlf 72 | *.vcproj text eol=crlf 73 | 74 | # No end-of-line conversions are applied (i.e., "-text -diff") to these files... 75 | *.7z binary 76 | *.ai binary 77 | *.apk binary 78 | *.bin binary 79 | *.bmp binary 80 | *.BMP binary 81 | *.com binary 82 | *.COM binary 83 | *.dex binary 84 | *.dll binary 85 | *.DLL binary 86 | *.dylib binary 87 | *.eps binary 88 | *.exe binary 89 | *.EXE binary 90 | *.exr binary 91 | *.fbx binary 92 | *.FBX binary 93 | *.fla binary 94 | *.flare binary 95 | *.flv binary 96 | *.gif binary 97 | *.gz binary 98 | *.ht binary 99 | *.ico binary 100 | *.jpeg binary 101 | *.jpg binary 102 | *.keystore binary 103 | *.mask binary 104 | *.mb binary 105 | *.mo binary 106 | *.mp3 binary 107 | *.mp4 binary 108 | *.mpg binary 109 | *.ogg binary 110 | *.PCX binary 111 | *.pcx binary 112 | *.pdb binary 113 | *.pdf binary 114 | *.png binary 115 | *.ps binary 116 | *.psd binary 117 | *.qt binary 118 | *.so binary 119 | *.swf binary 120 | *.tga binary 121 | *.tif binary 122 | *.tiff binary 123 | *.ttf binary 124 | *.TTF binary 125 | *.unitypackage binary 126 | *.unityPackage binary 127 | *.wav binary 128 | *.wmv binary 129 | *.zip binary 130 | *.ZIP binary 131 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/AssetUtility.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | using System; 5 | using System.IO; 6 | using System.Text; 7 | using System.Text.RegularExpressions; 8 | using UnityEditor; 9 | using Object = UnityEngine.Object; 10 | 11 | namespace Rotorz.Games.UnityEditorExtensions 12 | { 13 | /// 14 | /// Utility functions for asset files and folders. 15 | /// 16 | public static class AssetUtility 17 | { 18 | #region Asset Path Manipulation 19 | 20 | /// 21 | /// Combine one or more asset paths. 22 | /// 23 | /// First asset path. 24 | /// Other parts of asset path. 25 | /// 26 | /// The combined asset path. 27 | /// 28 | /// 29 | /// 30 | /// If is null. 31 | /// If one or more have a value of null. 32 | /// 33 | /// 34 | /// 35 | /// 36 | /// If is not a valid asset path. 37 | /// If one or more are not valid. 38 | /// 39 | /// 40 | public static string CombineAssetPaths(string firstPath, params string[] otherPaths) 41 | { 42 | CheckAssetPathArgument(firstPath, "firstPath"); 43 | 44 | if (otherPaths == null || otherPaths.Length == 0) { 45 | return firstPath; 46 | } 47 | 48 | var sb = new StringBuilder(firstPath); 49 | 50 | for (int i = 0; i < otherPaths.Length; ++i) { 51 | string otherPath = otherPaths[i]; 52 | 53 | if (otherPath == null) { 54 | throw new ArgumentNullException(string.Format("otherPaths[{0}]", i)); 55 | } 56 | if (otherPath == "" || !PathRegex.IsMatch(otherPath)) { 57 | throw new ArgumentException(string.Format("Invalid path '{0}'.", otherPath), string.Format("otherPaths[{0}]", i)); 58 | } 59 | 60 | sb.Append('/'); 61 | sb.Append(otherPath); 62 | } 63 | 64 | return sb.ToString(); 65 | } 66 | 67 | #endregion 68 | 69 | 70 | #region Asset Path Validation 71 | 72 | private const string SlugPattern = @"[^\s/\\][^/\\]*"; 73 | 74 | //private static readonly Regex SlugRegex = new Regex(SlugPattern, RegexOptions.CultureInvariant); 75 | private static readonly Regex PathRegex = new Regex(string.Format(@"^{0}(/{0})*$", SlugPattern), RegexOptions.CultureInvariant); 76 | 77 | private static string GetAssetPathError(string assetPath) 78 | { 79 | if (assetPath == null) { 80 | return "Asset path was null."; 81 | } 82 | if (!assetPath.StartsWith("Assets/")) { 83 | return "Asset path does not start with 'Assets/'."; 84 | } 85 | if (assetPath.IndexOfAny(Path.GetInvalidPathChars()) != -1) { 86 | return string.Format("Asset path '{0}' contains one or more invalid characters.", assetPath); 87 | } 88 | if (!PathRegex.IsMatch(assetPath)) { 89 | return string.Format("Invalid asset path '{0}'.", assetPath); 90 | } 91 | 92 | return null; 93 | } 94 | 95 | /// 96 | /// Determines whether the specified is valid. 97 | /// 98 | /// Asset path. 99 | /// 100 | /// A value of true if is valid; otherwise, false. 101 | /// 102 | public static bool IsValidAssetPath(string assetPath) 103 | { 104 | return GetAssetPathError(assetPath) == null; 105 | } 106 | 107 | /// 108 | /// Does nothing if the specified is valid; 109 | /// otherwise throws a exception. 110 | /// 111 | /// Asset path. 112 | /// Name of the parameter 113 | /// 114 | /// If is null. 115 | /// 116 | /// 117 | /// If is not a valid asset path. 118 | /// 119 | public static void CheckAssetPathArgument(string assetPath, string paramName) 120 | { 121 | ExceptionUtility.CheckExpectedStringArgument(assetPath, paramName); 122 | 123 | string error = GetAssetPathError(assetPath); 124 | if (error != null) { 125 | throw new ArgumentException(error, paramName); 126 | } 127 | } 128 | 129 | #endregion 130 | 131 | 132 | #region Assets 133 | 134 | /// 135 | /// Creates an asset file from the specified object at the specified path. 136 | /// 137 | /// 138 | /// Create a new instance of a custom and 139 | /// then save to an asset file: 140 | /// (); 142 | /// AssetUtility.CreateAsset(newAsset, "Assets/Some/Sub/Folder/MyAsset.asset"); 143 | /// AssetDatabase.SaveAssets(); 144 | /// ]]> 145 | /// 146 | /// Object that is to be saved. 147 | /// Path of new asset file. 148 | /// 149 | /// 150 | /// If is null. 151 | /// If is null. 152 | /// 153 | /// 154 | /// 155 | /// 156 | /// If has already been destroyed. 157 | /// If is not a valid asset path. 158 | /// 159 | /// 160 | public static void CreateAsset(Object obj, string assetPath) 161 | { 162 | UnityExceptionUtility.CheckArgumentObjectValid(obj, "obj"); 163 | 164 | CheckAssetPathArgument(assetPath, "assetPath"); 165 | if (!assetPath.EndsWith(".asset")) { 166 | throw new ArgumentException("Does not end with '.asset'.", "assetPath"); 167 | } 168 | 169 | // Ensure that directory exists before proceeding to create asset. 170 | string[] assetPathFragments = assetPath.Split('/'); 171 | if (assetPathFragments.Length > 2) { 172 | string assetDirectoryPath = string.Join("/", assetPathFragments, 0, assetPathFragments.Length - 1); 173 | CreateFolder(assetDirectoryPath); 174 | } 175 | 176 | AssetDatabase.CreateAsset(obj, assetPath); 177 | } 178 | 179 | #endregion 180 | 181 | 182 | #region Folders 183 | 184 | /// 185 | /// Ensures that all folders in the specified asset path exist. 186 | /// 187 | /// Asset path. 188 | /// 189 | /// If is null. 190 | /// 191 | /// 192 | /// If is not a valid asset path. 193 | /// 194 | public static void CreateFolder(string assetPath) 195 | { 196 | CheckAssetPathArgument(assetPath, "assetPath"); 197 | 198 | string absoluteFolderPath = Path.Combine(Directory.GetCurrentDirectory(), assetPath); 199 | Directory.CreateDirectory(absoluteFolderPath); 200 | } 201 | 202 | #endregion 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/SerializedPropertyUtility.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | using System; 5 | using UnityEditor; 6 | using UnityEngine; 7 | 8 | namespace Rotorz.Games.UnityEditorExtensions 9 | { 10 | /// 11 | /// Utility functionality for implementations. 12 | /// 13 | public static class SerializedPropertyUtility 14 | { 15 | /// 16 | /// Reset the value of a property. 17 | /// 18 | /// Serialized property for a serialized property. 19 | public static void ResetValue(SerializedProperty property) 20 | { 21 | if (property == null) { 22 | throw new ArgumentNullException("property"); 23 | } 24 | 25 | switch (property.propertyType) { 26 | case SerializedPropertyType.Integer: 27 | property.intValue = 0; 28 | break; 29 | 30 | case SerializedPropertyType.Boolean: 31 | property.boolValue = false; 32 | break; 33 | 34 | case SerializedPropertyType.Float: 35 | property.floatValue = 0f; 36 | break; 37 | 38 | case SerializedPropertyType.String: 39 | property.stringValue = ""; 40 | break; 41 | 42 | case SerializedPropertyType.Color: 43 | property.colorValue = Color.black; 44 | break; 45 | 46 | case SerializedPropertyType.ObjectReference: 47 | property.objectReferenceValue = null; 48 | break; 49 | 50 | case SerializedPropertyType.LayerMask: 51 | property.intValue = 0; 52 | break; 53 | 54 | case SerializedPropertyType.Enum: 55 | property.enumValueIndex = 0; 56 | break; 57 | 58 | case SerializedPropertyType.Vector2: 59 | property.vector2Value = default(Vector2); 60 | break; 61 | 62 | case SerializedPropertyType.Vector3: 63 | property.vector3Value = default(Vector3); 64 | break; 65 | 66 | case SerializedPropertyType.Vector4: 67 | property.vector4Value = default(Vector4); 68 | break; 69 | 70 | case SerializedPropertyType.Rect: 71 | property.rectValue = default(Rect); 72 | break; 73 | 74 | case SerializedPropertyType.ArraySize: 75 | property.intValue = 0; 76 | break; 77 | 78 | case SerializedPropertyType.Character: 79 | property.intValue = 0; 80 | break; 81 | 82 | case SerializedPropertyType.AnimationCurve: 83 | property.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f); 84 | break; 85 | 86 | case SerializedPropertyType.Bounds: 87 | property.boundsValue = default(Bounds); 88 | break; 89 | 90 | case SerializedPropertyType.Gradient: 91 | //!TODO: Amend when Unity add a public API for setting the gradient. 92 | break; 93 | } 94 | 95 | if (property.isArray) { 96 | property.arraySize = 0; 97 | } 98 | 99 | ResetChildPropertyValues(property); 100 | } 101 | 102 | private static void ResetChildPropertyValues(SerializedProperty element) 103 | { 104 | if (!element.hasChildren) { 105 | return; 106 | } 107 | 108 | var childProperty = element.Copy(); 109 | int elementPropertyDepth = element.depth; 110 | bool enterChildren = true; 111 | 112 | while (childProperty.Next(enterChildren) && childProperty.depth > elementPropertyDepth) { 113 | enterChildren = false; 114 | ResetValue(childProperty); 115 | } 116 | } 117 | 118 | /// 119 | /// Copies value of into . 120 | /// 121 | /// Destination property. 122 | /// Source property. 123 | public static void CopyPropertyValue(SerializedProperty destProperty, SerializedProperty sourceProperty) 124 | { 125 | if (destProperty == null) { 126 | throw new ArgumentNullException("destProperty"); 127 | } 128 | if (sourceProperty == null) { 129 | throw new ArgumentNullException("sourceProperty"); 130 | } 131 | 132 | sourceProperty = sourceProperty.Copy(); 133 | destProperty = destProperty.Copy(); 134 | 135 | CopyPropertyValueSingular(destProperty, sourceProperty); 136 | 137 | if (sourceProperty.hasChildren) { 138 | int elementPropertyDepth = sourceProperty.depth; 139 | while (sourceProperty.Next(true) && destProperty.Next(true) && sourceProperty.depth > elementPropertyDepth) { 140 | CopyPropertyValueSingular(destProperty, sourceProperty); 141 | } 142 | } 143 | } 144 | 145 | private static void CopyPropertyValueSingular(SerializedProperty destProperty, SerializedProperty sourceProperty) 146 | { 147 | switch (destProperty.propertyType) { 148 | case SerializedPropertyType.Integer: 149 | destProperty.intValue = sourceProperty.intValue; 150 | break; 151 | 152 | case SerializedPropertyType.Boolean: 153 | destProperty.boolValue = sourceProperty.boolValue; 154 | break; 155 | 156 | case SerializedPropertyType.Float: 157 | destProperty.floatValue = sourceProperty.floatValue; 158 | break; 159 | 160 | case SerializedPropertyType.String: 161 | destProperty.stringValue = sourceProperty.stringValue; 162 | break; 163 | 164 | case SerializedPropertyType.Color: 165 | destProperty.colorValue = sourceProperty.colorValue; 166 | break; 167 | 168 | case SerializedPropertyType.ObjectReference: 169 | destProperty.objectReferenceValue = sourceProperty.objectReferenceValue; 170 | break; 171 | 172 | case SerializedPropertyType.LayerMask: 173 | destProperty.intValue = sourceProperty.intValue; 174 | break; 175 | 176 | case SerializedPropertyType.Enum: 177 | destProperty.enumValueIndex = sourceProperty.enumValueIndex; 178 | break; 179 | 180 | case SerializedPropertyType.Vector2: 181 | destProperty.vector2Value = sourceProperty.vector2Value; 182 | break; 183 | 184 | case SerializedPropertyType.Vector3: 185 | destProperty.vector3Value = sourceProperty.vector3Value; 186 | break; 187 | 188 | case SerializedPropertyType.Vector4: 189 | destProperty.vector4Value = sourceProperty.vector4Value; 190 | break; 191 | 192 | case SerializedPropertyType.Rect: 193 | destProperty.rectValue = sourceProperty.rectValue; 194 | break; 195 | 196 | case SerializedPropertyType.ArraySize: 197 | destProperty.intValue = sourceProperty.intValue; 198 | break; 199 | 200 | case SerializedPropertyType.Character: 201 | destProperty.intValue = sourceProperty.intValue; 202 | break; 203 | 204 | case SerializedPropertyType.AnimationCurve: 205 | destProperty.animationCurveValue = sourceProperty.animationCurveValue; 206 | break; 207 | 208 | case SerializedPropertyType.Bounds: 209 | destProperty.boundsValue = sourceProperty.boundsValue; 210 | break; 211 | 212 | case SerializedPropertyType.Gradient: 213 | //!TODO: Amend when Unity add a public API for setting the gradient. 214 | break; 215 | } 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/ExtraEditorStyles.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | using UnityEditor; 5 | using UnityEngine; 6 | 7 | namespace Rotorz.Games.UnityEditorExtensions 8 | { 9 | /// 10 | /// Extra styles for editor user interfaces. 11 | /// 12 | public sealed class ExtraEditorStyles : EditorSingletonScriptableObject 13 | { 14 | private static ExtraEditorStyles s_Instance; 15 | private static SkinInfo s_Skin; 16 | 17 | 18 | /// 19 | /// Gets the one-and-only instance. 20 | /// 21 | public static ExtraEditorStyles Instance { 22 | get { 23 | EditorSingletonUtility.GetAssetInstance(ref s_Instance); 24 | return s_Instance; 25 | } 26 | } 27 | 28 | /// 29 | /// Gets the current skin. 30 | /// 31 | public static SkinInfo Skin { 32 | get { 33 | if (s_Skin == null) { 34 | s_Skin = EditorGUIUtility.isProSkin ? Instance.darkSkin : Instance.lightSkin; 35 | } 36 | return s_Skin; 37 | } 38 | } 39 | 40 | 41 | [SerializeField] 42 | private SkinInfo darkSkin = new SkinInfo(); 43 | [SerializeField] 44 | private SkinInfo lightSkin = new SkinInfo(); 45 | 46 | 47 | public GUIStyle BigButton { get; private set; } 48 | public GUIStyle BigButtonLeftAligned { get; private set; } 49 | public GUIStyle BigButtonRightAligned { get; private set; } 50 | public GUIStyle BigButtonPadded { get; private set; } 51 | 52 | public GUIStyle WhiteWordWrappedMiniLabel { get; private set; } 53 | public GUIStyle BoldLabel { get; private set; } 54 | public GUIStyle RightAlignedMiniLabel { get; internal set; } 55 | public GUIStyle GroupLabel { get; private set; } 56 | 57 | public GUIStyle WhiteMetaLabel { get; private set; } 58 | public GUIStyle MetaLabel { get; private set; } 59 | public GUIStyle MetaLinkButton { get; private set; } 60 | 61 | public GUIStyle SearchTextField { get; private set; } 62 | public GUIStyle SearchCancelButton { get; private set; } 63 | public GUIStyle SearchCancelButtonEmpty { get; private set; } 64 | 65 | public GUIStyle ListItem { get; private set; } 66 | public GUIStyle ListItemActive { get; private set; } 67 | 68 | public GUIStyle Separator { get; private set; } 69 | 70 | public GUIStyle TrailingTip { get; private set; } 71 | 72 | 73 | /// 74 | protected override void OnInitialize() 75 | { 76 | var skin = GUI.skin; 77 | var hiLabelStyle = skin.FindStyle("Hi Label"); 78 | 79 | this.BigButton = new GUIStyle(skin.button); 80 | this.BigButton.padding = new RectOffset(26, 27, 10, 10); 81 | this.BigButton.richText = true; 82 | 83 | this.BigButtonLeftAligned = new GUIStyle(this.BigButton); 84 | this.BigButtonLeftAligned.alignment = TextAnchor.MiddleLeft; 85 | 86 | this.BigButtonRightAligned = new GUIStyle(this.BigButton); 87 | this.BigButtonRightAligned.alignment = TextAnchor.MiddleRight; 88 | 89 | this.BigButtonPadded = new GUIStyle(this.BigButton); 90 | this.BigButtonPadded.padding.left = 34; 91 | this.BigButtonPadded.padding.right = 35; 92 | 93 | this.WhiteWordWrappedMiniLabel = new GUIStyle(EditorStyles.whiteMiniLabel); 94 | this.WhiteWordWrappedMiniLabel.wordWrap = true; 95 | 96 | this.BoldLabel = new GUIStyle(EditorStyles.label); 97 | this.BoldLabel.fontStyle = FontStyle.Bold; 98 | 99 | this.RightAlignedMiniLabel = new GUIStyle(EditorStyles.miniLabel); 100 | this.RightAlignedMiniLabel.alignment = TextAnchor.MiddleRight; 101 | 102 | this.GroupLabel = new GUIStyle(); 103 | this.GroupLabel.fontSize = 20; 104 | this.GroupLabel.fontStyle = FontStyle.Normal; 105 | this.GroupLabel.normal.textColor = Skin.GroupLabelColor; 106 | this.GroupLabel.margin = new RectOffset(5, 5, 6, 1); 107 | 108 | this.WhiteMetaLabel = new GUIStyle(); 109 | this.WhiteMetaLabel.fontSize = 11; 110 | this.WhiteMetaLabel.fontStyle = FontStyle.Normal; 111 | this.WhiteMetaLabel.normal.textColor = Color.white; 112 | this.WhiteMetaLabel.alignment = TextAnchor.UpperLeft; 113 | this.WhiteMetaLabel.clipping = TextClipping.Clip; 114 | this.WhiteMetaLabel.richText = true; 115 | 116 | this.MetaLabel = new GUIStyle(this.WhiteMetaLabel); 117 | this.MetaLabel.normal.textColor = Skin.MetaLabelColor; 118 | 119 | this.MetaLinkButton = new GUIStyle(this.MetaLabel); 120 | this.MetaLinkButton.normal.textColor = Color.white; 121 | this.MetaLinkButton.hover.textColor = Color.white; 122 | this.MetaLinkButton.hover.background = Skin.UnderlineBackground; 123 | this.MetaLinkButton.border = new RectOffset(0, 0, 1, 1); 124 | this.MetaLinkButton.fixedHeight = 14; 125 | this.MetaLinkButton.richText = true; 126 | 127 | this.SearchTextField = new GUIStyle(skin.FindStyle("SearchTextField")); 128 | this.SearchCancelButton = new GUIStyle(skin.FindStyle("SearchCancelButton")); 129 | this.SearchCancelButtonEmpty = new GUIStyle(skin.FindStyle("SearchCancelButtonEmpty")); 130 | 131 | this.ListItem = new GUIStyle(skin.label); 132 | this.ListItem.margin = new RectOffset(); 133 | this.ListItem.padding = new RectOffset(5, 5, 0, 0); 134 | this.ListItem.alignment = TextAnchor.MiddleLeft; 135 | this.ListItem.onNormal.background = hiLabelStyle.onActive.background; 136 | this.ListItem.onNormal.textColor = Color.white; 137 | this.ListItem.fixedHeight = 25; 138 | 139 | this.ListItemActive = new GUIStyle(this.ListItem); 140 | this.ListItemActive.fontStyle = FontStyle.Bold; 141 | 142 | this.Separator = new GUIStyle(); 143 | this.Separator.normal.background = EditorGUIUtility.whiteTexture; 144 | this.Separator.stretchWidth = true; 145 | 146 | this.TrailingTip = new GUIStyle(); 147 | this.TrailingTip.margin = new RectOffset(2, 2, 0, 0); 148 | this.TrailingTip.padding = new RectOffset(6, 6, 9, 6); 149 | this.TrailingTip.border = new RectOffset(32, 4, 8, 4); 150 | this.TrailingTip.wordWrap = true; 151 | this.TrailingTip.normal.background = Skin.TrailingTipBackground; 152 | this.TrailingTip.normal.textColor = EditorGUIUtility.isProSkin 153 | ? new Color32(140, 140, 140, 255) 154 | : new Color32(59, 59, 59, 255); 155 | } 156 | 157 | 158 | [System.Serializable] 159 | public sealed class SkinInfo 160 | { 161 | [SerializeField] 162 | private Color windowBackgroundColor = Color.black; 163 | [SerializeField] 164 | private Color separatorColor = Color.black; 165 | [SerializeField] 166 | private Color separatorLightColor = Color.black; 167 | [SerializeField] 168 | private Color groupLabelColor = Color.black; 169 | [SerializeField] 170 | private Color metaLabelColor = Color.black; 171 | [SerializeField] 172 | private Color linkColor = Color.black; 173 | [SerializeField] 174 | private Color selectedHighlightColor = Color.black; 175 | [SerializeField] 176 | private Color selectedHighlightStrongColor = Color.black; 177 | 178 | 179 | [SerializeField] 180 | private Texture2D texTrailingTipBackground = null; 181 | [SerializeField] 182 | private Texture2D underlineBackground = null; 183 | 184 | 185 | public Color WindowBackgroundColor { 186 | get { return this.windowBackgroundColor; } 187 | } 188 | 189 | public Color SeparatorColor { 190 | get { return this.separatorColor; } 191 | } 192 | 193 | public Color SeparatorLightColor { 194 | get { return this.separatorLightColor; } 195 | } 196 | 197 | public Color GroupLabelColor { 198 | get { return this.groupLabelColor; } 199 | } 200 | 201 | public Color MetaLabelColor { 202 | get { return this.metaLabelColor; } 203 | } 204 | 205 | public Color LinkColor { 206 | get { return this.linkColor; } 207 | } 208 | 209 | public Color SelectedHighlightColor { 210 | get { return this.selectedHighlightColor; } 211 | } 212 | 213 | public Color SelectedHighlightStrongColor { 214 | get { return this.selectedHighlightStrongColor; } 215 | } 216 | 217 | 218 | public Texture2D TrailingTipBackground { 219 | get { return this.texTrailingTipBackground; } 220 | } 221 | 222 | public Texture2D UnderlineBackground { 223 | get { return this.underlineBackground; } 224 | } 225 | } 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/ControlContent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using UnityEditor; 7 | using UnityEngine; 8 | 9 | namespace Rotorz.Games.UnityEditorExtensions 10 | { 11 | /// 12 | /// A structure that holds editor control content. When used correctly the wrapped 13 | /// instance will be recycled which helps to 14 | /// improve editor GUI performance by avoiding allocation / garbage collection. 15 | /// 16 | /// 17 | /// This structure implements the interface and is 18 | /// intended to be used with the using language construct: 19 | /// 27 | /// As a reminder, multiple using constructs can be defined adjacently: 28 | /// 34 | /// 35 | public struct ControlContent : IDisposable 36 | { 37 | #region User-defined Display Preference 38 | 39 | private static readonly string EDITORPREFS_KEY_TRAILINGTIPSVISIBLE = typeof(ControlContent).FullName + ".TrailingTipsVisible"; 40 | 41 | 42 | private static bool s_TrailingTipsVisibleInitialized = false; 43 | private static bool s_TrailingTipsVisible; 44 | 45 | 46 | /// 47 | /// Gets or sets whether trailing tips are currently visible in user interfaces. 48 | /// This property is persisted using and 49 | /// can be user-controlled when exposed in user interfaces with some sort of 50 | /// "Show Tips" toggle control. 51 | /// 52 | public static bool TrailingTipsVisible { 53 | get { 54 | if (!s_TrailingTipsVisibleInitialized) { 55 | s_TrailingTipsVisible = EditorPrefs.GetBool(EDITORPREFS_KEY_TRAILINGTIPSVISIBLE, false); 56 | s_TrailingTipsVisibleInitialized = true; 57 | } 58 | return s_TrailingTipsVisible; 59 | } 60 | set { 61 | if (value == s_TrailingTipsVisible) { 62 | return; 63 | } 64 | 65 | s_TrailingTipsVisibleInitialized = true; 66 | s_TrailingTipsVisible = value; 67 | EditorPrefs.SetBool(EDITORPREFS_KEY_TRAILINGTIPSVISIBLE, s_TrailingTipsVisible); 68 | 69 | OnTrailingTipsVisibleChanged(); 70 | } 71 | } 72 | 73 | 74 | /// 75 | /// Occurs when the value of the property 76 | /// changes. This is usefulw hen you want to repaint user interfaces whenever 77 | /// this preference is changed. 78 | /// 79 | public static event Action TrailingTipsVisibleChanged; 80 | 81 | private static void OnTrailingTipsVisibleChanged() 82 | { 83 | var handler = TrailingTipsVisibleChanged; 84 | if (handler != null) { 85 | handler.Invoke(); 86 | } 87 | } 88 | 89 | #endregion 90 | 91 | 92 | #region GUIContent Pooling 93 | 94 | private static readonly Stack s_GUIContentPool = new Stack(); 95 | 96 | 97 | private static GUIContent SpawnGUIContent(string labelText, Texture image, string tipText) 98 | { 99 | GUIContent content; 100 | if (s_GUIContentPool.Count != 0) { 101 | content = s_GUIContentPool.Pop(); 102 | } 103 | else { 104 | content = new GUIContent(); 105 | } 106 | 107 | content.text = labelText; 108 | content.image = image; 109 | content.tooltip = tipText; 110 | 111 | return content; 112 | } 113 | 114 | private static void DespawnGUIContent(GUIContent content) 115 | { 116 | ResetContent(content); 117 | s_GUIContentPool.Push(content); 118 | } 119 | 120 | private static void ResetContent(GUIContent content) 121 | { 122 | content.text = null; 123 | content.image = null; 124 | content.tooltip = null; 125 | } 126 | 127 | #endregion 128 | 129 | 130 | /// 131 | /// Gets basic control content with label text, an image and optional tip text. 132 | /// 133 | /// 134 | /// 139 | /// 140 | /// Label text. 141 | /// Image texture. 142 | /// Tip text. 143 | /// 144 | /// The control content. 145 | /// 146 | public static ControlContent Basic(string labelText, Texture image, string tipText = null) 147 | { 148 | ControlContent content = default(ControlContent); 149 | 150 | content.LabelContent = SpawnGUIContent(labelText, image, tipText); 151 | content.TrailingTipText = !string.IsNullOrEmpty(tipText) 152 | ? tipText 153 | : null; 154 | 155 | return content; 156 | } 157 | 158 | /// 159 | /// Gets basic control content with label text and optional tip text. 160 | /// 161 | /// 162 | /// 167 | /// 168 | /// Label text. 169 | /// Tip text. 170 | /// 171 | /// The control content. 172 | /// 173 | public static ControlContent Basic(string labelText, string tipText = null) 174 | { 175 | return Basic(labelText, null, tipText); 176 | } 177 | 178 | /// 179 | /// Gets basic control content with an image and optional tip text. 180 | /// 181 | /// 182 | /// 188 | /// 189 | /// Image texture. 190 | /// Tip text. 191 | /// 192 | /// The control content. 193 | /// 194 | public static ControlContent Basic(Texture image, string tipText = null) 195 | { 196 | return Basic(null, image, tipText); 197 | } 198 | 199 | 200 | /// 201 | /// Gets control content with label text, an image and trailing tip text that is 202 | /// either shown as a tooltip on the main content or as a trailing tip below the 203 | /// control content when is true. 204 | /// 205 | /// 206 | /// 216 | /// 217 | /// Label text. 218 | /// Image texture. 219 | /// Tip text. 220 | /// 221 | /// The control content. 222 | /// 223 | public static ControlContent WithTrailableTip(string labelText, Texture image, string tipText) 224 | { 225 | ControlContent content = default(ControlContent); 226 | 227 | if (TrailingTipsVisible) { 228 | content.LabelContent = SpawnGUIContent(labelText, image, null); 229 | content.TrailingTipText = !string.IsNullOrEmpty(tipText) 230 | ? tipText 231 | : null; 232 | } 233 | else { 234 | content.LabelContent = SpawnGUIContent(labelText, image, tipText); 235 | content.TrailingTipText = null; 236 | } 237 | 238 | return content; 239 | } 240 | 241 | /// 242 | /// Gets control content with label text and trailing tip text that is either 243 | /// shown as a tooltip on the main content or as a trailing tip below the control 244 | /// content when is true. 245 | /// 246 | /// 247 | /// 257 | /// 258 | /// Label text. 259 | /// Tip text. 260 | /// 261 | /// The control content. 262 | /// 263 | public static ControlContent WithTrailableTip(string labelText, string tipText) 264 | { 265 | return WithTrailableTip(labelText, null, tipText); 266 | } 267 | 268 | /// 269 | /// Gets control content with an image and trailing tip text that is either shown 270 | /// as a tooltip on the main content or as a trailing tip below the control 271 | /// content when is true. 272 | /// 273 | /// 274 | /// 284 | /// 285 | /// Image texture. 286 | /// Tip text. 287 | /// 288 | /// The control content. 289 | /// 290 | public static ControlContent WithTrailableTip(Texture image, string tipText) 291 | { 292 | return WithTrailableTip(null, image, tipText); 293 | } 294 | 295 | 296 | /// 297 | /// Gets the main control label content. 298 | /// 299 | /// 300 | /// Only includes tip text when is 301 | /// false since the tip will otherwise be shown as a trailing tip below. 302 | /// 303 | public GUIContent LabelContent { get; private set; } 304 | 305 | /// 306 | /// Gets the trailing tip text. 307 | /// 308 | public string TrailingTipText { get; private set; } 309 | 310 | 311 | /// 312 | public void Dispose() 313 | { 314 | if (this.LabelContent != null && !ReferenceEquals(this.LabelContent, GUIContent.none)) { 315 | var content = this.LabelContent; 316 | DespawnGUIContent(content); 317 | this.LabelContent = GUIContent.none; 318 | } 319 | } 320 | 321 | 322 | /// 323 | /// Implicitly converts into . 324 | /// 325 | /// The control content. 326 | public static implicit operator GUIContent(ControlContent content) 327 | { 328 | return content.LabelContent; 329 | } 330 | } 331 | } 332 | -------------------------------------------------------------------------------- /assets/Editor/UnityEditorExtensions/ExtraEditorGUI.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Rotorz Limited. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root. 3 | 4 | using System; 5 | using System.Reflection; 6 | using UnityEditor; 7 | using UnityEngine; 8 | 9 | namespace Rotorz.Games.UnityEditorExtensions 10 | { 11 | /// 12 | /// Extra GUI functionality for editor interfaces. 13 | /// 14 | public static class ExtraEditorGUI 15 | { 16 | static ExtraEditorGUI() 17 | { 18 | InitSpecial(); 19 | } 20 | 21 | 22 | /// 23 | /// Indicates that no layout options are to be specified. 24 | /// 25 | /// 26 | /// Avoids implied allocation of empty arrays when invoking GUI layout functions. 27 | /// 28 | internal static readonly GUILayoutOption[] None = null; 29 | 30 | 31 | #region Special 32 | 33 | private static void InitSpecial() 34 | { 35 | var tyGUIClip = typeof(GUI).Assembly.GetType("UnityEngine.GUIClip"); 36 | if (tyGUIClip != null) { 37 | var piVisibleRect = tyGUIClip.GetProperty("visibleRect", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); 38 | if (piVisibleRect != null) { 39 | var getMethod = piVisibleRect.GetGetMethod(true) ?? piVisibleRect.GetGetMethod(false); 40 | s_VisibleRect = (Func)Delegate.CreateDelegate(typeof(Func), getMethod); 41 | } 42 | } 43 | } 44 | 45 | private static Func s_VisibleRect; 46 | 47 | /// 48 | /// Gets rectangle of visible GUI area (TopmostRect + scrollViewOffsets). 49 | /// 50 | public static Rect VisibleRect { 51 | get { return s_VisibleRect(); } 52 | } 53 | 54 | #endregion 55 | 56 | 57 | #region Labels 58 | 59 | /// 60 | /// Output description text using small label font. 61 | /// 62 | /// Label text. 63 | public static void MiniFieldDescription(string label) 64 | { 65 | Color restore = GUI.contentColor; 66 | GUI.color = new Color32(92, 92, 92, 255); 67 | GUILayout.Label(label, ExtraEditorStyles.Instance.WhiteWordWrappedMiniLabel, None); 68 | GUI.color = restore; 69 | } 70 | 71 | #endregion 72 | 73 | 74 | #region Link Buttons 75 | 76 | private static int s_HoverControlID; 77 | 78 | internal static bool LinkButton(Rect position, string text, GUIStyle style) 79 | { 80 | int controlID = GUIUtility.GetControlID(FocusType.Passive); 81 | 82 | EditorGUIUtility.AddCursorRect(position, MouseCursor.Link); 83 | 84 | bool isMouseOverControl = position.Contains(Event.current.mousePosition); 85 | 86 | switch (Event.current.GetTypeForControl(controlID)) { 87 | case EventType.MouseDown: 88 | if (isMouseOverControl) { 89 | GUIUtility.hotControl = controlID; 90 | Event.current.Use(); 91 | } 92 | break; 93 | 94 | case EventType.MouseUp: 95 | if (controlID == GUIUtility.hotControl) { 96 | Event.current.Use(); 97 | if (isMouseOverControl) { 98 | return true; 99 | } 100 | else { 101 | s_HoverControlID = 0; 102 | } 103 | } 104 | break; 105 | 106 | case EventType.MouseMove: 107 | int newHoverControlID = s_HoverControlID; 108 | 109 | if (isMouseOverControl) { 110 | newHoverControlID = controlID; 111 | } 112 | else if (s_HoverControlID == controlID) { 113 | newHoverControlID = 0; 114 | } 115 | 116 | if (newHoverControlID != s_HoverControlID) { 117 | s_HoverControlID = newHoverControlID; 118 | Event.current.Use(); 119 | } 120 | break; 121 | 122 | case EventType.MouseDrag: 123 | if (controlID == GUIUtility.hotControl) { 124 | s_HoverControlID = isMouseOverControl ? controlID : 0; 125 | Event.current.Use(); 126 | } 127 | break; 128 | 129 | case EventType.Repaint: 130 | Color restoreColor = GUI.color; 131 | GUI.color = ExtraEditorStyles.Skin.LinkColor; 132 | style.Draw(position, text, isMouseOverControl, false, false, false); 133 | GUI.color = restoreColor; 134 | break; 135 | } 136 | 137 | return false; 138 | } 139 | 140 | internal static bool MetaLinkButton(Rect position, string text) 141 | { 142 | return LinkButton(position, text, ExtraEditorStyles.Instance.MetaLinkButton); 143 | } 144 | 145 | #endregion 146 | 147 | 148 | #region Icon Buttons 149 | 150 | private static readonly int s_IconButtonHint = "_IconButton_".GetHashCode(); 151 | 152 | 153 | public static bool IconButton(Rect position, bool visible, Texture2D iconNormal, Texture2D iconActive, GUIStyle style) 154 | { 155 | int controlID = GUIUtility.GetControlID(s_IconButtonHint, FocusType.Passive); 156 | bool result = false; 157 | 158 | position.height += 1; 159 | 160 | switch (Event.current.GetTypeForControl(controlID)) { 161 | case EventType.MouseDown: 162 | // Do not allow button to be pressed using right mouse button since 163 | // context menu should be shown instead! 164 | if (GUI.enabled && Event.current.button != 1 && position.Contains(Event.current.mousePosition)) { 165 | GUIUtility.hotControl = controlID; 166 | GUIUtility.keyboardControl = 0; 167 | Event.current.Use(); 168 | } 169 | break; 170 | 171 | case EventType.MouseDrag: 172 | if (GUIUtility.hotControl == controlID) { 173 | Event.current.Use(); 174 | } 175 | break; 176 | 177 | case EventType.MouseUp: 178 | if (GUIUtility.hotControl == controlID) { 179 | GUIUtility.hotControl = 0; 180 | result = position.Contains(Event.current.mousePosition); 181 | Event.current.Use(); 182 | } 183 | break; 184 | 185 | case EventType.Repaint: 186 | if (visible) { 187 | bool isActive = GUIUtility.hotControl == controlID && position.Contains(Event.current.mousePosition); 188 | using (var tempContent = ControlContent.Basic(isActive ? iconActive : iconNormal)) { 189 | position.height -= 1; 190 | style.Draw(position, tempContent, isActive, isActive, false, false); 191 | } 192 | } 193 | break; 194 | } 195 | 196 | return result; 197 | } 198 | 199 | public static bool IconButton(Rect position, Texture2D iconNormal, Texture2D iconActive, GUIStyle style) 200 | { 201 | return IconButton(position, true, iconNormal, iconActive, style); 202 | } 203 | 204 | #endregion 205 | 206 | 207 | #region Prefix Labels 208 | 209 | /// 210 | /// Prefix label to show above control. 211 | /// 212 | /// Text for label. 213 | /// Style for prefix label. 214 | public static void AbovePrefixLabel(string text, GUIStyle style) 215 | { 216 | using (var labelContent = ControlContent.Basic(text)) { 217 | Rect position = GUILayoutUtility.GetRect(labelContent, style); 218 | EditorGUI.HandlePrefixLabel(position, position, labelContent, 0, style); 219 | } 220 | } 221 | 222 | /// 223 | /// Prefix label to show above control. 224 | /// 225 | /// Text for label. 226 | public static void AbovePrefixLabel(string text) 227 | { 228 | AbovePrefixLabel(text, EditorStyles.label); 229 | } 230 | 231 | /// 232 | /// Prefix label to display above multi-part field. 233 | /// 234 | /// 235 | /// Example of control which behaves similar to EditorGUI.Vector3Field: 236 | /// 244 | /// 245 | /// Text for label. 246 | public static void MultiPartPrefixLabel(string text) 247 | { 248 | AbovePrefixLabel(text); 249 | GUIUtility.GetControlID(FocusType.Keyboard); 250 | } 251 | 252 | #endregion 253 | 254 | 255 | #region Separators 256 | 257 | private static void SeparatorHelper(int marginTop, int marginBottom, int thickness, Color color) 258 | { 259 | Rect position = GUILayoutUtility.GetRect(0, marginTop + thickness + marginBottom, None); 260 | 261 | if (Event.current.type == EventType.Repaint) { 262 | position.y += marginTop; 263 | position.height = thickness; 264 | 265 | position = EditorGUI.IndentedRect(position); 266 | 267 | Color restoreColor = GUI.color; 268 | GUI.color = color; 269 | ExtraEditorStyles.Instance.Separator.Draw(position, false, false, false, false); 270 | GUI.color = restoreColor; 271 | } 272 | } 273 | 274 | /// 275 | /// Draw splitter of specified color. 276 | /// 277 | /// Color for splitter. 278 | /// Margin above splitter. 279 | /// Margin below splitter. 280 | /// Thickness of splitter in pixels. 281 | public static void Separator(Color color, int marginTop = 3, int marginBottom = 3, int thickness = 1) 282 | { 283 | SeparatorHelper(marginTop, marginBottom, thickness, color); 284 | } 285 | 286 | /// 287 | /// Draw splitter of specified color. 288 | /// 289 | /// Position of which to draw splitter. 290 | /// Color for splitter. 291 | public static void Separator(Rect position, Color color) 292 | { 293 | if (Event.current.type == EventType.Repaint) { 294 | Color restoreColor = GUI.color; 295 | GUI.color = color; 296 | ExtraEditorStyles.Instance.Separator.Draw(position, false, false, false, false); 297 | GUI.color = restoreColor; 298 | } 299 | } 300 | 301 | /// 302 | /// Draw simple grey splitter. 303 | /// 304 | /// Margin above splitter. 305 | /// Margin below splitter. 306 | /// Thickness of splitter in pixels. 307 | public static void Separator(int marginTop = 3, int marginBottom = 3, int thickness = 1) 308 | { 309 | SeparatorHelper(marginTop, marginBottom, thickness, ExtraEditorStyles.Skin.SeparatorColor); 310 | } 311 | 312 | /// 313 | /// Draw simple grey splitter (lighter than ). 314 | /// 315 | /// Margin above splitter. 316 | /// Margin below splitter. 317 | /// Thickness of splitter in pixels. 318 | public static void SeparatorLight(int marginTop = 3, int marginBottom = 3, int thickness = 1) 319 | { 320 | SeparatorHelper(marginTop, marginBottom, thickness, ExtraEditorStyles.Skin.SeparatorLightColor); 321 | } 322 | 323 | /// 324 | /// Draw simple grey splitter. 325 | /// 326 | /// Position of which to draw splitter. 327 | public static void Separator(Rect position) 328 | { 329 | Separator(position, ExtraEditorStyles.Skin.SeparatorColor); 330 | } 331 | 332 | /// 333 | /// Draw simple light grey splitter (lighter than ). 334 | /// 335 | /// Position of which to draw splitter. 336 | public static void SeparatorLight(Rect position) 337 | { 338 | if (Event.current.type == EventType.Repaint) { 339 | Color restoreColor = GUI.color; 340 | GUI.color = ExtraEditorStyles.Skin.SeparatorLightColor; 341 | ExtraEditorStyles.Instance.Separator.Draw(position, false, false, false, false); 342 | GUI.color = restoreColor; 343 | } 344 | } 345 | 346 | #endregion 347 | 348 | 349 | #region Toggle Left Controls 350 | 351 | public static void ToggleLeft(Rect position, SerializedProperty prop, GUIContent label) 352 | { 353 | bool hasMultipleDifferentValues = prop.hasMultipleDifferentValues; 354 | bool value = hasMultipleDifferentValues ? false : prop.boolValue; 355 | 356 | bool restoreShowMixedValue = EditorGUI.showMixedValue; 357 | EditorGUI.showMixedValue = hasMultipleDifferentValues; 358 | 359 | EditorGUI.BeginChangeCheck(); 360 | value = EditorGUI.ToggleLeft(position, label, value); 361 | if (EditorGUI.EndChangeCheck()) { 362 | prop.boolValue = value; 363 | } 364 | 365 | EditorGUI.showMixedValue = restoreShowMixedValue; 366 | } 367 | 368 | public static void ToggleLeft(Rect position, SerializedProperty prop, string label) 369 | { 370 | using (var labelContent = ControlContent.Basic(label)) { 371 | ToggleLeft(position, prop, labelContent); 372 | } 373 | } 374 | 375 | public static void ToggleLeft(SerializedProperty prop, GUIContent label) 376 | { 377 | Rect position = EditorGUILayout.GetControlRect(true); 378 | ToggleLeft(position, prop, label); 379 | } 380 | 381 | public static void ToggleLeft(SerializedProperty prop, string label) 382 | { 383 | using (var labelContent = ControlContent.Basic(label)) { 384 | ToggleLeft(prop, labelContent); 385 | } 386 | } 387 | 388 | #endregion 389 | 390 | 391 | #region Vertical Splitter 392 | 393 | private static int s_AnchorContainerListWidth; 394 | private static int s_AnchorMousePosition; 395 | 396 | /// 397 | /// Handles interaction with a vertical splitter in a user interface. This control 398 | /// does not paint a visual representation of the vertical splitter; consider using 399 | /// for that. 400 | /// 401 | /// Position of vertical splitter in GUI. 402 | /// Current width of vertical panel. 403 | /// Default width of vertical panel is restored when user 404 | /// double-clicks on the vertical splitter control. 405 | /// 406 | /// New width of vertical panel. 407 | /// 408 | public static int VerticalSplitter(Rect position, int width, int defaultWidth) 409 | { 410 | position.x -= 3; 411 | position.width += 6; 412 | 413 | int controlID = GUIUtility.GetControlID(FocusType.Passive); 414 | 415 | EditorGUIUtility.AddCursorRect(position, MouseCursor.SplitResizeLeftRight); 416 | 417 | switch (Event.current.GetTypeForControl(controlID)) { 418 | case EventType.MouseDown: 419 | if (position.Contains(Event.current.mousePosition)) { 420 | if (Event.current.clickCount == 2) { 421 | width = defaultWidth; 422 | } 423 | else { 424 | GUIUtility.hotControl = controlID; 425 | s_AnchorContainerListWidth = width; 426 | s_AnchorMousePosition = (int)Event.current.mousePosition.x; 427 | } 428 | GUIUtility.keyboardControl = 0; 429 | Event.current.Use(); 430 | } 431 | break; 432 | 433 | case EventType.MouseUp: 434 | if (GUIUtility.hotControl == controlID) { 435 | GUIUtility.hotControl = 0; 436 | Event.current.Use(); 437 | } 438 | break; 439 | 440 | case EventType.MouseDrag: 441 | if (GUIUtility.hotControl == controlID) { 442 | int mousePosition = (int)Event.current.mousePosition.x; 443 | width = s_AnchorContainerListWidth + (mousePosition - s_AnchorMousePosition); 444 | Event.current.Use(); 445 | } 446 | break; 447 | } 448 | 449 | return width; 450 | } 451 | 452 | #endregion 453 | 454 | 455 | #region Trailing Tips 456 | 457 | public static void TrailingTip(string tipText) 458 | { 459 | if (string.IsNullOrEmpty(tipText)) { 460 | return; 461 | } 462 | 463 | using (var labelContent = ControlContent.Basic(tipText)) { 464 | Rect position = GUILayoutUtility.GetRect(labelContent, ExtraEditorStyles.Instance.TrailingTip); 465 | position.y -= 2; 466 | 467 | EditorGUI.LabelField(position, labelContent, ExtraEditorStyles.Instance.TrailingTip); 468 | } 469 | } 470 | 471 | public static void TrailingTip(ControlContent content) 472 | { 473 | TrailingTip(content.TrailingTipText); 474 | } 475 | 476 | #endregion 477 | 478 | 479 | #region Texture Drawing 480 | 481 | private static GUIStyle s_DrawTextureTempStyle = new GUIStyle(); 482 | 483 | 484 | /// 485 | /// Draw texture using to workaround bug in Unity where 486 | /// flickers when embedded inside a property drawer. 487 | /// 488 | /// Position of which to draw texture in space of GUI. 489 | /// Texture. 490 | public static void DrawTexture(Rect position, Texture2D texture) 491 | { 492 | if (Event.current.type != EventType.Repaint) { 493 | return; 494 | } 495 | 496 | s_DrawTextureTempStyle.normal.background = texture; 497 | s_DrawTextureTempStyle.Draw(position, GUIContent.none, false, false, false, false); 498 | s_DrawTextureTempStyle.normal.background = null; 499 | } 500 | 501 | #endregion 502 | 503 | 504 | #region Input Handling 505 | 506 | /// 507 | /// Test for "Return" key-down event; this is useful for accepting input. 508 | /// 509 | /// 510 | /// 515 | /// 516 | /// 517 | /// A value of true if return key was used to accept user input; otherwise, 518 | /// a value of false. 519 | /// 520 | public static bool AcceptKeyboardReturn() 521 | { 522 | if (Event.current.rawType == EventType.KeyDown && Event.current.keyCode == KeyCode.Return) { 523 | GUIUtility.keyboardControl = 0; 524 | Event.current.Use(); 525 | return true; 526 | } 527 | return false; 528 | } 529 | 530 | #endregion 531 | 532 | 533 | #region Metrics 534 | 535 | /// 536 | /// Convert rectangle from window space to screen space. 537 | /// 538 | /// GUI Rectangle. 539 | /// 540 | /// Screen rectangle. 541 | /// 542 | public static Rect GUIToScreenRect(Rect guiRect) 543 | { 544 | Vector2 screenPoint = EditorGUIUtility.GUIToScreenPoint(new Vector2(guiRect.x, guiRect.y)); 545 | return new Rect(screenPoint.x, screenPoint.y, guiRect.width, guiRect.height); 546 | } 547 | 548 | #endregion 549 | } 550 | } 551 | --------------------------------------------------------------------------------