diff --git a/Editor/Mono/2D/SpriteAtlas/SpriteAtlasInspector.cs b/Editor/Mono/2D/SpriteAtlas/SpriteAtlasInspector.cs index 951f61703b..db10617930 100644 --- a/Editor/Mono/2D/SpriteAtlas/SpriteAtlasInspector.cs +++ b/Editor/Mono/2D/SpriteAtlas/SpriteAtlasInspector.cs @@ -64,7 +64,7 @@ class Styles public readonly GUIContent packButton = EditorGUIUtility.TrTextContent("Pack Preview", "Pack this atlas."); public readonly GUIContent disabledPackLabel = EditorGUIUtility.TrTextContent("Sprite Atlas packing is disabled. Enable it in Edit > Settings > Editor.", null, EditorGUIUtility.GetHelpIcon(MessageType.Info)); - public readonly GUIContent packableListLabel = EditorGUIUtility.TrTextContent("Objects for Packing", "Only accept Folder, Sprite Sheet(Texture) and Sprite."); + public readonly GUIContent packableListLabel = EditorGUIUtility.TrTextContent("Objects for Packing", "Only accept Folder, Sprite Sheet (Texture) and Sprite."); public readonly GUIContent notPowerOfTwoWarning = EditorGUIUtility.TrTextContent("This scale will produce a Sprite Atlas variant with a packed texture that is NPOT (non - power of two). This may cause visual artifacts in certain compression/texture formats."); diff --git a/Editor/Mono/2D/SpriteEditorModule/SpriteFrameModule/SpriteFrameModule.cs b/Editor/Mono/2D/SpriteEditorModule/SpriteFrameModule/SpriteFrameModule.cs index bb333c5ce9..b288ecf72a 100644 --- a/Editor/Mono/2D/SpriteEditorModule/SpriteFrameModule/SpriteFrameModule.cs +++ b/Editor/Mono/2D/SpriteEditorModule/SpriteFrameModule/SpriteFrameModule.cs @@ -268,8 +268,6 @@ UnityTexture2D GetTextureToSlice() return readableTexture; // we want to slice based on the original texture slice. Upscale the imported texture var texture = UnityEditor.SpriteUtility.CreateTemporaryDuplicate(readableTexture, width, height); - if (texture != null) - texture.filterMode = texture.filterMode; return texture; } @@ -303,7 +301,7 @@ public void ScaleSpriteRect(Rect r) public void TrimAlpha() { - var texture = m_TextureDataProvider.GetReadableTexture2D(); + var texture = GetTextureToSlice(); if (texture == null) return; @@ -346,6 +344,7 @@ public void TrimAlpha() spriteEditor.SetDataModified(); selected.rect = rect; + PopulateSpriteFrameInspectorField(); } } diff --git a/Editor/Mono/Animation/AnimationUtility.bindings.cs b/Editor/Mono/Animation/AnimationUtility.bindings.cs index 60db90a02c..27f2e3dea5 100644 --- a/Editor/Mono/Animation/AnimationUtility.bindings.cs +++ b/Editor/Mono/Animation/AnimationUtility.bindings.cs @@ -298,6 +298,7 @@ internal static void SetKeyBroken(ref Keyframe key, bool broken) extern private static void Internal_SetKeyRightTangentMode(ref Keyframe key, TangentMode tangentMode); extern private static void Internal_SetKeyBroken(ref Keyframe key, bool broken); + [NativeThrows] extern internal static int AddInbetweenKey(AnimationCurve curve, float time); [Obsolete("GetAllCurves is deprecated. Use GetCurveBindings and GetObjectReferenceCurveBindings instead.")] diff --git a/Editor/Mono/Animation/AnimationWindow/AnimEditor.cs b/Editor/Mono/Animation/AnimationWindow/AnimEditor.cs index b24379daae..33ce6adb7a 100644 --- a/Editor/Mono/Animation/AnimationWindow/AnimEditor.cs +++ b/Editor/Mono/Animation/AnimationWindow/AnimEditor.cs @@ -820,6 +820,12 @@ static void KeyModified(ShortcutArguments args) animEditor.Repaint(); } + [Shortcut("Animation/Frame All", typeof(AnimationWindow), KeyCode.A)] + static void FrameAll(ShortcutArguments args) + { + ExecuteShortcut(args, animEditor => { animEditor.triggerFraming = true; }); + } + private void PlayButtonOnGUI() { EditorGUI.BeginChangeCheck(); diff --git a/Editor/Mono/Animation/AnimationWindow/CurveEditor.cs b/Editor/Mono/Animation/AnimationWindow/CurveEditor.cs index 7c3285f878..3d896119c4 100644 --- a/Editor/Mono/Animation/AnimationWindow/CurveEditor.cs +++ b/Editor/Mono/Animation/AnimationWindow/CurveEditor.cs @@ -828,29 +828,17 @@ private void RecalculateSelectionBounds() m_SelectionBoundsAreDirty = false; } - // Frame all curves to be visible. - public void FrameClip(bool horizontally, bool vertically) + public Bounds GetClipBounds() { - Bounds frameBounds = curveBounds; - if (frameBounds.size == Vector3.zero) - return; - - if (horizontally) - SetShownHRangeInsideMargins(frameBounds.min.x, frameBounds.max.x); - if (vertically) - SetShownVRangeInsideMargins(frameBounds.min.y, frameBounds.max.y); + return curveBounds; } - // Frame selected keys to be visible. - public void FrameSelected(bool horizontally, bool vertically) + public Bounds GetSelectionBounds() { if (!hasSelection) - { - FrameClip(horizontally, vertically); - return; - } + return GetClipBounds(); - Bounds frameBounds = new Bounds(); + Bounds frameBounds; // Add neighboring keys in bounds if only a single key is selected. if (selectedCurves.Count == 1) @@ -875,6 +863,26 @@ public void FrameSelected(bool horizontally, bool vertically) // Enforce minimum size of bounds frameBounds.size = new Vector3(Mathf.Max(frameBounds.size.x, 0.1F), Mathf.Max(frameBounds.size.y, 0.1F), 0); + return frameBounds; + } + + // Frame all curves to be visible. + public void FrameClip(bool horizontally, bool vertically) + { + Frame(GetClipBounds(), horizontally, vertically); + } + + // Frame selected keys to be visible. + public void FrameSelected(bool horizontally, bool vertically) + { + Frame(GetSelectionBounds(), horizontally, vertically); + } + + public void Frame(Bounds frameBounds, bool horizontally, bool vertically) + { + if (frameBounds.size == Vector3.zero) + return; + if (horizontally) SetShownHRangeInsideMargins(frameBounds.min.x, frameBounds.max.x); if (vertically) @@ -987,15 +995,6 @@ public void CurveGUI() DeleteSelectedKeys(); evt.Use(); } - - // Frame All. - // Manually handle hotkey unless we decide to add it to default Unity hotkeys like - // we did for FrameSelected. - if (evt.keyCode == KeyCode.A) - { - FrameClip(true, true); - evt.Use(); - } break; case EventType.ContextClick: @@ -1788,7 +1787,7 @@ int GetCurveAtPosition(Vector2 viewPos, out Vector2 closestPointOnCurve) { CurveWrapper wrapper = GetCurveWrapperFromID(m_DrawOrder[i]); - if (wrapper.hidden || wrapper.readOnly) + if (wrapper.hidden || wrapper.readOnly || wrapper.curve.length == 0) continue; // Sample the curves at pixel intervals in the area around the desired time, @@ -1992,6 +1991,9 @@ CurveSelection AddKeyAtTime(CurveWrapper cw, float time) int keyIndex = AnimationUtility.AddInbetweenKey(cw.curve, time); if (keyIndex >= 0) { + CurveUtility.SetKeyModeFromContext(cw.curve, keyIndex); + AnimationUtility.UpdateTangentsFromModeSurrounding(cw.curve, keyIndex); + // Select the key CurveSelection selectedPoint = new CurveSelection(cw.id, keyIndex); cw.selected = CurveWrapper.SelectionMode.Selected; diff --git a/Editor/Mono/Animation/AnimationWindow/CurveEditorWindow.cs b/Editor/Mono/Animation/AnimationWindow/CurveEditorWindow.cs index 48876c0b04..3865b15e78 100644 --- a/Editor/Mono/Animation/AnimationWindow/CurveEditorWindow.cs +++ b/Editor/Mono/Animation/AnimationWindow/CurveEditorWindow.cs @@ -5,6 +5,7 @@ using System; using UnityEngine; using UnityEditor; +using UnityEditor.ShortcutManagement; using System.Linq; using TangentMode = UnityEditor.AnimationUtility.TangentMode; @@ -286,6 +287,16 @@ public void Show(Action onCurveChanged, CurveEditorSettings sett ShowAuxWindow(); } + public void FrameSelected() + { + m_CurveEditor.FrameSelected(true, true); + } + + public void FrameClip() + { + m_CurveEditor.FrameClip(true, true); + } + internal class Styles { public GUIStyle curveEditorBackground = "PopupCurveEditorBackground"; @@ -606,5 +617,17 @@ void SendEvent(string eventName, bool exitGUI) } GUI.changed = true; } + + [Shortcut("Curve Editor/Frame All", typeof(CurveEditorWindow), KeyCode.A)] + static void FrameClip(ShortcutArguments args) + { + var curveEditorWindow = (CurveEditorWindow)args.context; + + if (EditorWindow.focusedWindow != curveEditorWindow) + return; + + curveEditorWindow.FrameClip(); + curveEditorWindow.Repaint(); + } } } diff --git a/Editor/Mono/Animation/AnimationWindow/DopeSheetEditor.cs b/Editor/Mono/Animation/AnimationWindow/DopeSheetEditor.cs index f89526ebeb..5b2f0a8e87 100644 --- a/Editor/Mono/Animation/AnimationWindow/DopeSheetEditor.cs +++ b/Editor/Mono/Animation/AnimationWindow/DopeSheetEditor.cs @@ -703,18 +703,6 @@ private void HandleKeyboard() break; } } - - // Frame All. - // Manually handle hotkey unless we decide to add it to default Unity hotkeys like - // we did for FrameSelected. - if (Event.current.type == EventType.KeyDown) - { - if (Event.current.keyCode == KeyCode.A) - { - FrameClip(); - Event.current.Use(); - } - } } private void HandleSelectAll() diff --git a/Editor/Mono/Animation/AnimationWindow/MinMaxCurveEditorWindow.cs b/Editor/Mono/Animation/AnimationWindow/MinMaxCurveEditorWindow.cs index 73964221de..a4c7c7ac65 100644 --- a/Editor/Mono/Animation/AnimationWindow/MinMaxCurveEditorWindow.cs +++ b/Editor/Mono/Animation/AnimationWindow/MinMaxCurveEditorWindow.cs @@ -49,6 +49,8 @@ public static MinMaxCurveEditorWindow instance public AnimationCurve minCurve { get { return m_MinCurve; } } public AnimationCurve maxCurve { get { return m_MaxCurve; } } + public static string xAxisLabel { get; set; } = "time"; + public static bool visible { get { return s_SharedMinMaxCurveEditor != null; } @@ -68,6 +70,7 @@ void Init(CurveEditorSettings settings) m_CurveEditor.settings.rectangleToolFlags = CurveEditorSettings.RectangleToolFlags.MiniRectangleTool; m_CurveEditor.settings.undoRedoSelection = true; m_CurveEditor.settings.showWrapperPopups = true; + m_CurveEditor.settings.xAxisLabel = xAxisLabel; UpdateRegionDomain(); // For each of horizontal and vertical axis, if we have a finite range for that axis, use that range, diff --git a/Editor/Mono/Annotation/SceneViewCameraWindow.cs b/Editor/Mono/Annotation/SceneViewCameraWindow.cs index 906a4ac358..c33e3ab5b8 100644 --- a/Editor/Mono/Annotation/SceneViewCameraWindow.cs +++ b/Editor/Mono/Annotation/SceneViewCameraWindow.cs @@ -30,39 +30,44 @@ public static void Init() readonly SceneView m_SceneView; GUIContent m_CameraSpeedSliderContent; - GUIContent[] m_CameraSpeedMinMax; + GUIContent m_CameraSpeedMin; + GUIContent m_CameraSpeedMax; GUIContent m_FieldOfView; GUIContent m_DynamicClip; GUIContent m_OcclusionCulling; + GUIContent m_EasingEnabled; + GUIContent m_EasingDuration; - const int k_FieldCount = 10; - const int k_WindowWidth = 300; - const int k_WindowHeight = ((int)EditorGUI.kSingleLineHeight) * k_FieldCount + kFrameWidth * 2; + const int kFieldCount = 12; + const int kWindowWidth = 290; + const int kWindowHeight = ((int)EditorGUI.kSingleLineHeight) * kFieldCount + kFrameWidth * 2; const int kFrameWidth = 10; - const float k_PrefixLabelWidth = 120f; - const float kMinMaxSpeedLabelWidth = 26f; - const float k_NearClipMin = .01f; + const float kPrefixLabelWidth = 120f; + const float kMinSpeedLabelWidth = 25f; + const float kMaxSpeedLabelWidth = 29f; + const float kMinMaxSpeedFieldWidth = 50f; + const float kMinMaxSpeedSpace = 8f; + const float kNearClipMin = .01f; float[] m_Vector2Floats = { 0, 0 }; public override Vector2 GetWindowSize() { - return new Vector2(k_WindowWidth, k_WindowHeight); + return new Vector2(kWindowWidth, kWindowHeight); } public SceneViewCameraWindow(SceneView sceneView) { m_SceneView = sceneView; - m_CameraSpeedSliderContent = EditorGUIUtility.TrTextContent("Speed", "The current speed of the camera in the Scene view."); - m_CameraSpeedMinMax = new GUIContent[] - { - EditorGUIUtility.TrTextContent("Min", "The minimum speed of the camera in the Scene view. Valid values are between [0.01, 98]."), - EditorGUIUtility.TrTextContent("Max", "The maximum speed of the camera in the Scene view. Valid values are between [0.02, 99].") - }; - m_FieldOfView = EditorGUIUtility.TrTextContent("Field of View", "The height of the Camera's view angle. Measured in degrees vertically, or along the local Y axis."); + m_CameraSpeedSliderContent = EditorGUIUtility.TrTextContent("Camera Speed", "The current speed of the camera in the Scene view."); + m_CameraSpeedMin = EditorGUIUtility.TrTextContent("Min", "The minimum speed of the camera in the Scene view. Valid values are between [0.01, 98]."); + m_CameraSpeedMax = EditorGUIUtility.TrTextContent("Max", "The maximum speed of the camera in the Scene view. Valid values are between [0.02, 99]."); + m_FieldOfView = EditorGUIUtility.TrTextContent("Field of View", "The height of the camera's view angle. Measured in degrees vertically, or along the local Y axis."); m_DynamicClip = EditorGUIUtility.TrTextContent("Dynamic Clipping", "Check this to enable camera's near and far clipping planes to be calculated relative to the viewport size of the Scene."); - m_OcclusionCulling = EditorGUIUtility.TrTextContent("Occlusion Culling", "Check this to enable occlusion culling in the Scene view. Occlusion culling disables rendering of objects when they\'re not currently seen by the Camera because they\'re hidden (occluded) by other objects."); + m_OcclusionCulling = EditorGUIUtility.TrTextContent("Occlusion Culling", "Check this to enable occlusion culling in the Scene view. Occlusion culling disables rendering of objects when they\'re not currently seen by the camera because they\'re hidden (occluded) by other objects."); + m_EasingEnabled = EditorGUIUtility.TrTextContent("Camera Easing", "Check this to enable camera movement easing. This makes the camera ease in when it starts moving and ease out when it stops."); + m_EasingDuration = EditorGUIUtility.TrTextContent("Duration", "How long it takes for the speed of the camera to accelerate to its initial full speed. Measured in seconds."); } public override void OnGUI(Rect rect) @@ -82,7 +87,7 @@ public override void OnGUI(Rect rect) private void Draw(Rect rect) { - var settings = m_SceneView.sceneViewCameraSettings; + var settings = m_SceneView.cameraSettings; Styles.Init(); const int k_SettingsIconPad = 2; @@ -96,7 +101,7 @@ private void Draw(Rect rect) EditorGUI.BeginChangeCheck(); - EditorGUIUtility.labelWidth = k_PrefixLabelWidth; + EditorGUIUtility.labelWidth = kPrefixLabelWidth; GUILayout.Label(EditorGUIUtility.TrTextContent("Scene Camera"), EditorStyles.boldLabel); @@ -111,12 +116,12 @@ private void Draw(Rect rect) using (new EditorGUI.DisabledScope(settings.dynamicClip)) { float near = settings.nearClip, far = settings.farClip; - ClipPlanesField(EditorGUI.s_ClipingPlanesLabel, ref near, ref far, EditorGUI.kNearFarLabelsWidth); + DrawClipPlanesField(EditorGUI.s_ClipingPlanesLabel, ref near, ref far, EditorGUI.kNearFarLabelsWidth); settings.nearClip = near; settings.farClip = far; - settings.nearClip = Mathf.Max(k_NearClipMin, settings.nearClip); + settings.nearClip = Mathf.Max(kNearClipMin, settings.nearClip); if (settings.nearClip > settings.farClip) - settings.farClip = settings.nearClip + k_NearClipMin; + settings.farClip = settings.nearClip + kNearClipMin; } settings.occlusionCulling = EditorGUILayout.Toggle(m_OcclusionCulling, settings.occlusionCulling); @@ -126,6 +131,15 @@ private void Draw(Rect rect) GUILayout.Label(EditorGUIUtility.TrTextContent("Navigation"), EditorStyles.boldLabel); + settings.easingEnabled = EditorGUILayout.Toggle(m_EasingEnabled, settings.easingEnabled); + + using (new EditorGUI.DisabledScope(!settings.easingEnabled)) + { + EditorGUI.indentLevel += 1; + settings.easingDuration = EditorGUILayout.Slider(m_EasingDuration, settings.easingDuration, .1f, 2f); + EditorGUI.indentLevel -= 1; + } + settings.speed = EditorGUILayout.Slider(m_CameraSpeedSliderContent, settings.speed, settings.speedMin, settings.speedMax); EditorGUI.BeginChangeCheck(); @@ -133,11 +147,7 @@ private void Draw(Rect rect) m_Vector2Floats[0] = settings.speedMin; m_Vector2Floats[1] = settings.speedMax; - GUILayout.BeginHorizontal(); - GUILayout.Space(EditorGUIUtility.labelWidth); - Rect r = EditorGUILayout.GetControlRect(false, EditorGUI.kSingleLineHeight, EditorStyles.numberField); - EditorGUI.MultiFloatField(r, m_CameraSpeedMinMax, m_Vector2Floats, kMinMaxSpeedLabelWidth); - GUILayout.EndHorizontal(); + DrawSpeedMinMaxFields(); if (EditorGUI.EndChangeCheck()) settings.SetSpeedMinMax(m_Vector2Floats); @@ -147,7 +157,22 @@ private void Draw(Rect rect) GUILayout.EndArea(); } - internal static void ClipPlanesField(GUIContent label, ref float near, ref float far, float propertyLabelsWidth, params GUILayoutOption[] options) + void DrawSpeedMinMaxFields() + { + GUILayout.BeginHorizontal(); + GUILayout.Space(EditorGUIUtility.labelWidth); + Rect r = EditorGUILayout.GetControlRect(false, EditorGUI.kSingleLineHeight, EditorStyles.numberField); + r.width = kMinSpeedLabelWidth + kMinMaxSpeedFieldWidth; + EditorGUIUtility.labelWidth = kMinSpeedLabelWidth; + m_Vector2Floats[0] = EditorGUI.FloatField(r, m_CameraSpeedMin, m_Vector2Floats[0]); + r.x += r.width + kMinMaxSpeedSpace; + r.width = kMaxSpeedLabelWidth + kMinMaxSpeedFieldWidth; + EditorGUIUtility.labelWidth = kMaxSpeedLabelWidth; + m_Vector2Floats[1] = EditorGUI.FloatField(r, m_CameraSpeedMax, m_Vector2Floats[1]); + GUILayout.EndHorizontal(); + } + + void DrawClipPlanesField(GUIContent label, ref float near, ref float far, float propertyLabelsWidth, params GUILayoutOption[] options) { bool hasLabel = EditorGUI.LabelHasContent(label); const float height = EditorGUI.kSingleLineHeight * 2 + EditorGUI.kVerticalSpacingMultiField; @@ -179,7 +204,7 @@ void ShowContextMenu() void Reset() { - m_SceneView.ResetSceneViewCameraSettings(); + m_SceneView.ResetCameraSettings(); m_SceneView.Repaint(); } } diff --git a/Editor/Mono/Annotation/SceneViewSettingsProvider.cs b/Editor/Mono/Annotation/SceneViewSettingsProvider.cs deleted file mode 100644 index 19a3a88776..0000000000 --- a/Editor/Mono/Annotation/SceneViewSettingsProvider.cs +++ /dev/null @@ -1,74 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine; - -namespace UnityEditor -{ - class SceneViewSettingsProvider : SettingsProvider - { - class Styles - { - static bool s_Initialized; - - public static GUIContent cameraMovementEasingEnabled = EditorGUIUtility.TrTextContent("Camera Easing", "Check this to enable camera movement easing. This makes the Camera ease in when it starts moving, and ease out when it stops."); - public static GUIContent cameraMovementEasingDuration = EditorGUIUtility.TrTextContent("Duration", "How long it takes for the Camera speed to accelerate to full speed. Measured in seconds."); - - public static GUIStyle settings; - - public static void Init() - { - if (s_Initialized) - return; - - s_Initialized = true; - - settings = new GUIStyle() - { - margin = new RectOffset(8, 4, 4, 4) - }; - } - } - - [SettingsProvider] - static SettingsProvider CreateSceneViewSettingsProvider() - { - return new SceneViewSettingsProvider("Preferences/Scene View"); - } - - public SceneViewSettingsProvider(string path, SettingsScope scopes = SettingsScope.User) - : base(path, scopes) - { - PopulateSearchKeywordsFromGUIContentProperties(); - } - - public override void OnGUI(string searchContext) - { - base.OnGUI(searchContext); - Styles.Init(); - var searching = !string.IsNullOrEmpty(searchContext); - - GUILayout.BeginVertical(Styles.settings, GUILayout.MaxWidth(SettingsWindow.s_DefaultLayoutMaxWidth)); - - if (!searching) - GUILayout.Label(EditorGUIUtility.TrTextContent("Navigation"), EditorStyles.boldLabel); - - if (!searching || SearchUtils.MatchSearch(searchContext, Styles.cameraMovementEasingEnabled.text)) - SceneViewMotion.movementEasingEnabled = EditorGUILayout.Toggle( - Styles.cameraMovementEasingEnabled, - SceneViewMotion.movementEasingEnabled); - - using (new EditorGUI.DisabledScope(!SceneViewMotion.movementEasingEnabled)) - { - EditorGUI.indentLevel += 1; - if (!searching || SearchUtils.MatchSearch(searchContext, Styles.cameraMovementEasingDuration.text)) - SceneViewMotion.movementEasingDuration = EditorGUILayout.Slider(Styles.cameraMovementEasingDuration, SceneViewMotion.movementEasingDuration, .1f, 3f); - EditorGUI.indentLevel -= 1; - } - - GUILayout.EndVertical(); - } - } -} diff --git a/Editor/Mono/AssemblyHelper.cs b/Editor/Mono/AssemblyHelper.cs index b9a64ff204..fdf4b5e6f8 100644 --- a/Editor/Mono/AssemblyHelper.cs +++ b/Editor/Mono/AssemblyHelper.cs @@ -18,6 +18,8 @@ namespace UnityEditor { internal partial class AssemblyHelper { + static Dictionary managedToDllType = new Dictionary(); + // Check if assmebly internal name doesn't match file name, and show the warning. static public void CheckForAssemblyFileNameMismatch(string assemblyPath) { @@ -261,7 +263,6 @@ public static string[] GetDefaultAssemblySearchPaths() foreach (var asm in precompiledAssemblies) searchPaths.Add(Path.GetDirectoryName(asm.Path)); - searchPaths.Add("Library/ScriptAssemblies"); return searchPaths.ToArray(); } @@ -501,8 +502,14 @@ internal static IEnumerable FindImplementors(Assembly assembly) where T : public static bool IsManagedAssembly(string file) { - UnityEditorInternal.DllType type = UnityEditorInternal.InternalEditorUtility.DetectDotNetDll(file); - return type != UnityEditorInternal.DllType.Unknown && type != UnityEditorInternal.DllType.Native; + bool isManagedDll; + if (managedToDllType.TryGetValue(file, out isManagedDll)) + { + return isManagedDll; + } + var res = InternalEditorUtility.IsDotNetDll(file); + managedToDllType[file] = res; + return res; } public static bool IsInternalAssembly(string file) diff --git a/Editor/Mono/AssemblyInfo/AssemblyInfo.cs b/Editor/Mono/AssemblyInfo/AssemblyInfo.cs index 78be260894..506935cabd 100644 --- a/Editor/Mono/AssemblyInfo/AssemblyInfo.cs +++ b/Editor/Mono/AssemblyInfo/AssemblyInfo.cs @@ -6,6 +6,7 @@ using UnityEngine; // ADD_NEW_PLATFORM_HERE +[assembly: InternalsVisibleTo("Unity.LiveNotes")] [assembly: InternalsVisibleTo("Unity.Burst")] [assembly: InternalsVisibleTo("Unity.Burst.Editor")] [assembly: InternalsVisibleTo("Unity.CollabProxy.Editor")] diff --git a/Editor/Mono/AssemblyValidation.cs b/Editor/Mono/AssemblyValidation.cs index 522a9d361a..077dda09c4 100644 --- a/Editor/Mono/AssemblyValidation.cs +++ b/Editor/Mono/AssemblyValidation.cs @@ -144,6 +144,16 @@ public static bool PluginCompatibleWithEditor(string path) return pluginImporter.GetCompatibleWithEditor(); } + public static bool ShouldValidateReferences(string path) + { + var pluginImporter = AssetImporter.GetAtPath(path) as PluginImporter; + + if (pluginImporter == null) + return true; + + return pluginImporter.ValidateReferences; + } + public static void PrintAssemblyDefinitions(AssemblyDefinition[] assemblyDefinitions) { foreach (var assemblyDefinition in assemblyDefinitions) @@ -233,6 +243,13 @@ public static void CheckAssemblyReferences(string[] assemblyPaths, if (errors[i].HasFlag(ErrorFlags.IncompatibleWithEditor)) continue; + var assemblyPath = assemblyPaths[i]; + + // Check if "Validate References" option is enabled + // in the PluginImporter + if (!ShouldValidateReferences(assemblyPath)) + continue; + ResolveAndSetupReferences(i, errors, assemblyDefinitions, @@ -327,7 +344,7 @@ public static void ResolveAndSetupReferences(int index, catch (AssemblyResolutionException) { errors[index].Add(ErrorFlags.UnresolvableReference, - string.Format("Unable to resolve reference '{0}'. Is the assembly missing or incompatible with the current platform?", + string.Format("Unable to resolve reference '{0}'. Is the assembly missing or incompatible with the current platform?\nReference validation can be disabled in the Plugin Inspector.", reference.Name)); } } diff --git a/Editor/Mono/AssetDatabase/AssetDatabase.bindings.cs b/Editor/Mono/AssetDatabase/AssetDatabase.bindings.cs index e94d8fe00a..43cb7deac8 100644 --- a/Editor/Mono/AssetDatabase/AssetDatabase.bindings.cs +++ b/Editor/Mono/AssetDatabase/AssetDatabase.bindings.cs @@ -19,8 +19,16 @@ public enum ForceReserializeAssetsOptions ReserializeAssetsAndMetadata = ReserializeAssets | ReserializeMetadata } + internal enum ImportPackageOptions + { + Default = 0, + NoGUI = 1 << 0, + ImportDelayed = 1 << 1 + } + [NativeHeader("Modules/AssetDatabase/Editor/Public/AssetDatabase.h")] [NativeHeader("Modules/AssetDatabase/Editor/Public/AssetDatabaseUtility.h")] + [NativeHeader("Editor/Src/PackageUtility.h")] public partial class AssetDatabase { [FreeFunction("AssetDatabase::ReSerializeAssetsForced")] @@ -110,5 +118,18 @@ public static void ForceReserializeAssets() [FreeFunction("AssetDatabase::GUIDFromExistingAssetPath")] extern internal static GUID GUIDFromExistingAssetPath(string path); + + [FreeFunction("::ImportPackage")] + extern private static bool ImportPackage(string packagePath, ImportPackageOptions options); + //TODO: This API should be Obsoleted when there is time available to update all the uses of it in Package Manager packages + public static void ImportPackage(string packagePath, bool interactive) + { + ImportPackage(packagePath, ImportPackageOptions.ImportDelayed | (interactive ? ImportPackageOptions.Default : ImportPackageOptions.NoGUI)); + } + + internal static bool ImportPackageImmediately(string packagePath) + { + return ImportPackage(packagePath, ImportPackageOptions.NoGUI); + } } } diff --git a/Editor/Mono/AssetDatabase/AssetPreview.bindings.cs b/Editor/Mono/AssetDatabase/AssetPreview.bindings.cs index 51d96b072d..44d04e28d4 100644 --- a/Editor/Mono/AssetDatabase/AssetPreview.bindings.cs +++ b/Editor/Mono/AssetDatabase/AssetPreview.bindings.cs @@ -30,6 +30,9 @@ internal static Texture2D GetAssetPreview(int instanceID) [FreeFunction("AssetPreviewBindings::GetAssetPreview")] internal static extern Texture2D GetAssetPreview(int instanceID, int clientID); + [FreeFunction("AssetPreviewBindings::HasAssetPreview")] + internal static extern bool HasAssetPreview(int instanceID, int clientID); + public static bool IsLoadingAssetPreview(int instanceID) { return IsLoadingAssetPreview(instanceID, kSharedClientID); diff --git a/Editor/Mono/AssetModificationProcessor.cs b/Editor/Mono/AssetModificationProcessor.cs index 37fad46f85..e96e48bba6 100644 --- a/Editor/Mono/AssetModificationProcessor.cs +++ b/Editor/Mono/AssetModificationProcessor.cs @@ -8,6 +8,7 @@ using UnityEditor.VersionControl; using UnityEditorInternal; using UnityEditorInternal.VersionControl; +using System.Linq; using System.Reflection; namespace UnityEditor @@ -116,8 +117,12 @@ static void FileModeChanged(string[] assets, UnityEditor.VersionControl.FileMode // that we have the most recent status if (Provider.enabled) { - if (Provider.PromptAndCheckoutIfNeeded(assets, "")) + var editableAssets = new string[assets.Length]; + if (Provider.MakeEditable(assets, editableAssets)) + { + // TODO: handle partial results from MakeEditable i.e. editableassets Provider.SetFileMode(assets, mode); + } } } @@ -168,13 +173,18 @@ static void OnWillSaveAssets(string[] assets, out string[] assetsThatShouldBeSav } assets = assetsNotOpened.ToArray(); - // Try to checkout if needed. This may fail but is catched below. - if (assets.Length != 0 && !Provider.PromptAndCheckoutIfNeeded(assets, "")) + // Try to checkout if needed. This may fail but is caught below. + var editableAssets = new string[assets.Length]; + if (assets.Length != 0 && !Provider.MakeEditable(assets, editableAssets)) { - Debug.LogError("Could not check out the following files in version control before saving: " + - string.Join(", ", assets)); - assetsThatShouldBeSaved = new string[0]; - return; + // only save assets that can be made editable (not locked by someone else, etc.), + // unless we are in the behavior mode that just overwrites everything anyway + if (!EditorUserSettings.overwriteFailedCheckoutAssets) + { + editableAssets = editableAssets.Where(a => a != null).ToArray(); + assetsThatShouldBeReverted = assets.Except(editableAssets).ToArray(); + assetsThatShouldBeSaved = assetsThatShouldBeSaved.Except(assetsThatShouldBeReverted).ToArray(); + } } } diff --git a/Editor/Mono/AssetPipeline/SpeedTreeImporter.bindings.cs b/Editor/Mono/AssetPipeline/SpeedTreeImporter.bindings.cs index 98cb567b1e..7c05bf4d56 100644 --- a/Editor/Mono/AssetPipeline/SpeedTreeImporter.bindings.cs +++ b/Editor/Mono/AssetPipeline/SpeedTreeImporter.bindings.cs @@ -44,6 +44,10 @@ public extern bool isV8 get; } + public extern Shader defaultShader { get; } + + public extern Shader defaultBillboardShader { get; } + ///////////////////////////////////////////////////////////////////////////// // Mesh properties diff --git a/Editor/Mono/AssetPostprocessor.cs b/Editor/Mono/AssetPostprocessor.cs index 20573c9042..673ad31dfc 100644 --- a/Editor/Mono/AssetPostprocessor.cs +++ b/Editor/Mono/AssetPostprocessor.cs @@ -254,6 +254,16 @@ static void CleanupPostprocessors() } } + static bool ImplementsAnyOfTheses(Type type, string[] methods) + { + foreach (var method in methods) + { + if (type.GetMethod(method, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null) + return true; + } + return false; + } + [RequiredByNativeCode] static string GetMeshProcessorsHashString() { @@ -268,11 +278,20 @@ static string GetMeshProcessorsHashString() { var inst = Activator.CreateInstance(assetPostprocessorClass) as AssetPostprocessor; var type = inst.GetType(); - bool hasPreProcessMethod = type.GetMethod("OnPreprocessModel", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null; - bool hasPostprocessMeshHierarchy = type.GetMethod("OnPostprocessMeshHierarchy", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null; - bool hasPostProcessMethod = type.GetMethod("OnPostprocessModel", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null; + bool hasAnyPostprocessMethod = ImplementsAnyOfTheses(type, new[] + { + "OnPreprocessModel", + "OnPostprocessMeshHierarchy", + "OnPostprocessModel", + "OnPreprocessAnimation", + "OnPostprocessAnimation", + "OnPostprocessGameObjectWithAnimatedUserProperties", + "OnPostprocessGameObjectWithUserProperties", + "OnPostprocessMaterial", + "OnAssignMaterialModel" + }); uint version = inst.GetVersion(); - if (version != 0 && (hasPreProcessMethod || hasPostprocessMeshHierarchy || hasPostProcessMethod)) + if (version != 0 && hasAnyPostprocessMethod) { versionsByType.Add(type.FullName, version); } diff --git a/Editor/Mono/Audio/Mixer/GUI/AudioMixerChannelStripView.cs b/Editor/Mono/Audio/Mixer/GUI/AudioMixerChannelStripView.cs index fedabc757a..ddf24fc77f 100644 --- a/Editor/Mono/Audio/Mixer/GUI/AudioMixerChannelStripView.cs +++ b/Editor/Mono/Audio/Mixer/GUI/AudioMixerChannelStripView.cs @@ -1298,7 +1298,7 @@ void DoTotaldB(ChannelStripParams p) GUI.Label(rect, string.Format(CultureInfo.InvariantCulture.NumberFormat, "{0:F1} dB", vu_level), styles.totalVULevel); } - GUIContent addText = EditorGUIUtility.TrTextContent("Add.."); + GUIContent addText = EditorGUIUtility.TrTextContent("Add..."); void DoEffectList(ChannelStripParams p, bool selected, ref int highlightEffectIndex, ref Dictionary patchslots, bool showBusConnectionsOfSelection) { Event evt = Event.current; diff --git a/Editor/Mono/Audio/Mixer/GUI/AudioMixerEffectView.cs b/Editor/Mono/Audio/Mixer/GUI/AudioMixerEffectView.cs index d9fefce433..89f6e54a4d 100644 --- a/Editor/Mono/Audio/Mixer/GUI/AudioMixerEffectView.cs +++ b/Editor/Mono/Audio/Mixer/GUI/AudioMixerEffectView.cs @@ -283,11 +283,11 @@ public void DoEffectGUI(int effectIndex, AudioMixerGroupController group, List blacklists = Il2CppBlacklistPaths; + if (rcr != null) { blacklists = blacklists.Concat(new[] @@ -327,7 +329,7 @@ private static void RunAssemblyStripper(IEnumerable assemblies, string managedAs } } - if (!stripEngineCode) + if (!performEngineStripping) { // if we don't do stripping, add all modules blacklists. foreach (var file in Directory.GetFiles(platformProvider.moduleStrippingInformationFolder, "*.xml")) @@ -359,20 +361,20 @@ private static void RunAssemblyStripper(IEnumerable assemblies, string managedAs blacklists, buildTargetGroup, managedStrippingLevel, - stripEngineCode)) + performEngineStripping)) throw new Exception("Error in stripping assemblies: " + assemblies + ", " + error); - if (platformProvider.supportsEngineStripping) + if (engineStrippingSupported) { var icallSummaryPath = Path.Combine(managedAssemblyFolderPath, "ICallSummary.txt"); GenerateInternalCallSummaryFile(icallSummaryPath, managedAssemblyFolderPath, tempStripPath); - if (stripEngineCode) + if (performEngineStripping) { // Find which modules we must include in the build based on Assemblies HashSet nativeClasses; HashSet nativeModules; - CodeStrippingUtils.GenerateDependencies(tempStripPath, icallSummaryPath, rcr, stripEngineCode, out nativeClasses, out nativeModules, platformProvider); + CodeStrippingUtils.GenerateDependencies(tempStripPath, icallSummaryPath, rcr, performEngineStripping, out nativeClasses, out nativeModules, platformProvider); // Add module-specific blacklists. addedMoreBlacklists = AddWhiteListsForModules(nativeModules, ref blacklists, platformProvider.moduleStrippingInformationFolder); } @@ -468,8 +470,11 @@ private static string GetMethodPreserveBlacklistContents(RuntimeClassRegistry rc return sb.ToString(); } - static public void InvokeFromBuildPlayer(BuildTarget buildTarget, RuntimeClassRegistry usedClasses, ManagedStrippingLevel managedStrippingLevel, BuildReport report) + static public void StripForMonoBackend(BuildTarget buildTarget, RuntimeClassRegistry usedClasses, ManagedStrippingLevel managedStrippingLevel, BuildReport report) { + if (managedStrippingLevel == ManagedStrippingLevel.Disabled) + return; + var stagingAreaData = Paths.Combine("Temp", "StagingArea", "Data"); var platformProvider = new BaseIl2CppPlatformProvider(buildTarget, Path.Combine(stagingAreaData, "Libraries"), report); diff --git a/Editor/Mono/BuildPipeline/CodeStrippingUtils.cs b/Editor/Mono/BuildPipeline/CodeStrippingUtils.cs index 90761ff741..3711a1cff6 100644 --- a/Editor/Mono/BuildPipeline/CodeStrippingUtils.cs +++ b/Editor/Mono/BuildPipeline/CodeStrippingUtils.cs @@ -254,7 +254,7 @@ public static void WriteModuleAndClassRegistrationFile(string strippedAssemblyDi HashSet nativeClasses; HashSet nativeModules; // by default, we only care about il2cpp - bool doStripping = PlayerSettings.stripEngineCode && !platformProvider.scriptsOnlyBuild; + bool doStripping = PlayerSettings.stripEngineCode; GenerateDependencies(strippedAssemblyDir, icallsListFile, rcr, doStripping, out nativeClasses, out nativeModules, platformProvider); var outputClassRegistration = Path.Combine(outputDir, "UnityClassRegistration.cpp"); diff --git a/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs b/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs index ef95be9507..7bf291f4cf 100644 --- a/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs +++ b/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs @@ -81,6 +81,8 @@ public override void UpdateBootConfig(BuildTarget target, BootConfigData config, if (PlayerSettings.forceSingleInstance) config.AddKey("single-instance"); + if (!PlayerSettings.useFlipModelSwapchain) + config.AddKey("force-d3d11-bltblt-mode"); if (IL2CPPUtils.UseIl2CppCodegenWithMonoBackend(BuildPipeline.GetBuildTargetGroup(target))) config.Set("mono-codegen", "il2cpp"); if ((options & BuildOptions.EnableHeadlessMode) != 0) @@ -257,6 +259,12 @@ private void SetupStagingArea(BuildPostProcessArgs args, HashSet filesTo ProcessIl2CppOutputForBinary(args); } } + else + { + var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(args.target); + var managedStrippingLevel = PlayerSettings.GetManagedStrippingLevel(buildTargetGroup); + AssemblyStripper.StripForMonoBackend(args.target, args.usedClassRegistry, managedStrippingLevel, args.report); + } RenameFilesInStagingArea(args); } diff --git a/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs b/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs index 8024841d91..bd8fb3c095 100644 --- a/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs +++ b/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs @@ -218,15 +218,22 @@ internal static string[] GetBuilderDefinedDefines(IIl2CppPlatformProvider il2cpp return defines.ToArray(); } - internal static string[] GetBuildingIL2CPPArguments(IIl2CppPlatformProvider il2cppPlatformProvider, BuildTargetGroup buildTargetGroup) + internal static string[] GetDebuggerIL2CPPArguments(IIl2CppPlatformProvider il2cppPlatformProvider, BuildTargetGroup buildTargetGroup) { - // When changing this function, don't forget to change GetBuilderDefinedDefines! var arguments = new List(); - var apiCompatibilityLevel = PlayerSettings.GetApiCompatibilityLevel(buildTargetGroup); if (EnableIL2CPPDebugger(il2cppPlatformProvider, buildTargetGroup)) arguments.Add("--enable-debugger"); + return arguments.ToArray(); + } + + internal static string[] GetBuildingIL2CPPArguments(IIl2CppPlatformProvider il2cppPlatformProvider, BuildTargetGroup buildTargetGroup) + { + // When changing this function, don't forget to change GetBuilderDefinedDefines! + var arguments = new List(); + var apiCompatibilityLevel = PlayerSettings.GetApiCompatibilityLevel(buildTargetGroup); + if (BuildPipeline.IsFeatureSupported("ENABLE_SCRIPTING_GC_WBARRIERS", il2cppPlatformProvider.target)) { var hasGCBarrierValidation = PlayerSettings.gcWBarrierValidation; @@ -428,6 +435,7 @@ private void ConvertPlayerDlltoCpp(string inputDirectory, string outputDirectory arguments.AddRange(Il2CppNativeCodeBuilderUtils.AddBuilderArguments(il2CppNativeCodeBuilder, OutputFileRelativePath(), m_PlatformProvider.includePaths, m_PlatformProvider.libraryPaths, compilerConfiguration)); } + arguments.AddRange(IL2CPPUtils.GetDebuggerIL2CPPArguments(m_PlatformProvider, buildTargetGroup)); arguments.AddRange(IL2CPPUtils.GetBuildingIL2CPPArguments(m_PlatformProvider, buildTargetGroup)); arguments.Add($"--map-file-parser={CommandLineFormatter.PrepareFileName(GetMapFileParserPath())}"); diff --git a/Editor/Mono/BuildPlayerWindow.cs b/Editor/Mono/BuildPlayerWindow.cs index c7d112d132..b430bba740 100644 --- a/Editor/Mono/BuildPlayerWindow.cs +++ b/Editor/Mono/BuildPlayerWindow.cs @@ -26,8 +26,8 @@ public partial class BuildPlayerWindow : EditorWindow { class Styles { - public GUIContent invalidColorSpaceMessage = EditorGUIUtility.TrTextContent("In order to build a player go to 'Player Settings...' to resolve the incompatibility between the Color Space and the current settings.", EditorGUIUtility.GetHelpIcon(MessageType.Warning)); - public GUIContent invalidLightmapEncodingMessage = EditorGUIUtility.TrTextContent("In order to build a player go to 'Player Settings...' to resolve the incompatibility between the selected Lightmap Encoding and the current settings.", EditorGUIUtility.GetHelpIcon(MessageType.Warning)); + public GUIContent invalidColorSpaceMessage = EditorGUIUtility.TrTextContent("In order to build a player, go to 'Player Settings...' to resolve the incompatibility between the Color Space and the current settings.", EditorGUIUtility.GetHelpIcon(MessageType.Warning)); + public GUIContent invalidLightmapEncodingMessage = EditorGUIUtility.TrTextContent("In order to build a player, go to 'Player Settings...' to resolve the incompatibility between the selected Lightmap Encoding and the current settings.", EditorGUIUtility.GetHelpIcon(MessageType.Warning)); public GUIStyle selected = "OL SelectedRow"; public GUIStyle box = "OL Box"; public GUIStyle title = EditorStyles.boldLabel; @@ -250,8 +250,7 @@ private void ActiveBuildTargetsGUI() GUI.enabled = BuildPipeline.IsBuildTargetSupported(selectedTargetGroup, selectedTarget); if (GUILayout.Button(EditorGUIUtility.TrTextContent("Player Settings..."), GUILayout.Width(Styles.kButtonWidth))) { - Selection.activeObject = Unsupported.GetSerializedAssetInterfaceSingleton("PlayerSettings"); - EditorWindow.GetWindow(); + SettingsService.OpenProjectSettings("Project/Player"); } GUILayout.EndHorizontal(); diff --git a/Editor/Mono/BuildPlayerWindowBuildMethods.cs b/Editor/Mono/BuildPlayerWindowBuildMethods.cs index 55b2d63c22..da7db3cc4f 100644 --- a/Editor/Mono/BuildPlayerWindowBuildMethods.cs +++ b/Editor/Mono/BuildPlayerWindowBuildMethods.cs @@ -13,6 +13,7 @@ using System; using UnityEditor.Build.Reporting; using UnityEditor.Connect; +using UnityEditor.Utils; namespace UnityEditor { @@ -182,7 +183,10 @@ public static void BuildPlayer(BuildPlayerOptions options) Debug.LogWarning(resultStr); break; case Build.Reporting.BuildResult.Failed: - DeleteBuildFolderIfEmpty(report.summary.outputPath); + // On some platforms the user creates the build folder, therefore they own the folder and + // it should not be automatically deleted by the Unity Editor, even if it is empty (case 1073851) + if (options.target != BuildTarget.XboxOne) + DeleteBuildFolderIfEmpty(report.summary.outputPath); Debug.LogError(resultStr); throw new BuildMethodException(report.SummarizeErrors()); default: @@ -356,7 +360,7 @@ static bool PickBuildLocation(BuildTargetGroup targetGroup, BuildTarget target, if (isWindowsStandalone) { extension = realExtension; - path = Path.Combine(path, PlayerSettings.productName + '.' + extension); + path = Path.Combine(path, Paths.MakeValidFileName(PlayerSettings.productName) + '.' + extension); } if (!IsBuildPathValid(path)) diff --git a/Editor/Mono/BuildTargetConverter.cs b/Editor/Mono/BuildTargetConverter.cs index 41591ed029..93004b4cd1 100644 --- a/Editor/Mono/BuildTargetConverter.cs +++ b/Editor/Mono/BuildTargetConverter.cs @@ -39,6 +39,8 @@ internal class BuildTargetConverter return RuntimePlatform.tvOS; case BuildTarget.WebGL: return RuntimePlatform.WebGLPlayer; + case BuildTarget.Lumin: + return RuntimePlatform.Lumin; default: return null; } diff --git a/Editor/Mono/Camera/EditorCameraUtils.bindings.cs b/Editor/Mono/Camera/EditorCameraUtils.bindings.cs new file mode 100644 index 0000000000..39d1798fe8 --- /dev/null +++ b/Editor/Mono/Camera/EditorCameraUtils.bindings.cs @@ -0,0 +1,22 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEngine; +using UnityEngine.Bindings; +using UnityEngine.Internal; +using UnityEngine.Scripting; + +namespace UnityEditor.Rendering +{ + [NativeHeader("Editor/Src/Camera/EditorCameraUtils.h")] + [RequiredByNativeCode] + public static class EditorCameraUtils + { + public static bool RenderToCubemap(this Camera camera, Texture target, int faceMask, StaticEditorFlags culledFlags) + => RenderToCubemapImpl(camera, target, faceMask, culledFlags) == 1; + + [FreeFunction("EditorCameraUtilsScripting::RenderToCubemap")] + static extern int RenderToCubemapImpl(Camera camera, Texture target, [DefaultValue("63")] int faceMask, StaticEditorFlags culledFlags); + } +} diff --git a/Editor/Mono/Collab/Collab.bindings.cs b/Editor/Mono/Collab/Collab.bindings.cs index 253f72c7b9..17d55a013a 100644 --- a/Editor/Mono/Collab/Collab.bindings.cs +++ b/Editor/Mono/Collab/Collab.bindings.cs @@ -218,6 +218,9 @@ public extern void TestClearSoftLockAsCollaborator(string projectGuid, string pr [NativeMethod(HasExplicitThis = true, ThrowsException = true, IsThreadSafe = true)] public extern void ClearSelectedChangesToPublish(); + [NativeMethod(HasExplicitThis = true, ThrowsException = true, IsThreadSafe = true)] + public extern void SendCollabInfoNotification(); + [NativeMethod(HasExplicitThis = true, ThrowsException = true)] public extern SoftLock[] GetSoftLocks(string assetGuid); } diff --git a/Editor/Mono/ConsoleWindow.cs b/Editor/Mono/ConsoleWindow.cs index 232dc0085a..22f43dc90e 100644 --- a/Editor/Mono/ConsoleWindow.cs +++ b/Editor/Mono/ConsoleWindow.cs @@ -369,7 +369,7 @@ static internal GUIStyle GetStyleForErrorMode(int mode, bool isIcon, bool isSmal if (HasMode(mode, Mode.Fatal | Mode.Assert | Mode.Error | Mode.ScriptingError | Mode.AssetImportError | Mode.ScriptCompileError | - Mode.GraphCompileError | Mode.ScriptingAssertion)) + Mode.GraphCompileError | Mode.ScriptingAssertion | Mode.ScriptingException)) { if (isIcon) { @@ -803,11 +803,11 @@ private void SearchField(Event e) } } - private static string StacktraceWithHyperlinks(string stacktraceText) + internal static string StacktraceWithHyperlinks(string stacktraceText) { StringBuilder textWithHyperlinks = new StringBuilder(); var lines = stacktraceText.Split(new string[] {"\n"}, StringSplitOptions.None); - for (int i = 0; i < lines[i].Length; ++i) + for (int i = 0; i < lines.Length; ++i) { string textBeforeFilePath = ") (at "; int filePathIndex = lines[i].IndexOf(textBeforeFilePath, StringComparison.Ordinal); @@ -820,7 +820,7 @@ private static string StacktraceWithHyperlinks(string stacktraceText) int lineIndex = filePathPart.LastIndexOf(":", StringComparison.Ordinal); // LastIndex because the url can contain ':' ex:"C:" if (lineIndex > 0) { - int endLineIndex = filePathPart.IndexOf(")", StringComparison.Ordinal); + int endLineIndex = filePathPart.LastIndexOf(")", StringComparison.Ordinal); // LastIndex because files or folder in the url can contain ')' if (endLineIndex > 0) { string lineString = @@ -830,7 +830,7 @@ private static string StacktraceWithHyperlinks(string stacktraceText) textWithHyperlinks.Append(lines[i].Substring(0, filePathIndex)); textWithHyperlinks.Append(""); textWithHyperlinks.Append(filePath + ":" + lineString); - textWithHyperlinks.AppendLine(")"); + textWithHyperlinks.Append(")\n"); continue; // continue to evade the default case } @@ -838,8 +838,11 @@ private static string StacktraceWithHyperlinks(string stacktraceText) } } // default case if no hyperlink : we just write the line - textWithHyperlinks.AppendLine(lines[i]); + textWithHyperlinks.Append(lines[i] + "\n"); } + // Remove the last \n + if (textWithHyperlinks.Length > 0) // textWithHyperlinks always ends with \n if it is not empty + textWithHyperlinks.Remove(textWithHyperlinks.Length - 1, 1); return textWithHyperlinks.ToString(); } diff --git a/Editor/Mono/ContainerWindow.cs b/Editor/Mono/ContainerWindow.cs index cd573768e9..20a6d072d6 100644 --- a/Editor/Mono/ContainerWindow.cs +++ b/Editor/Mono/ContainerWindow.cs @@ -97,7 +97,7 @@ internal void ShowPopupWithMode(ShowMode mode, bool giveFocus) // Fit window to screen - needs to be done after bringing the window live position = FitWindowRectToScreen(m_PixelRect, true, false); - rootView.position = new Rect(0, 0, m_PixelRect.width, m_PixelRect.height); + rootView.position = new Rect(0, 0, Mathf.Ceil(m_PixelRect.width), Mathf.Ceil(m_PixelRect.height)); rootView.Reflow(); } @@ -135,7 +135,8 @@ public void Show(ShowMode showMode, bool loadPosition, bool displayImmediately, // Fit window to screen - needs to be done after bringing the window live position = FitWindowRectToScreen(m_PixelRect, true, false); - rootView.position = new Rect(0, 0, m_PixelRect.width, m_PixelRect.height); + rootView.position = new Rect(0, 0, Mathf.Ceil(m_PixelRect.width), Mathf.Ceil(m_PixelRect.height)); + rootView.Reflow(); // save position right away @@ -261,7 +262,7 @@ internal void OnResize() { if (rootView == null) return; - rootView.position = new Rect(0, 0, position.width, position.height); + rootView.position = new Rect(0, 0, Mathf.Ceil(position.width), Mathf.Ceil(position.height)); // save position Save(); @@ -305,7 +306,7 @@ public View rootView { m_RootView = value; m_RootView.SetWindowRecurse(this); - m_RootView.position = new Rect(0, 0, position.width, position.height); + m_RootView.position = new Rect(0, 0, Mathf.Ceil(position.width), Mathf.Ceil(position.height)); m_MinSize = value.minSize; m_MaxSize = value.maxSize; } diff --git a/Editor/Mono/CustomInspectorStubs.cs b/Editor/Mono/CustomInspectorStubs.cs index 824cd94150..8645e8b7e0 100644 --- a/Editor/Mono/CustomInspectorStubs.cs +++ b/Editor/Mono/CustomInspectorStubs.cs @@ -17,6 +17,7 @@ private PhysicsManager() {} // Exposed as internal, editor-only, because we only need it do make a custom inspector [NativeClass(null)] + [ExcludeFromPreset] internal sealed class AudioManager : ProjectSettingsBase { private AudioManager() {} diff --git a/Editor/Mono/EditorApplication.bindings.cs b/Editor/Mono/EditorApplication.bindings.cs index 761cd38fac..cef9ed570d 100644 --- a/Editor/Mono/EditorApplication.bindings.cs +++ b/Editor/Mono/EditorApplication.bindings.cs @@ -223,5 +223,7 @@ public static extern double timeSinceStartup } internal static extern void CloseAndRelaunch(string[] arguments); + + internal static extern void RequestCloseAndRelaunchWithCurrentArguments(); } } diff --git a/Editor/Mono/EditorGUI.EnumMaskField.deprecated.cs b/Editor/Mono/EditorGUI.EnumMaskField.deprecated.cs index 62abcbfe63..df06043570 100644 --- a/Editor/Mono/EditorGUI.EnumMaskField.deprecated.cs +++ b/Editor/Mono/EditorGUI.EnumMaskField.deprecated.cs @@ -397,7 +397,7 @@ internal static int DoMaskField(Rect position, int controlID, int mask, string[] mask = ~0; } else - buttonContent = EditorGUIUtility.TempContent("Mixed ..."); + buttonContent = EditorGUIUtility.TempContent("Mixed..."); break; } } diff --git a/Editor/Mono/EditorGUI.cs b/Editor/Mono/EditorGUI.cs index e1ff1b1ffd..d36b3b1739 100644 --- a/Editor/Mono/EditorGUI.cs +++ b/Editor/Mono/EditorGUI.cs @@ -9,8 +9,6 @@ using System.Globalization; using System.Reflection; using System.Text.RegularExpressions; -using System.Xml; -using System.Xml.Linq; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.Scripting; @@ -20,9 +18,7 @@ using Object = UnityEngine.Object; using Event = UnityEngine.Event; using UnityEditor.Build; -using UnityEditor.StyleSheets; using UnityEngine.Internal; -using DescriptionAttribute = System.ComponentModel.DescriptionAttribute; namespace UnityEditor { @@ -2404,7 +2400,7 @@ internal static GenericMenu FillPropertyContextMenu(SerializedProperty property, info.properties = properties; info.assetPath = AssetDatabase.GetAssetPath(sourceObject); GameObject rootObject = PrefabUtility.GetRootGameObject(sourceObject); - if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootObject)) + if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootObject) || EditorUtility.IsPersistent(targetObject)) pm.AddDisabledItem(menuItemContent); else pm.AddItem(menuItemContent, false, TargetChoiceHandler.ApplyPrefabPropertyOverride, info); @@ -2903,49 +2899,52 @@ internal static void IntPopupInternal(Rect position, SerializedProperty property internal static void SortingLayerField(Rect position, GUIContent label, SerializedProperty layerID, GUIStyle style, GUIStyle labelStyle) { - int id = GUIUtility.GetControlID(s_SortingLayerFieldHash, FocusType.Keyboard, position); - position = PrefixLabel(position, id, label, labelStyle); - - Event evt = Event.current; - int selected = PopupCallbackInfo.GetSelectedValueForControl(id, -1); - if (selected != -1) + using (new PropertyScope(position, null, layerID)) { - int[] layerIDs = InternalEditorUtility.sortingLayerUniqueIDs; - if (selected >= layerIDs.Length) + int id = GUIUtility.GetControlID(s_SortingLayerFieldHash, FocusType.Keyboard, position); + position = PrefixLabel(position, id, label, labelStyle); + + Event evt = Event.current; + int selected = PopupCallbackInfo.GetSelectedValueForControl(id, -1); + if (selected != -1) { - TagManagerInspector.ShowWithInitialExpansion(TagManagerInspector.InitialExpansionState.SortingLayers); + int[] layerIDs = InternalEditorUtility.sortingLayerUniqueIDs; + if (selected >= layerIDs.Length) + { + TagManagerInspector.ShowWithInitialExpansion(TagManagerInspector.InitialExpansionState.SortingLayers); + } + else + { + layerID.intValue = layerIDs[selected]; + } } - else + + if (evt.type == EventType.MouseDown && position.Contains(evt.mousePosition) || evt.MainActionKeyForControl(id)) { - layerID.intValue = layerIDs[selected]; - } - } + int i = 0; + int[] layerIDs = InternalEditorUtility.sortingLayerUniqueIDs; + string[] layerNames = InternalEditorUtility.sortingLayerNames; + for (i = 0; i < layerIDs.Length; i++) + { + if (layerIDs[i] == layerID.intValue) + break; + } + ArrayUtility.Add(ref layerNames, ""); + ArrayUtility.Add(ref layerNames, "Add Sorting Layer..."); - if (evt.type == EventType.MouseDown && position.Contains(evt.mousePosition) || evt.MainActionKeyForControl(id)) - { - int i = 0; - int[] layerIDs = InternalEditorUtility.sortingLayerUniqueIDs; - string[] layerNames = InternalEditorUtility.sortingLayerNames; - for (i = 0; i < layerIDs.Length; i++) + DoPopup(position, id, i, EditorGUIUtility.TempContent(layerNames), style); + } + else if (Event.current.type == EventType.Repaint) { - if (layerIDs[i] == layerID.intValue) - break; + var layerName = layerID.hasMultipleDifferentValues ? + mixedValueContent : + EditorGUIUtility.TempContent(InternalEditorUtility.GetSortingLayerNameFromUniqueID(layerID.intValue)); + showMixedValue = layerID.hasMultipleDifferentValues; + BeginHandleMixedValueContentColor(); + style.Draw(position, layerName, id, false); + EndHandleMixedValueContentColor(); + showMixedValue = false; } - ArrayUtility.Add(ref layerNames, ""); - ArrayUtility.Add(ref layerNames, "Add Sorting Layer..."); - - DoPopup(position, id, i, EditorGUIUtility.TempContent(layerNames), style); - } - else if (Event.current.type == EventType.Repaint) - { - var layerName = layerID.hasMultipleDifferentValues ? - mixedValueContent : - EditorGUIUtility.TempContent(InternalEditorUtility.GetSortingLayerNameFromUniqueID(layerID.intValue)); - showMixedValue = layerID.hasMultipleDifferentValues; - BeginHandleMixedValueContentColor(); - style.Draw(position, layerName, id, false); - EndHandleMixedValueContentColor(); - showMixedValue = false; } } @@ -3259,12 +3258,12 @@ internal struct EnumData private static string EnumNameFromEnumField(FieldInfo field) { - var description = field.GetCustomAttributes(typeof(DescriptionAttribute), false); + var description = field.GetCustomAttributes(typeof(InspectorNameAttribute), false); if (description.Length > 0) { - return ((DescriptionAttribute)description.First()).Description; + return ((InspectorNameAttribute)description.First()).displayName; } - else if (field.IsDefined(typeof(ObsoleteAttribute), false)) + if (field.IsDefined(typeof(ObsoleteAttribute), false)) { return string.Format("{0} (Obsolete)", ObjectNames.NicifyVariableName(field.Name)); } @@ -4312,6 +4311,8 @@ public static Color ColorField(Rect position, GUIContent label, Color value, boo return DoColorField(PrefixLabel(position, id, label), id, value, showEyedropper, showAlpha, hdr); } + const float kEyedropperSize = 20f; + private static Color DoColorField(Rect position, int id, Color value, bool showEyedropper, bool showAlpha, bool hdr) { Event evt = Event.current; @@ -4319,13 +4320,14 @@ private static Color DoColorField(Rect position, int id, Color value, bool showE Color origColor = value; value = showMixedValue ? Color.white : value; bool hovered = position.Contains(evt.mousePosition); + bool hoveredEyedropper = new Rect(position.x + position.width - kEyedropperSize, position.y, kEyedropperSize, position.height).Contains(evt.mousePosition); switch (evt.GetTypeForControl(id)) { case EventType.MouseDown: if (showEyedropper) { - position.width -= 20; + hovered ^= hoveredEyedropper; } if (hovered) @@ -4374,8 +4376,7 @@ private static Color DoColorField(Rect position, int id, Color value, bool showE if (showEyedropper) { - position.width += 20; - if (hovered) + if (hoveredEyedropper) { GUIUtility.keyboardControl = id; EyeDropper.Start(GUIView.current); @@ -4936,7 +4937,7 @@ internal static bool ShouldDrawOverrideBackground(Object[] targetObjs, Event evt targetObjs.Length == 1 && comp != null && EditorGUIUtility.comparisonViewMode == EditorGUIUtility.ComparisonViewMode.None && - PrefabUtility.GetCorrespondingObjectFromSource(comp.gameObject) != null && + PrefabUtility.GetCorrespondingConnectedObjectFromSource(comp.gameObject) != null && PrefabUtility.GetCorrespondingObjectFromSource(comp) == null; } @@ -5006,16 +5007,20 @@ internal static void RemovedComponentTitlebar(Rect position, GameObject instance GenericMenu menu = new GenericMenu(); PrefabUtility.HandleApplyRevertMenuItems( "Removed Component", - sourceComponent, + instanceGo, (menuItemContent, sourceObject) => { TargetChoiceHandler.ObjectInstanceAndSourceInfo info = new TargetChoiceHandler.ObjectInstanceAndSourceInfo(); info.instanceObject = instanceGo; Component componentToRemove = sourceComponent; - while (componentToRemove != sourceObject) + while (componentToRemove.gameObject != sourceObject) + { componentToRemove = PrefabUtility.GetCorrespondingObjectFromSource(componentToRemove); + if (componentToRemove == null) + return; + } info.correspondingObjectInSource = componentToRemove; - if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(componentToRemove)) + if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(componentToRemove) || EditorUtility.IsPersistent(instanceGo)) menu.AddDisabledItem(menuItemContent); else menu.AddItem(menuItemContent, false, TargetChoiceHandler.ApplyPrefabRemovedComponent, info); @@ -5547,7 +5552,7 @@ internal static GUIContent BeginPropertyInternal(Rect totalPosition, GUIContent var hasPrefabOverride = property.prefabOverride; if (!linkedProperties || hasPrefabOverride) EditorGUIUtility.SetBoldDefaultFont(hasPrefabOverride); - if (hasPrefabOverride && !property.isDefaultOverride) + if (hasPrefabOverride && !property.isDefaultOverride && !property.isDrivenRectTransformProperty) { Rect highlightRect = totalPosition; highlightRect.xMin += EditorGUI.indent; diff --git a/Editor/Mono/EditorGUIUtility.cs b/Editor/Mono/EditorGUIUtility.cs index 0c08cc546e..1fe6f155ea 100644 --- a/Editor/Mono/EditorGUIUtility.cs +++ b/Editor/Mono/EditorGUIUtility.cs @@ -48,7 +48,7 @@ internal static Material GUITextureBlit2SRGBMaterial if (!s_GUITextureBlit2SRGBMaterial) { Shader shader = LoadRequired("SceneView/GUITextureBlit2SRGB.shader") as Shader; - s_GUITextureBlit2SRGBMaterial = new Material(shader) {hideFlags = HideFlags.HideAndDontSave}; + s_GUITextureBlit2SRGBMaterial = new Material(shader); } s_GUITextureBlit2SRGBMaterial.SetFloat("_ManualTex2SRGB", QualitySettings.activeColorSpace == ColorSpace.Linear ? 1.0f : 0.0f); return s_GUITextureBlit2SRGBMaterial; @@ -63,7 +63,7 @@ internal static Material GUITextureBlitSceneGUIMaterial if (!s_GUITextureBlitSceneGUI) { Shader shader = LoadRequired("SceneView/GUITextureBlitSceneGUI.shader") as Shader; - s_GUITextureBlitSceneGUI = new Material(shader) { hideFlags = HideFlags.HideAndDontSave }; + s_GUITextureBlitSceneGUI = new Material(shader); } return s_GUITextureBlitSceneGUI; } @@ -109,7 +109,7 @@ internal static void RepaintCurrentWindow() internal static bool HasCurrentWindowKeyFocus() { CheckOnGUI(); - return GUIView.current.hasFocus; + return GUIView.current != null ? GUIView.current.hasFocus : false; } public static Rect PointsToPixels(Rect rect) diff --git a/Editor/Mono/EditorHandles/PositionHandle.cs b/Editor/Mono/EditorHandles/PositionHandle.cs index 43e851dad2..77ee6a60fc 100644 --- a/Editor/Mono/EditorHandles/PositionHandle.cs +++ b/Editor/Mono/EditorHandles/PositionHandle.cs @@ -100,13 +100,15 @@ internal struct PositionHandleParam [Flags] public enum Handle { + None = 0, X = 1 << 0, Y = 1 << 1, Z = 1 << 2, XY = 1 << 3, YZ = 1 << 4, XZ = 1 << 5, - XYZ = 1 << 6 + XYZ = 1 << 6, + All = ~None } public enum Orientation diff --git a/Editor/Mono/EditorHandles/RotationHandle.cs b/Editor/Mono/EditorHandles/RotationHandle.cs index b830a51912..bfa5526fe6 100644 --- a/Editor/Mono/EditorHandles/RotationHandle.cs +++ b/Editor/Mono/EditorHandles/RotationHandle.cs @@ -82,11 +82,13 @@ internal struct RotationHandleParam [Flags] public enum Handle { + None = 0, X = 1 << 0, Y = 1 << 1, Z = 1 << 2, CameraAxis = 1 << 3, - XYZ = 1 << 4 + XYZ = 1 << 4, + All = ~None } static RotationHandleParam s_Default = new RotationHandleParam((Handle)(-1), Vector3.one, 1f, 1.1f, true, false); diff --git a/Editor/Mono/EditorHandles/ScaleHandle.cs b/Editor/Mono/EditorHandles/ScaleHandle.cs index 7cea5118f9..7385194302 100644 --- a/Editor/Mono/EditorHandles/ScaleHandle.cs +++ b/Editor/Mono/EditorHandles/ScaleHandle.cs @@ -78,10 +78,12 @@ internal struct ScaleHandleParam [Flags] public enum Handle { + None = 0, X = 1 << 0, Y = 1 << 1, Z = 1 << 2, - XYZ = 1 << 3 + XYZ = 1 << 3, + All = ~None } public enum Orientation diff --git a/Editor/Mono/EditorHandles/TransformHandle.cs b/Editor/Mono/EditorHandles/TransformHandle.cs index 893063de8c..288afbf4ae 100644 --- a/Editor/Mono/EditorHandles/TransformHandle.cs +++ b/Editor/Mono/EditorHandles/TransformHandle.cs @@ -237,6 +237,147 @@ public TransformHandleParam( this.vertexSnappingRotation = vertexSnappingRotation; this.vertexSnappingScale = vertexSnappingScale; } + + public TransformHandleParam Without(PositionHandleParam.Handle handles) + { + return new TransformHandleParam( + RemoveHandles(position, handles), + rotation, + scale, + RemoveHandles(cameraAlignedPosition, handles), + cameraAlignedRotation, + cameraAlignedScale, + RemoveHandles(localPosition, handles), + localRotation, + localScale, + RemoveHandles(vertexSnappingPosition, handles), + vertexSnappingRotation, + vertexSnappingScale + ); + } + + static PositionHandleParam RemoveHandles(PositionHandleParam p, PositionHandleParam.Handle handles) + { + return new PositionHandleParam(p.handles & ~handles, p.axisOffset, p.axisSize, p.planeOffset, p.planeSize, p.axesOrientation, p.planeOrientation); + } + + public TransformHandleParam Without(RotationHandleParam.Handle handles) + { + return new TransformHandleParam( + position, + RemoveHandles(rotation, handles), + scale, + cameraAlignedPosition, + RemoveHandles(cameraAlignedRotation, handles), + cameraAlignedScale, + localPosition, + RemoveHandles(localRotation, handles), + localScale, + vertexSnappingPosition, + RemoveHandles(vertexSnappingRotation, handles), + vertexSnappingScale + ); + } + + static RotationHandleParam RemoveHandles(RotationHandleParam r, RotationHandleParam.Handle handles) + { + return new RotationHandleParam(r.handles & ~handles, r.axisSize, r.xyzSize, r.cameraAxisSize, r.enableRayDrag, r.displayXYZCircle); + } + + public TransformHandleParam Without(ScaleHandleParam.Handle handles) + { + return new TransformHandleParam( + position, + rotation, + RemoveHandles(scale, handles), + cameraAlignedPosition, + cameraAlignedRotation, + RemoveHandles(cameraAlignedScale, handles), + localPosition, + localRotation, + RemoveHandles(localScale, handles), + vertexSnappingPosition, + vertexSnappingRotation, + RemoveHandles(vertexSnappingScale, handles) + ); + } + + static ScaleHandleParam RemoveHandles(ScaleHandleParam s, ScaleHandleParam.Handle handles) + { + return new ScaleHandleParam(s.handles & ~handles, s.axisOffset, s.axisSize, s.axisLineScale, s.xyzSize, s.orientation); + } + + public TransformHandleParam WithSoloPositionManipulatorSize() + { + return new TransformHandleParam( + CopyDefaultSize(position), + rotation, + scale, + CopyDefaultSize(cameraAlignedPosition), + cameraAlignedRotation, + cameraAlignedScale, + CopyDefaultSize(localPosition), + localRotation, + localScale, + CopyDefaultSize(vertexSnappingPosition), + vertexSnappingRotation, + vertexSnappingScale + ); + } + + static PositionHandleParam CopyDefaultSize(PositionHandleParam p) + { + var d = PositionHandleParam.DefaultHandle; + return new PositionHandleParam(p.handles, d.axisOffset, d.axisSize, d.planeOffset, d.planeSize, p.axesOrientation, p.planeOrientation); + } + + public TransformHandleParam WithSoloRotationManipulatorSize() + { + return new TransformHandleParam( + position, + CopyDefaultSize(rotation), + scale, + cameraAlignedPosition, + CopyDefaultSize(cameraAlignedRotation), + cameraAlignedScale, + localPosition, + CopyDefaultSize(localRotation), + localScale, + vertexSnappingPosition, + CopyDefaultSize(vertexSnappingRotation), + vertexSnappingScale + ); + } + + static RotationHandleParam CopyDefaultSize(RotationHandleParam r) + { + var d = RotationHandleParam.Default; + return new RotationHandleParam(r.handles, d.axisSize, d.xyzSize, d.cameraAxisSize, r.enableRayDrag, r.displayXYZCircle); + } + + public TransformHandleParam WithSoloScaleManipulatorSize() + { + return new TransformHandleParam( + position, + rotation, + CopyDefaultSize(scale), + cameraAlignedPosition, + cameraAlignedRotation, + CopyDefaultSize(cameraAlignedScale), + localPosition, + localRotation, + CopyDefaultSize(localScale), + vertexSnappingPosition, + vertexSnappingRotation, + CopyDefaultSize(vertexSnappingScale) + ); + } + + static ScaleHandleParam CopyDefaultSize(ScaleHandleParam s) + { + var d = ScaleHandleParam.Default; + return new ScaleHandleParam(s.handles, d.axisOffset, d.axisSize, d.axisLineScale, s.xyzSize, s.orientation); + } } struct RotationHandleData @@ -245,6 +386,7 @@ struct RotationHandleData public Quaternion initialRotation; } + // non-uniform scale public static void TransformHandle(ref Vector3 position, ref Quaternion rotation, ref Vector3 scale) { TransformHandle( @@ -252,6 +394,114 @@ public static void TransformHandle(ref Vector3 position, ref Quaternion rotation ); } + public static void TransformHandle(ref Vector3 position, Quaternion rotation, ref Vector3 scale) + { + TransformHandle( + TransformHandleIds.Default, ref position, ref rotation, ref scale, + TransformHandleParam.Default.Without(RotationHandleParam.Handle.All) + ); + } + + public static void TransformHandle(Vector3 position, ref Quaternion rotation, ref Vector3 scale) + { + TransformHandle( + TransformHandleIds.Default, ref position, ref rotation, ref scale, + TransformHandleParam.Default.Without(PositionHandleParam.Handle.All) + ); + } + + // uniform scale + public static void TransformHandle(ref Vector3 position, ref Quaternion rotation, ref float uniformScale) + { + var s = Vector3.one * uniformScale; + TransformHandle( + TransformHandleIds.Default, ref position, ref rotation, ref s, + TransformHandleParam.Default + .Without(ScaleHandleParam.Handle.X | ScaleHandleParam.Handle.Y | ScaleHandleParam.Handle.Z) + ); + uniformScale = s.x; + } + + public static void TransformHandle(ref Vector3 position, Quaternion rotation, ref float uniformScale) + { + var s = Vector3.one * uniformScale; + TransformHandle( + TransformHandleIds.Default, ref position, ref rotation, ref s, + TransformHandleParam.Default + .Without(RotationHandleParam.Handle.All) + .Without(ScaleHandleParam.Handle.X | ScaleHandleParam.Handle.Y | ScaleHandleParam.Handle.Z) + ); + uniformScale = s.x; + } + + public static void TransformHandle(Vector3 position, ref Quaternion rotation, ref float uniformScale) + { + var s = Vector3.one * uniformScale; + TransformHandle( + TransformHandleIds.Default, ref position, ref rotation, ref s, + TransformHandleParam.Default + .Without(PositionHandleParam.Handle.All) + .Without(ScaleHandleParam.Handle.X | ScaleHandleParam.Handle.Y | ScaleHandleParam.Handle.Z) + ); + uniformScale = s.x; + } + + // only position and rotation + public static void TransformHandle(ref Vector3 position, ref Quaternion rotation) + { + var s = Vector3.one; + TransformHandle( + TransformHandleIds.Default, ref position, ref rotation, ref s, + TransformHandleParam.Default.Without(ScaleHandleParam.Handle.All) + ); + } + + // only position + static void TransformHandle(ref Vector3 position, Quaternion rotation) + { + var s = Vector3.one; + TransformHandle( + TransformHandleIds.Default, ref position, ref rotation, ref s, + TransformHandleParam.Default.Without(ScaleHandleParam.Handle.All).WithSoloPositionManipulatorSize() + ); + } + + // only rotation + static void TransformHandle(Vector3 position, ref Quaternion rotation) + { + var s = Vector3.one; + TransformHandle( + TransformHandleIds.Default, ref position, ref rotation, ref s, + TransformHandleParam.Default.Without(ScaleHandleParam.Handle.All).WithSoloRotationManipulatorSize() + ); + } + + // only scale + static void TransformHandle(Vector3 position, Quaternion rotation, ref Vector3 scale) + { + TransformHandle( + TransformHandleIds.Default, ref position, ref rotation, ref scale, + TransformHandleParam.Default + .Without(PositionHandleParam.Handle.All) + .Without(RotationHandleParam.Handle.All) + .WithSoloScaleManipulatorSize() + ); + } + + static void TransformHandle(Vector3 position, Quaternion rotation, ref float uniformScale) + { + var s = Vector3.one * uniformScale; + TransformHandle( + TransformHandleIds.Default, ref position, ref rotation, ref s, + TransformHandleParam.Default + .Without(PositionHandleParam.Handle.All) + .Without(RotationHandleParam.Handle.All) + .Without(ScaleHandleParam.Handle.X | ScaleHandleParam.Handle.Y | ScaleHandleParam.Handle.Z) + .WithSoloScaleManipulatorSize() + ); + uniformScale = s.x; + } + static bool s_IsHotInCameraAlignedMode = false; static Dictionary s_TransformHandle_RotationData = new Dictionary(); internal static void TransformHandle(TransformHandleIds ids, ref Vector3 position, ref Quaternion rotation, ref Vector3 scale, TransformHandleParam param) diff --git a/Editor/Mono/EditorHandles/VertexSnapping.cs b/Editor/Mono/EditorHandles/VertexSnapping.cs index c6d2638f68..c51b3f74d7 100644 --- a/Editor/Mono/EditorHandles/VertexSnapping.cs +++ b/Editor/Mono/EditorHandles/VertexSnapping.cs @@ -108,6 +108,7 @@ private static void UpdateVertexSnappingOffset() // Important to reset handleOffset before querying handlePosition, // since handlePosition depends on handleOffset. + Tools.InvalidateHandlePosition(); Tools.handleOffset = Vector3.zero; Tools.handleOffset = near - Tools.handlePosition; } diff --git a/Editor/Mono/EditorSettings.bindings.cs b/Editor/Mono/EditorSettings.bindings.cs index d4a9de68db..c985e2c3f7 100644 --- a/Editor/Mono/EditorSettings.bindings.cs +++ b/Editor/Mono/EditorSettings.bindings.cs @@ -177,6 +177,9 @@ public static string webSecurityEmulationHostUrl [StaticAccessor("GetEditorSettings()", StaticAccessorType.Dot)] public static extern bool enableTextureStreamingInPlayMode { get; set; } + [StaticAccessor("GetEditorSettings()", StaticAccessorType.Dot)] + public static extern bool asyncShaderCompilation { get; set; } + public static string[] projectGenerationUserExtensions { get diff --git a/Editor/Mono/EditorUserSettings.bindings.cs b/Editor/Mono/EditorUserSettings.bindings.cs index 49d908b6e4..cc94a79eb7 100644 --- a/Editor/Mono/EditorUserSettings.bindings.cs +++ b/Editor/Mono/EditorUserSettings.bindings.cs @@ -46,6 +46,9 @@ public static string GetConfigValue(string name) [NativeProperty("VCShowFailedCheckout")] public static extern bool showFailedCheckout { get; set; } + [NativeProperty("VCOverwriteFailedCheckoutAssets")] + public static extern bool overwriteFailedCheckoutAssets { get; set; } + [NativeProperty("VCAllowAsyncUpdate")] public static extern bool allowAsyncStatusUpdate { get; set; } diff --git a/Editor/Mono/EditorUtility.bindings.cs b/Editor/Mono/EditorUtility.bindings.cs index d204d99db2..900393e4b2 100644 --- a/Editor/Mono/EditorUtility.bindings.cs +++ b/Editor/Mono/EditorUtility.bindings.cs @@ -53,11 +53,13 @@ public static bool DisplayDialog(string title, string message, string ok) public static extern bool IsPersistent(Object target); public static extern string SaveFilePanel(string title, string directory, string defaultName, string extension); public static extern int NaturalCompare(string a, string b); - public static extern void SetDirty([NotNull] Object target); public static extern Object InstanceIDToObject(int instanceID); public static extern void CompressTexture([NotNull] Texture2D texture, TextureFormat format, int quality); public static extern void CompressCubemapTexture([NotNull] Cubemap texture, TextureFormat format, int quality); + [FreeFunction("EditorUtility::SetDirtyObjectOrScene")] + public static extern void SetDirty([NotNull] Object target); + [FreeFunction("InvokeDiffTool")] public static extern string InvokeDiffTool(string leftTitle, string leftFile, string rightTitle, string rightFile, string ancestorTitle, string ancestorFile); diff --git a/Editor/Mono/EditorUtility.cs b/Editor/Mono/EditorUtility.cs index 1a2574c1a4..373b091d44 100644 --- a/Editor/Mono/EditorUtility.cs +++ b/Editor/Mono/EditorUtility.cs @@ -333,7 +333,7 @@ internal static void DisplayObjectContextMenu(Rect position, Object[] context, i Component targetComponent = (Component)targetObject; // Do nothing if component is not on a prefab instance. - if (PrefabUtility.GetCorrespondingObjectFromSource(targetComponent.gameObject) == null) {} + if (PrefabUtility.GetCorrespondingConnectedObjectFromSource(targetComponent.gameObject) == null) {} // Handle added component. else if (PrefabUtility.GetCorrespondingObjectFromSource(targetObject) == null && targetComponent != null) { @@ -347,7 +347,7 @@ internal static void DisplayObjectContextMenu(Rect position, Object[] context, i info.instanceObject = targetComponent; info.assetPath = AssetDatabase.GetAssetPath(sourceGo); GameObject rootObject = PrefabUtility.GetRootGameObject(sourceGo); - if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootObject)) + if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootObject) || EditorUtility.IsPersistent(instanceGo)) pm.AddDisabledItem(menuItemContent); else pm.AddItem(menuItemContent, false, TargetChoiceHandler.ApplyPrefabAddedComponent, info); @@ -387,7 +387,7 @@ internal static void DisplayObjectContextMenu(Rect position, Object[] context, i info.instanceObject = targetObject; info.assetPath = AssetDatabase.GetAssetPath(sourceObject); GameObject rootObject = PrefabUtility.GetRootGameObject(sourceObject); - if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootObject)) + if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootObject) || EditorUtility.IsPersistent(targetObject)) pm.AddDisabledItem(menuItemContent); else pm.AddItem(menuItemContent, false, TargetChoiceHandler.ApplyPrefabObjectOverride, info); diff --git a/Editor/Mono/EditorWindow.cs b/Editor/Mono/EditorWindow.cs index 823b0e5948..42005fd7a9 100644 --- a/Editor/Mono/EditorWindow.cs +++ b/Editor/Mono/EditorWindow.cs @@ -10,8 +10,7 @@ using UnityEngine.Internal; using Unity.Experimental.EditorMode; -using SerializableJsonDictionary = UnityEditor.Experimental.UIElements.SerializableJsonDictionary; -using ExperimentalVisualElement = UnityEngine.Experimental.UIElements.VisualElement; +using SerializableJsonDictionary = UnityEditor.UIElements.SerializableJsonDictionary; using UnityEngine.UIElements; using UnityEditor.UIElements; @@ -48,26 +47,6 @@ public partial class EditorWindow : ScriptableObject private readonly Dictionary m_RootElementPerEditorMode = new Dictionary(); - //temporary for backward compatibility - internal ExperimentalVisualElement m_RootVisualContainer; - internal ExperimentalVisualElement rootVisualContainer - { - get - { - if (m_RootVisualContainer == null) - { - m_RootVisualContainer = new ExperimentalVisualElement() - { - name = VisualElementUtils.GetUniqueName("rootVisualContainer"), - pickingMode = UnityEngine.Experimental.UIElements.PickingMode.Ignore, // do not eat events so IMGUI gets them - persistenceKey = name - }; - UnityEditor.Experimental.UIElements.UIElementsEditorUtility.AddDefaultEditorStyleSheets(m_RootVisualContainer); - } - return m_RootVisualContainer; - } - } - public VisualElement rootVisualElement { get @@ -80,7 +59,8 @@ internal VisualElement GetRootElement(bool createIfNull) where TMode : Ed { var type = typeof(TMode); VisualElement root = null; - if (!m_RootElementPerEditorMode.TryGetValue(type, out root)) + + if ((m_RootElementPerEditorMode != null) && (!m_RootElementPerEditorMode.TryGetValue(type, out root))) { if (createIfNull) { @@ -91,6 +71,7 @@ internal VisualElement GetRootElement(bool createIfNull) where TMode : Ed root = GetRootElement(true); } } + return root; } @@ -321,8 +302,10 @@ public void RemoveNotification() internal void DrawNotification() { - EditorStyles.notificationText.CalcMinMaxWidth(m_Notification, out m_NotificationSize.y, out m_NotificationSize.x); - m_NotificationSize.y = EditorStyles.notificationText.CalcHeight(m_Notification, m_NotificationSize.x); + if (Event.current.type != EventType.Repaint) + return; + + m_NotificationSize = EditorStyles.notificationText.CalcSize(m_Notification); Vector2 warningSize = m_NotificationSize; float targetWidth = position.width - EditorStyles.notificationText.margin.horizontal; @@ -333,26 +316,20 @@ internal void DrawNotification() if (targetWidth < m_NotificationSize.x) { float scale = targetWidth / m_NotificationSize.x; - warningSize.x *= scale; - warningSize.y = EditorStyles.notificationText.CalcHeight(m_Notification, warningSize.x); scaledNotificationText = new GUIStyle(EditorStyles.notificationText); scaledNotificationText.fontSize = Mathf.FloorToInt(scaledNotificationText.font.fontSize * scale); + + warningSize = scaledNotificationText.CalcSize(m_Notification); } + warningSize.x += 1; //we'll give the text a little room to breathe to avoid word-wrapping issues with drop shadows + if (warningSize.y > targetHeight) warningSize.y = targetHeight; Rect r = new Rect((position.width - warningSize.x) * .5f, 20 + (position.height - 20 - warningSize.y) * .7f, warningSize.x, warningSize.y); - // Round notification coordinate & with to integers, so that text - // shadow rendering(which is offset from base text) gets exactly - // the same floating point results for text wrapping. Without this, - // it can lead to tiny differences that make shadow be word - wrapped - // differently from foreground text. - r.x = Mathf.FloorToInt(r.x); - r.width = Mathf.FloorToInt(r.width); - double time = EditorApplication.timeSinceStartup; if (time > m_FadeoutTime) GUI.color = new Color(1, 1, 1, 1 - (float)((time - m_FadeoutTime) / kWarningFadeoutTime)); @@ -678,24 +655,10 @@ internal void ShowModal() ShowWithMode(ShowMode.AuxWindow); SavedGUIState guiState = SavedGUIState.Create(); - if (m_Parent.uieMode == GUIView.UIElementsMode.Public) - { - m_Parent.visualTree.panel.dispatcher?.PushDispatcherContext(); - } - else if (m_Parent.uieMode == GUIView.UIElementsMode.Experimental) - { - m_Parent.experimentalVisualTree.panel.dispatcher?.PushDispatcherContext(); - } + m_Parent.visualTree.panel.dispatcher?.PushDispatcherContext(); MakeModal(m_Parent.window); - if (m_Parent.uieMode == GUIView.UIElementsMode.Public) - { - m_Parent.visualTree.panel.dispatcher?.PopDispatcherContext(); - } - else if (m_Parent.uieMode == GUIView.UIElementsMode.Experimental) - { - m_Parent.experimentalVisualTree.panel.dispatcher?.PopDispatcherContext(); - } + m_Parent.visualTree.panel.dispatcher?.PopDispatcherContext(); guiState.ApplyAndForget(); } @@ -1111,9 +1074,6 @@ public Rect position private void RefreshStylesAfterExternalEvent() { - if (m_Parent.uieMode != GUIView.UIElementsMode.Public) - return; - var panel = m_Parent.visualTree.elementPanel; if (panel == null) return; @@ -1193,35 +1153,6 @@ internal class EditorWindowTitleAttribute : System.Attribute public bool useTypeNameAsIconName { get; set; } } - // makes UIElements opt-in while it's experimental, as a using statement is necessary to call this method - namespace Experimental.UIElements - { - public static class UIElementsEntryPoint - { - public static ExperimentalVisualElement GetRootVisualContainer(this EditorWindow window) - { - var result = window.rootVisualContainer; - - //this nasty code is temporary, thank god! - if (result.panel == null && window.m_Parent != null && window.m_Parent.actualView == window) - { - window.m_Parent.RegisterExperimentalUIElementWindow(); - } - - return result; - } - - public static void SetAntiAliasing(this EditorWindow window, int aa) - { - window.antiAliasing = aa; - } - - public static int GetAntiAliasing(this EditorWindow window) - { - return window.antiAliasing; - } - } - } namespace UIElements { public static class UIElementsEntryPoint diff --git a/Editor/Mono/GUI/AnimatedValues.cs b/Editor/Mono/GUI/AnimatedValues.cs index d938c4a44c..2811aa5c6c 100644 --- a/Editor/Mono/GUI/AnimatedValues.cs +++ b/Editor/Mono/GUI/AnimatedValues.cs @@ -11,6 +11,8 @@ namespace UnityEditor.AnimatedValues public abstract class BaseAnimValue { T m_Start; + + [SerializeField] T m_Target; double m_LastTime; diff --git a/Editor/Mono/GUI/AppStatusBar.cs b/Editor/Mono/GUI/AppStatusBar.cs index 9fa8036c83..f8ff66f043 100644 --- a/Editor/Mono/GUI/AppStatusBar.cs +++ b/Editor/Mono/GUI/AppStatusBar.cs @@ -60,7 +60,7 @@ protected override void OldOnGUI() const int statusWheelWidth = 24; const int progressBarStatusWheelSpacing = 3; const int progressBarWidth = 185; - const int lightingBakeModeBarWidth = 80; + const int lightingBakeModeBarWidth = 140; const int barHeight = 19; ConsoleWindow.LoadIcons(); @@ -177,7 +177,7 @@ private string GetBakeModeString() if (!showBakeMode) return ""; - return "Auto Bake " + (Lightmapping.giWorkflowMode == Lightmapping.GIWorkflowMode.Iterative ? "On" : "Off"); + return "Auto Generate Lighting " + (Lightmapping.giWorkflowMode == Lightmapping.GIWorkflowMode.Iterative ? "On" : "Off"); } } } //namespace diff --git a/Editor/Mono/GUI/DockArea.cs b/Editor/Mono/GUI/DockArea.cs index 55ae29a7c5..663c6b4844 100644 --- a/Editor/Mono/GUI/DockArea.cs +++ b/Editor/Mono/GUI/DockArea.cs @@ -161,19 +161,11 @@ protected override void OnEnable() base.OnEnable(); - if (uieMode == UIElementsMode.Experimental) + if (imguiContainer != null) { - if (experimentalImguiContainer != null) - experimentalImguiContainer.name = VisualElementUtils.GetUniqueName("Dockarea"); - } - else - { - if (imguiContainer != null) - { - imguiContainer.name = VisualElementUtils.GetUniqueName("Dockarea"); - imguiContainer.tabIndex = -1; - imguiContainer.focusOnlyIfHasFocusableControls = false; - } + imguiContainer.name = VisualElementUtils.GetUniqueName("Dockarea"); + imguiContainer.tabIndex = -1; + imguiContainer.focusOnlyIfHasFocusableControls = false; } } @@ -324,8 +316,8 @@ protected override void OldOnGUI() dockAreaRect.x = background.margin.left; Rect wPos = windowPosition; Rect containerWindowPosition = window.position; - containerWindowPosition.width = Mathf.FloorToInt(containerWindowPosition.width); - containerWindowPosition.height = Mathf.FloorToInt(containerWindowPosition.height); + containerWindowPosition.width = Mathf.Ceil(containerWindowPosition.width); + containerWindowPosition.height = Mathf.Ceil(containerWindowPosition.height); bool customBorder = floatingWindow && windowPosition.y == 0; bool isBottomTab = wPos.yMax == containerWindowPosition.height; @@ -414,11 +406,9 @@ private Rect UpdateViewRect(Rect dockAreaRect, bool isBottomTab, bool customBord { const float viewMarginLeftOffset = 2f; float viewMarginTopOffset = customBorder ? 1f : 2f; - var viewRect = new Rect( - dockAreaRect.x + viewMarginLeftOffset, - dockAreaRect.y + kTabHeight - viewMarginTopOffset - 1f, - dockAreaRect.width - viewMarginLeftOffset * 2f, - dockAreaRect.height - kTabHeight + viewMarginTopOffset - (customBorder ? -1f : 1f) + (floatingWindow && isBottomTab ? 1f : 0f)); + float x = dockAreaRect.x + viewMarginLeftOffset; + float y = dockAreaRect.y + kTabHeight - viewMarginTopOffset - 1f; + var viewRect = new Rect(x, y, position.width - x, position.height - y); if (selected >= 0 && selected < m_Panes.Count) m_Panes[selected].m_Pos = new Rect(GUIUtility.GUIToScreenPoint(Vector2.zero), viewRect.size); @@ -695,7 +685,7 @@ protected override void AddDefaultItemsToMenu(GenericMenu menu, EditorWindow vie } menu.AddSeparator(""); - menu.AddItem(EditorGUIUtility.TextContent("UIElements Debugger _%f5"), false, DebugWindow, view); + AddUIElementsDebuggerToMenu(menu); } void AddTabToHere(object userData) @@ -1137,7 +1127,7 @@ protected override void AddDefaultItemsToMenu(GenericMenu menu, EditorWindow win } menu.AddSeparator(""); - menu.AddItem(EditorGUIUtility.TextContent("UIElements Debugger _%f5"), false, DebugWindow, window); + AddUIElementsDebuggerToMenu(menu); } } } diff --git a/Editor/Mono/GUI/EditModeTools/EditModeTool.cs b/Editor/Mono/GUI/EditModeTools/EditModeTool.cs new file mode 100644 index 0000000000..c07148d361 --- /dev/null +++ b/Editor/Mono/GUI/EditModeTools/EditModeTool.cs @@ -0,0 +1,96 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; +using UnityEditor.EditorTools; +using UnityEditorInternal; +using UnityEngine; +using SceneViewEditMode = UnityEditorInternal.EditMode.SceneViewEditMode; + +namespace UnityEditor +{ + abstract class EditModeTool : EditorTool + { + GUIContent m_Content; + IToolModeOwner m_Owner; + bool m_CanEditMultipleObjects; + + protected EditModeTool() + { + m_CanEditMultipleObjects = editorType.GetCustomAttributes(typeof(CanEditMultipleObjects), false).Length > 0; + } + + void OnEnable() + { + EditorTools.EditorTools.activeToolChanged += ActiveToolChanged; + } + + void OnDisable() + { + EditorTools.EditorTools.activeToolChanged -= ActiveToolChanged; + } + + public abstract SceneViewEditMode editMode { get; } + + public abstract Type editorType { get; } + + public override GUIContent toolbarIcon + { + get + { + if (m_Content == null) + { + var customEditorAttributes = editorType.GetCustomAttributes(typeof(CustomEditor), false); + + if (customEditorAttributes.Length > 0) + { + m_Content = new GUIContent( + AssetPreview.GetMiniTypeThumbnailFromType(((CustomEditor)customEditorAttributes[0]) + .m_InspectedType), + editorType.ToString()); + } + else + { + m_Content = new GUIContent(editorType.ToString(), editorType.ToString()); + } + } + + return m_Content; + } + } + + public IToolModeOwner owner + { + get { return m_Owner; } + internal set { m_Owner = value; } + } + + public override bool IsAvailable() + { + return m_CanEditMultipleObjects || Selection.count == 1; + } + + void ActiveToolChanged() + { + if (EditorTools.EditorTools.IsActiveTool(this)) + OnActivate(); + else + OnDeactivate(); + } + + void OnActivate() + { + if (EditorApplication.isPlayingOrWillChangePlaymode && !EditorApplication.isPlaying) + return; + EditMode.ChangeEditModeFromToolContext(owner, editMode); + } + + void OnDeactivate() + { + if (EditorApplication.isPlayingOrWillChangePlaymode && !EditorApplication.isPlaying) + return; + EditMode.ChangeEditModeFromToolContext(owner, SceneViewEditMode.None); + } + } +} diff --git a/Editor/Mono/GUI/EditorStyles.cs b/Editor/Mono/GUI/EditorStyles.cs index f5d19e0b66..4cdafe2260 100644 --- a/Editor/Mono/GUI/EditorStyles.cs +++ b/Editor/Mono/GUI/EditorStyles.cs @@ -297,6 +297,11 @@ public sealed class EditorStyles // the editor styles currently in use internal static EditorStyles s_Current; + static EditorStyles() + { + s_Current = new EditorStyles(); + } + // the list of editor styles to use private static EditorStyles[] s_CachedStyles = { null, null }; diff --git a/Editor/Mono/GUI/FlowLayout.cs b/Editor/Mono/GUI/FlowLayout.cs index b63403b9bc..24fc24e6f6 100644 --- a/Editor/Mono/GUI/FlowLayout.cs +++ b/Editor/Mono/GUI/FlowLayout.cs @@ -75,7 +75,7 @@ public override void SetHorizontal(float x, float width) if (i.rect.xMax - pulledOffset > x + width) { // TODO: When we move a line back, we should re-expand - pulledOffset = i.rect.x - i.margin.left; + pulledOffset = i.rect.x - i.marginLeft; m_Lines++; } i.SetHorizontal(i.rect.x - pulledOffset, i.rect.width); @@ -114,8 +114,8 @@ public override void CalcHeight() int j = (int)i.rect.y; m_LineInfo[j].minSize = Mathf.Max(i.minHeight, m_LineInfo[j].minSize); m_LineInfo[j].maxSize = Mathf.Max(i.maxHeight, m_LineInfo[j].maxSize); - m_LineInfo[j].topBorder = Mathf.Min(i.margin.top, m_LineInfo[j].topBorder); - m_LineInfo[j].bottomBorder = Mathf.Min(i.margin.bottom, m_LineInfo[j].bottomBorder); + m_LineInfo[j].topBorder = Mathf.Min(i.marginTop, m_LineInfo[j].topBorder); + m_LineInfo[j].bottomBorder = Mathf.Min(i.marginBottom, m_LineInfo[j].bottomBorder); } for (int i = 0; i < m_Lines; i++) @@ -138,8 +138,8 @@ public override void CalcHeight() // Do the dance between children & parent for haggling over how many empty pixels to have float firstPadding, lastPadding; - margin.top = _topMarginMin; - margin.bottom = _bottomMarginMin; + m_MarginTop = _topMarginMin; + m_MarginBottom = _bottomMarginMin; firstPadding = lastPadding = 0; minHeight = Mathf.Max(minHeight, m_ChildMinHeight + firstPadding + lastPadding); @@ -173,8 +173,8 @@ public override void SetVertical(float y, float height) y = 0; float clientY, clientHeight; - clientY = y - margin.top; - clientHeight = y + margin.vertical; + clientY = y - marginTop; + clientHeight = y + marginVertical; // Figure out how to distribute the elements between the different lines float heightToDistribute = clientHeight - spacing * (m_Lines - 1); @@ -197,9 +197,9 @@ public override void SetVertical(float y, float height) { LineInfo li = m_LineInfo[(int)i.rect.y]; if (i.stretchHeight != 0) - i.SetVertical(li.start + i.margin.top, li.size - i.margin.vertical); + i.SetVertical(li.start + i.marginTop, li.size - i.marginVertical); else - i.SetVertical(li.start + i.margin.top, Mathf.Clamp(li.size - i.margin.vertical, i.minHeight, i.maxHeight)); + i.SetVertical(li.start + i.marginTop, Mathf.Clamp(li.size - i.marginVertical, i.minHeight, i.maxHeight)); } } } diff --git a/Editor/Mono/GUI/ListViewGUILayout.cs b/Editor/Mono/GUI/ListViewGUILayout.cs index 60b1e549c3..706c09d9e4 100644 --- a/Editor/Mono/GUI/ListViewGUILayout.cs +++ b/Editor/Mono/GUI/ListViewGUILayout.cs @@ -148,8 +148,8 @@ public override void CalcHeight() base.CalcHeight(); - margin.top = 0; - margin.bottom = 0; + m_MarginTop = 0; + m_MarginBottom = 0; if (minHeight == 0) // empty lv? { diff --git a/Editor/Mono/GUI/MaskFieldGUI.cs b/Editor/Mono/GUI/MaskFieldGUI.cs index 1a667890de..2d5ea383eb 100644 --- a/Editor/Mono/GUI/MaskFieldGUI.cs +++ b/Editor/Mono/GUI/MaskFieldGUI.cs @@ -172,7 +172,7 @@ internal static void GetMenuOptions(int mask, string[] flagNames, int[] flagValu var flagEndIndex = flagStartIndex + flagCount; // Button text - buttonText = "Mixed ..."; + buttonText = "Mixed..."; if (mask == 0) buttonText = nothingName; else if (mask == ~0) diff --git a/Editor/Mono/GUI/PopupWindow.cs b/Editor/Mono/GUI/PopupWindow.cs index 8ab95b6ae0..a893de091c 100644 --- a/Editor/Mono/GUI/PopupWindow.cs +++ b/Editor/Mono/GUI/PopupWindow.cs @@ -136,7 +136,6 @@ internal void CloseContent() { if (m_WindowContent != null) m_WindowContent.OnClose(); - m_WindowContent = null; } } } diff --git a/Editor/Mono/GUI/RenameOverlay.cs b/Editor/Mono/GUI/RenameOverlay.cs index b6bc34e1ef..e5e895213c 100644 --- a/Editor/Mono/GUI/RenameOverlay.cs +++ b/Editor/Mono/GUI/RenameOverlay.cs @@ -54,7 +54,7 @@ internal class RenameOverlay string k_RenameOverlayFocusName = "RenameOverlayField"; // property interface - public string name { get {return m_Name; }} + public string name { get {return m_Name; } internal set { m_Name = value; } } public string originalName { get {return m_OriginalName; }} public bool userAcceptedRename { get {return m_UserAcceptedRename; }} public int userData { get {return m_UserData; }} diff --git a/Editor/Mono/GUI/ReorderableList.cs b/Editor/Mono/GUI/ReorderableList.cs index bb40168f64..fedacbc972 100644 --- a/Editor/Mono/GUI/ReorderableList.cs +++ b/Editor/Mono/GUI/ReorderableList.cs @@ -31,6 +31,7 @@ public class ReorderableList public delegate void ChangedCallbackDelegate(ReorderableList list); public delegate bool CanRemoveCallbackDelegate(ReorderableList list); public delegate bool CanAddCallbackDelegate(ReorderableList list); + public delegate void DragCallbackDelegate(ReorderableList list); // draw callbacks @@ -51,6 +52,7 @@ public class ReorderableList public AddCallbackDelegate onAddCallback; public AddDropdownCallbackDelegate onAddDropdownCallback; public RemoveCallbackDelegate onRemoveCallback; + public DragCallbackDelegate onMouseDragCallback; public SelectCallbackDelegate onMouseUpCallback; public CanRemoveCallbackDelegate onCanRemoveCallback; public CanAddCallbackDelegate onCanAddCallback; @@ -705,6 +707,9 @@ private void DoDraggingAndSelection(Rect listRect) // Set m_Dragging state on first MouseDrag event after we got hotcontrol (to prevent animating elements when deleting elements by context menu) m_Dragging = true; + if (onMouseDragCallback != null) + onMouseDragCallback(this); + // if we are dragging, update the position UpdateDraggedY(listRect); evt.Use(); diff --git a/Editor/Mono/GUI/SplitView.cs b/Editor/Mono/GUI/SplitView.cs index f0fc43a7ff..0105d78bf5 100644 --- a/Editor/Mono/GUI/SplitView.cs +++ b/Editor/Mono/GUI/SplitView.cs @@ -92,7 +92,7 @@ void SetupRectsFromSplitter() if (children.Length == 0) return; - int cursor = 0; + float cursor = 0; int total = 0; foreach (int size in splitState.realSizes) @@ -108,15 +108,7 @@ void SetupRectsFromSplitter() SavedGUIState state = SavedGUIState.Create(); for (int i = 0; i < children.Length; i++) - { - int size = (int)Mathf.Round(splitState.realSizes[i] * scale); - if (vertical) - children[i].position = new Rect(0, cursor, position.width, size); - else - children[i].position = new Rect(cursor, 0, size, position.height); - - cursor += size; - } + cursor += PlaceView(i, cursor, Mathf.Round(splitState.realSizes[i] * scale)); state.ApplyAndForget(); } @@ -165,17 +157,32 @@ internal override void Reflow() for (int k = 0; k < children.Length - 1; k++) splitState.DoSplitter(k, k + 1, 0); - splitState.RelativeToRealSizes(vertical ? (int)position.height : (int)position.width); + splitState.RelativeToRealSizes(vertical ? Mathf.RoundToInt(position.height) : Mathf.RoundToInt(position.width)); SetupRectsFromSplitter(); } - void PlaceView(int i, float pos, float size) + float PlaceView(int i, float pos, float size) { + float width = position.width; + float height = position.height; float roundPos = Mathf.Round(pos); + float roundSize = Mathf.Round(size); + Rect newRect; if (vertical) - children[i].position = new Rect(0, roundPos, position.width, Mathf.Round(pos + size) - roundPos); + { + newRect = new Rect(0, roundPos, width, roundSize); + if (i == children.Length - 1) + newRect.height = height - roundPos; + } else - children[i].position = new Rect(roundPos, 0, Mathf.Round(pos + size) - roundPos, position.height); + { + newRect = new Rect(roundPos, 0, roundSize, height); + if (i == children.Length - 1) + newRect.width = width - roundPos; + } + + children[i].position = newRect; + return vertical ? newRect.height : newRect.width; } public override void AddChild(View child, int idx) @@ -470,14 +477,8 @@ void MakeRoomForRect(Rect r) sources[i] = children[i].position; CalcRoomForRect(sources, r); - // string s = "Making room for " + r +" \nchildren {\n"; for (int i = 0; i < sources.Length; i++) - { - // s += " " + sources[i] + " \n"; children[i].position = sources[i]; - } - // s+= "}"; - // Debug.Log (s); } void CalcRoomForRect(Rect[] sources, Rect r) diff --git a/Editor/Mono/GUI/Splitter.cs b/Editor/Mono/GUI/Splitter.cs index 407e25370a..16a3e705f8 100644 --- a/Editor/Mono/GUI/Splitter.cs +++ b/Editor/Mono/GUI/Splitter.cs @@ -296,8 +296,8 @@ public override void SetVertical(float y, float height) float topMar = padding.top, bottomMar = padding.bottom; if (entries.Count != 0) { - topMar = Mathf.Max(topMar, ((GUILayoutEntry)entries[0]).margin.top); - bottomMar = Mathf.Max(bottomMar, ((GUILayoutEntry)entries[entries.Count - 1]).margin.bottom); + topMar = Mathf.Max(topMar, ((GUILayoutEntry)entries[0]).marginTop); + bottomMar = Mathf.Max(bottomMar, ((GUILayoutEntry)entries[entries.Count - 1]).marginBottom); } y += topMar; height -= bottomMar + topMar; @@ -334,9 +334,9 @@ public override void SetVertical(float y, float height) { foreach (GUILayoutEntry i in entries) { - float topMar = Mathf.Max(i.margin.top, padding.top); + float topMar = Mathf.Max(i.marginTop, padding.top); float thisY = y + topMar; - float thisHeight = height - Mathf.Max(i.margin.bottom, padding.bottom) - topMar; + float thisHeight = height - Mathf.Max(i.marginBottom, padding.bottom) - topMar; if (i.stretchHeight != 0) i.SetVertical(thisY, thisHeight); @@ -347,14 +347,14 @@ public override void SetVertical(float y, float height) else { // If not, the subelements' margins have already been propagated upwards to this group, so we can safely ignore them - float thisY = y - margin.top; - float thisHeight = height + margin.vertical; + float thisY = y - marginTop; + float thisHeight = height + marginVertical; foreach (GUILayoutEntry i in entries) { if (i.stretchHeight != 0) - i.SetVertical(thisY + i.margin.top, thisHeight - i.margin.vertical); + i.SetVertical(thisY + i.marginTop, thisHeight - i.marginVertical); else - i.SetVertical(thisY + i.margin.top, Mathf.Clamp(thisHeight - i.margin.vertical, i.minHeight, i.maxHeight)); + i.SetVertical(thisY + i.marginTop, Mathf.Clamp(thisHeight - i.marginVertical, i.minHeight, i.maxHeight)); } } } diff --git a/Editor/Mono/GUI/Toolbar.cs b/Editor/Mono/GUI/Toolbar.cs index a114374de6..11ac78b13c 100644 --- a/Editor/Mono/GUI/Toolbar.cs +++ b/Editor/Mono/GUI/Toolbar.cs @@ -357,7 +357,7 @@ void DoToolButtons(Rect rect) || (evt.button == 0 && evt.modifiers == EventModifiers.Alt)) ) { - EditorToolGUI.DoToolHistoryContextMenu(); + EditorToolGUI.DoToolContextMenu(); } else { diff --git a/Editor/Mono/GUI/Tools/BuiltinTools.cs b/Editor/Mono/GUI/Tools/BuiltinTools.cs index 222730caaf..509e9c2ac7 100644 --- a/Editor/Mono/GUI/Tools/BuiltinTools.cs +++ b/Editor/Mono/GUI/Tools/BuiltinTools.cs @@ -406,7 +406,7 @@ protected override void ToolGUI(SceneView view, Vector3 handlePosition, bool isS GUI.color = fadedColor; } - Vector3 oldPivot = Tools.GetHandlePosition(); + Vector3 oldPivot = Tools.cachedHandlePosition; // Pivot handle if (!Tools.vertexDragging) diff --git a/Editor/Mono/GUI/Tools/EditorTool.cs b/Editor/Mono/GUI/Tools/EditorTool.cs index 676167d245..e0f30eee96 100644 --- a/Editor/Mono/GUI/Tools/EditorTool.cs +++ b/Editor/Mono/GUI/Tools/EditorTool.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using UnityEngine; -using UObject = UnityEngine.Object; +using UnityObject = UnityEngine.Object; namespace UnityEditor.EditorTools { @@ -28,9 +28,13 @@ public abstract class EditorTool : ScriptableObject { [HideInInspector] [SerializeField] - internal UObject[] m_Targets; + internal UnityObject[] m_Targets; - public IEnumerable targets + [HideInInspector] + [SerializeField] + internal UnityObject m_Target; + + public IEnumerable targets { get { @@ -45,14 +49,15 @@ public IEnumerable targets } } + public UnityObject target + { + get { return m_Target == null ? Selection.activeObject : m_Target; } + } + public abstract GUIContent toolbarIcon { get; } public virtual void OnToolGUI(EditorWindow window) {} - public virtual void OnActivate() {} - - public virtual void OnDeactivate() {} - public virtual bool IsAvailable() { return true; diff --git a/Editor/Mono/GUI/Tools/EditorToolContext.cs b/Editor/Mono/GUI/Tools/EditorToolContext.cs index dfca84ca13..51c7db8f7d 100644 --- a/Editor/Mono/GUI/Tools/EditorToolContext.cs +++ b/Editor/Mono/GUI/Tools/EditorToolContext.cs @@ -7,7 +7,7 @@ using System.ComponentModel; using System.Linq; using UnityEngine; -using UObject = UnityEngine.Object; +using UnityObject = UnityEngine.Object; namespace UnityEditor.EditorTools { @@ -19,8 +19,24 @@ sealed class EditorToolContext : ScriptableSingleton [SerializeField] EditorTool m_ActiveTool; + static ActiveEditorTracker m_Tracker; + + [SerializeField] + List m_ToolHistory = new List(); + static bool s_ChangingActiveTool; + // Mimic behavior of Tools.toolChanged for backwards compatibility until existing tools are converted to the new + // apis. + internal static event Action activeToolChanged; + + // EditorTools that are created as custom editor tools. This list represents only the shared tracker. + List m_CustomEditorTools = new List(); + + // This list represents any custom editor tools created by locked inspectors. They are not shown in the scene + // or context menu. + List m_LockedCustomEditorTools = new List(); + internal static EditorTool activeTool { get @@ -31,7 +47,11 @@ internal static EditorTool activeTool set { if (s_ChangingActiveTool) + { + // pop the changing state so that we don't lock the active tool after an exception is thrown. + s_ChangingActiveTool = false; throw new InvalidOperationException("Attempting to set the active tool from EditorTool.OnActivate or EditorTool.OnDeactivate. This is not allowed."); + } var tool = value; @@ -50,28 +70,34 @@ internal static EditorTool activeTool instance.m_ToolHistory.Add(tool); - if (instance.m_ActiveTool != null) - instance.m_ActiveTool.OnDeactivate(); + EditorTools.ActiveToolWillChange(); var previous = instance.m_ActiveTool; + instance.m_ActiveTool = tool; - tool.OnActivate(); + EditorTools.ActiveToolDidChange(); + + if (activeToolChanged != null) + activeToolChanged(previous, instance.m_ActiveTool); Tools.SyncToolEnum(); - s_ChangingActiveTool = false; + Tools.InvalidateHandlePosition(); - if (toolChanged != null) - toolChanged(previous, tool); + s_ChangingActiveTool = false; } } - [SerializeField] - List m_ToolHistory = new List(); - - // The currently available CustomEditor EditorTools. - HashSet m_CustomEditorTools = new HashSet(); + static ActiveEditorTracker tracker + { + get + { + if (m_Tracker == null) + m_Tracker = new ActiveEditorTracker(); + return m_Tracker; + } + } [Serializable] struct CustomEditorToolContext : ISerializationCallbackReceiver @@ -84,7 +110,9 @@ struct CustomEditorToolContext : ISerializationCallbackReceiver public Type editorToolType; - public UObject[] targetObjects; + public UnityObject targetObject; + + public UnityObject[] targetObjects; public string editorToolState { @@ -98,12 +126,14 @@ public CustomEditorToolContext(EditorTool tool) if (tool != null) { editorToolType = tool.GetType(); + targetObject = tool.target; targetObjects = tool.targets.ToArray(); m_EditorToolState = EditorJsonUtility.ToJson(tool); } else { editorToolType = null; + targetObject = null; targetObjects = null; m_EditorToolState = null; } @@ -145,8 +175,6 @@ public void OnAfterDeserialize() [SerializeField] CustomEditorToolContext m_PreviousCustomEditorToolContext; - public static event Action toolChanged; - // EditorApplication.isPlayingOrWillEnterPlayMode doesn't handle exiting. [SerializeField] PlayModeStateChange m_PlayModeState; @@ -161,9 +189,6 @@ void OnEnable() Undo.undoRedoPerformed += UndoRedoPerformed; ActiveEditorTracker.editorTrackerRebuilt += TrackerRebuilt; Selection.selectedObjectWasDestroyed += SelectedObjectWasDestroyed; - - if (m_ActiveTool != null) - m_ActiveTool.OnActivate(); } void OnDisable() @@ -174,9 +199,6 @@ void OnDisable() ActiveEditorTracker.editorTrackerRebuilt -= TrackerRebuilt; ClearCustomEditorTools(); - - if (m_ActiveTool != null) - m_ActiveTool.OnDeactivate(); } void PlayModeStateChanged(PlayModeStateChange state) @@ -196,6 +218,7 @@ void PlayModeStateChanged(PlayModeStateChange state) break; case PlayModeStateChange.ExitingPlayMode: + // ExitPlayMode tests invoke this callback twice if (EditorApplication.isPlaying) m_PlayModeState = PlayModeStateChange.ExitingPlayMode; @@ -203,7 +226,7 @@ void PlayModeStateChanged(PlayModeStateChange state) } // TrackerRebuilt is called during the ExitingEditMode phase, but the selection might not be valid yet. - if (m_PlayModeState == PlayModeStateChange.EnteredPlayMode) + if (m_PlayModeState == PlayModeStateChange.EnteredPlayMode || m_PlayModeState == PlayModeStateChange.EnteredEditMode) RebuildAvailableCustomEditorTools(); } @@ -225,7 +248,7 @@ void EnsureCurrentToolIsNotNull() void SelectedObjectWasDestroyed(int id) { - if (m_CustomEditorTools.Contains(m_ActiveTool) && + if (m_CustomEditorTools.Any(x => x == m_ActiveTool) && m_ActiveTool.m_Targets.Any(x => x == null || x.GetInstanceID() == id)) { m_PreviousCustomEditorToolContext = new CustomEditorToolContext(m_ActiveTool); @@ -242,27 +265,40 @@ void RestoreCustomEditorTool() { var restored = m_CustomEditorTools.FirstOrDefault(m_PreviousCustomEditorToolContext.IsEqual); + // Check for existence in locked inspectors too, but only if the locked inspector target is being inspected + if (restored == null + && m_PreviousCustomEditorToolContext.targetObject != null + && Selection.objects.Any(x => x.Equals(m_PreviousCustomEditorToolContext.targetObject))) + restored = m_LockedCustomEditorTools.FirstOrDefault(m_PreviousCustomEditorToolContext.IsEqual); + if (restored != null) { var targets = restored.targets.ToArray(); EditorJsonUtility.FromJsonOverwrite(m_PreviousCustomEditorToolContext.editorToolState, restored); restored.m_Targets = targets; + restored.m_Target = targets.Last(); activeTool = restored; } m_PreviousCustomEditorToolContext = CustomEditorToolContext.Empty; } + // destroy invalid custom editor tools void ClearCustomEditorTools() { - foreach (var tool in m_CustomEditorTools) + foreach (var customEditorTool in m_CustomEditorTools) { - if (tool != null && tool != m_ActiveTool) - { - DestroyImmediate(tool); - } + if (customEditorTool != null && customEditorTool != m_ActiveTool) + DestroyImmediate(customEditorTool); } + foreach (var customEditorTool in m_LockedCustomEditorTools) + { + if (customEditorTool != null && customEditorTool != m_ActiveTool) + DestroyImmediate(customEditorTool); + } + + m_LockedCustomEditorTools.Clear(); m_CustomEditorTools.Clear(); } @@ -355,13 +391,13 @@ internal static void OnToolGUI(EditorWindow window) } } - bool IsCustomEditorTool(EditorTool tool) + static bool IsCustomEditorTool(EditorTool tool) { - return tool != null - && tool.m_Targets != null - && tool.m_Targets.Length > 0; + return EditorToolUtility.IsCustomEditorTool(tool != null ? tool.GetType() : null); } + static List s_CustomEditorTools = new List(); + void RebuildAvailableCustomEditorTools() { // Do not rebuild the cache since objects are serialized, destroyed, deserialized during this phase @@ -369,66 +405,183 @@ void RebuildAvailableCustomEditorTools() m_PlayModeState == PlayModeStateChange.ExitingPlayMode) return; - var isCustomEditorTool = IsCustomEditorTool(m_ActiveTool); + var preservedActiveTool = false; ClearCustomEditorTools(); - foreach (var kvp in EditorToolUtility.FindActiveCustomEditorTools()) + var inspectors = InspectorWindow.GetInspectors(); + + // If the shared tracker is locked, use our own tracker instance so that the current selection is always + // represented. Addresses case where a single locked inspector is open. + var shared = ActiveEditorTracker.sharedTracker; + preservedActiveTool |= CollectCustomEditorToolsFromTracker(shared.isLocked ? tracker : shared, m_CustomEditorTools); + + foreach (var inspector in inspectors) { - var toolType = kvp.Key; - var toolInfo = kvp.Value.ToArray(); + if (inspector.isLocked) + preservedActiveTool |= CollectCustomEditorToolsFromTracker(inspector.tracker, m_LockedCustomEditorTools); + } - if (isCustomEditorTool && m_ActiveTool.GetType() == toolType) + if (IsCustomEditorTool(m_ActiveTool) && !preservedActiveTool) + { + var previous = m_ActiveTool; + m_PreviousCustomEditorToolContext = new CustomEditorToolContext(m_ActiveTool); + RestorePreviousTool(); + DestroyImmediate(previous); + } + } + + bool CollectCustomEditorToolsFromTracker(ActiveEditorTracker tracker, List list) + { + list.Clear(); + var activeIsCustomEditorTool = IsCustomEditorTool(m_ActiveTool); + var preservedActiveTool = false; + + EditorToolUtility.GetEditorToolsForTracker(tracker, s_CustomEditorTools); + + foreach (var customEditorTool in s_CustomEditorTools) + { + var toolType = customEditorTool.editorToolType; + var toolOwner = customEditorTool.owner; + + EditorTool customEditorToolInstance; + + // The only case where a custom editor tool is serialized is when it is the active tool. All other + // instances are discarded and rebuilt on any tracker rebuild. + if (activeIsCustomEditorTool && CustomEditorToolIsMatch(toolOwner, toolType, m_ActiveTool)) { - m_ActiveTool.m_Targets = toolInfo; - m_CustomEditorTools.Add(m_ActiveTool); + preservedActiveTool = true; + + m_ActiveTool.m_Targets = toolOwner.targets; + m_ActiveTool.m_Target = toolOwner.target; + + // domain reload - the owning editor was destroyed and therefore we need to reset the EditMode active + if (m_ActiveTool is EditModeTool && toolOwner.GetInstanceID() != UnityEditorInternal.EditMode.ownerID) + UnityEditorInternal.EditMode.ChangeEditModeFromToolContext(toolOwner, ((EditModeTool)m_ActiveTool).editMode); + + customEditorToolInstance = m_ActiveTool; } else { - var toolInstance = (EditorTool)CreateInstance(toolType, x => { ((EditorTool)x).m_Targets = toolInfo; }); - toolInstance.hideFlags = HideFlags.DontSave; - m_CustomEditorTools.Add(toolInstance); + customEditorToolInstance = (EditorTool)CreateInstance(toolType, x => + { + ((EditorTool)x).m_Targets = toolOwner.targets; + ((EditorTool)x).m_Target = toolOwner.target; + }); + + customEditorToolInstance.hideFlags = HideFlags.DontSave; } + + list.Add(customEditorToolInstance); + + var editModeTool = customEditorToolInstance as EditModeTool; + + if (editModeTool != null) + editModeTool.owner = toolOwner; } - if (isCustomEditorTool && !m_CustomEditorTools.Contains(m_ActiveTool)) + return preservedActiveTool; + } + + static bool CustomEditorToolIsMatch(Editor editor, Type toolType, EditorTool tool) + { + if (editor == null || toolType != tool.GetType()) + return false; + + // if it's an EditModeTool we need to be stricter about ownership for backwards compatibility. + var editModeTool = tool as EditModeTool; + + if (editModeTool != null) + return editModeTool.owner == (IToolModeOwner)editor || editModeTool.target == editor.target; + + // otherwise just check if it's a valid type + return true; + } + + internal static EditorTool GetCustomEditorToolOfType(Type type, bool searchLockedInspectors = true) + { + foreach (var customEditorTool in instance.m_CustomEditorTools) + if (customEditorTool != null && customEditorTool.GetType() == type) + return customEditorTool; + + if (searchLockedInspectors) { - m_PreviousCustomEditorToolContext = new CustomEditorToolContext(m_ActiveTool); - DestroyImmediate(m_ActiveTool); - RestorePreviousTool(); + foreach (var customEditorTool in instance.m_LockedCustomEditorTools) + if (customEditorTool != null && customEditorTool.GetType() == type) + return customEditorTool; } + + return null; } - internal static EditorTool GetCustomEditorToolOfType(Type type) + internal static EditorTool GetCustomEditorToolsForType(Type targetType, List list, bool searchLockedInspectors) { - foreach (var tool in instance.m_CustomEditorTools) - if (tool != null && tool.GetType() == type) - return tool; + foreach (var customEditorTool in instance.m_CustomEditorTools) + if (customEditorTool != null && + EditorToolUtility.GetCustomEditorToolTargetType(customEditorTool) == targetType) + list.Add(customEditorTool); + + if (searchLockedInspectors) + { + foreach (var customEditorTool in instance.m_LockedCustomEditorTools) + if (customEditorTool != null && EditorToolUtility.GetCustomEditorToolTargetType(customEditorTool) == targetType) + list.Add(customEditorTool); + } + return null; } - internal static void GetCustomEditorTools(List list) + internal static void GetCustomEditorTools(List list, bool includeLockedInspectorTools) { list.Clear(); foreach (var customEditorTool in instance.m_CustomEditorTools) list.Add(customEditorTool); + + if (includeLockedInspectorTools) + { + foreach (var customEditorTool in instance.m_LockedCustomEditorTools) + list.Add(customEditorTool); + } } - internal static void GetCustomEditorTools(Type type, List list) + internal static void GetCustomEditorToolsForTarget(UnityObject target, List list, bool searchLockedInspectors) { - if (type == null) + list.Clear(); + + if (target == null) return; - list.Clear(); + foreach (var tool in instance.m_CustomEditorTools) + { + if (tool.target == target) + list.Add(tool); + } - foreach (var customEditorTool in instance.m_CustomEditorTools) + if (searchLockedInspectors) { - if (EditorToolUtility.GetCustomEditorToolTargetType(customEditorTool) == type) - list.Add(customEditorTool); + foreach (var tool in instance.m_LockedCustomEditorTools) + { + if (tool.target == target) + list.Add(tool); + } } } + internal static EditorTool GetCustomEditorTool(Func predicate, bool searchLockedInspectors) + { + foreach (var tool in instance.m_CustomEditorTools) + if (predicate(tool)) + return tool; + + if (searchLockedInspectors) + foreach (var tool in instance.m_LockedCustomEditorTools) + if (predicate(tool)) + return tool; + + return null; + } + [EditorBrowsable(EditorBrowsableState.Never)] internal static ScriptableObject CreateInstance(Type type, Action initialize) { diff --git a/Editor/Mono/GUI/Tools/EditorToolGUI.cs b/Editor/Mono/GUI/Tools/EditorToolGUI.cs index edf91ed1c4..92b4363f6d 100644 --- a/Editor/Mono/GUI/Tools/EditorToolGUI.cs +++ b/Editor/Mono/GUI/Tools/EditorToolGUI.cs @@ -23,9 +23,7 @@ public static void EditorToolbarForTarget(UObject target) if (target == null) throw new ArgumentNullException("target"); - var targetType = target.GetType(); - s_CustomEditorTools.Clear(); - EditorToolContext.GetCustomEditorTools(targetType, s_CustomEditorTools); + EditorToolContext.GetCustomEditorToolsForTarget(target, s_CustomEditorTools, true); EditorToolbar(s_CustomEditorTools); } @@ -75,13 +73,15 @@ public static void EditorToolbar(IList tools) where T : EditorTool static class EditorToolGUI { + const int k_MaxToolHistory = 6; + static class Styles { public static GUIContent selectionToolsWindowTitle = EditorGUIUtility.TrTextContent("Tools"); public static GUIContent recentTools = EditorGUIUtility.TrTextContent("Recent"); public static GUIContent selectionTools = EditorGUIUtility.TrTextContent("Selection"); public static GUIContent availableTools = EditorGUIUtility.TrTextContent("Available"); - public static GUIContent noToolsAvailable = EditorGUIUtility.TrTextContent("No tools for selected components."); + public static GUIContent noToolsAvailable = EditorGUIUtility.TrTextContent("No custom tools available"); } [EditorBrowsable(EditorBrowsableState.Never)] @@ -158,24 +158,30 @@ internal static void DoBuiltinToolSettings(Rect rect) public static void DrawSceneViewTools(SceneView sceneView) { - SceneViewOverlay.Window(Styles.selectionToolsWindowTitle, DoContextualToolbarOverlay, int.MaxValue, - SceneViewOverlay.WindowDisplayOption.OneWindowPerTitle); + SceneViewOverlay.Window(Styles.selectionToolsWindowTitle, DoContextualToolbarOverlay, int.MaxValue, null, + SceneViewOverlay.WindowDisplayOption.MultipleWindowsPerTarget, sceneView); } static void DoContextualToolbarOverlay(UnityEngine.Object target, SceneView sceneView) { GUILayout.BeginHorizontal(GUIStyle.none, GUILayout.MinWidth(210), GUILayout.Height(30)); - s_EditorToolModes.Clear(); - EditorToolContext.GetCustomEditorTools(s_EditorToolModes); + EditorToolContext.GetCustomEditorTools(s_EditorToolModes, false); if (s_EditorToolModes.Count > 0) { EditorGUI.BeginChangeCheck(); + EditorGUILayout.EditorToolbar(s_EditorToolModes); + if (EditorGUI.EndChangeCheck()) - foreach (var editor in sceneView.GetActiveEditors()) - editor.Repaint(); + { + foreach (var inspector in InspectorWindow.GetInspectors()) + { + foreach (var editor in inspector.tracker.activeEditors) + editor.Repaint(); + } + } } else { @@ -187,42 +193,49 @@ static void DoContextualToolbarOverlay(UnityEngine.Object target, SceneView scen GUILayout.EndHorizontal(); } - internal static void DoToolHistoryContextMenu() + internal static void DoToolContextMenu() { var toolHistoryMenu = new GenericMenu() { allowDuplicateNames = true }; + var foundTool = false; + s_ToolList.Clear(); + EditorToolContext.GetToolHistory(s_ToolList, true); // recent history - if (EditorToolContext.GetLastTool() != null) + if (EditorToolContext.GetLastCustomTool() != null) { + foundTool = true; toolHistoryMenu.AddDisabledItem(Styles.recentTools); - for (var i = 0; i < s_ToolList.Count; i++) + for (var i = 0; i < Math.Min(k_MaxToolHistory, s_ToolList.Count); i++) { var tool = s_ToolList[i]; if (EditorToolUtility.IsCustomEditorTool(tool.GetType())) continue; - toolHistoryMenu.AddItem( - new GUIContent(EditorToolUtility.GetToolName(tool)), - false, - () => { EditorToolContext.activeTool = tool; }); + if (tool.IsAvailable()) + toolHistoryMenu.AddItem( + new GUIContent(EditorToolUtility.GetToolName(tool)), + false, + () => { EditorToolContext.activeTool = tool; }); + else + toolHistoryMenu.AddDisabledItem(new GUIContent(EditorToolUtility.GetToolName(tool))); } toolHistoryMenu.AddSeparator(""); } - s_ToolList.Clear(); - EditorToolContext.GetCustomEditorTools(s_ToolList); + EditorToolContext.GetCustomEditorTools(s_ToolList, false); if (s_ToolList.Any()) { + foundTool = true; toolHistoryMenu.AddDisabledItem(Styles.selectionTools); for (var i = 0; i < s_ToolList.Count; i++) @@ -232,23 +245,37 @@ internal static void DoToolHistoryContextMenu() if (!EditorToolUtility.IsCustomEditorTool(tool.GetType())) continue; - toolHistoryMenu.AddItem( - new GUIContent(EditorToolUtility.GetToolName(tool)), - false, - () => { EditorToolContext.activeTool = tool; }); + if (tool.IsAvailable()) + toolHistoryMenu.AddItem( + new GUIContent(EditorToolUtility.GetToolName(tool)), + false, + () => { EditorToolContext.activeTool = tool; }); + else + toolHistoryMenu.AddDisabledItem(new GUIContent(EditorToolUtility.GetToolName(tool))); } toolHistoryMenu.AddSeparator(""); } - toolHistoryMenu.AddDisabledItem(Styles.availableTools); + var global = EditorToolUtility.GetCustomEditorToolsForType(null); + + if (global.Any()) + { + foundTool = true; + toolHistoryMenu.AddDisabledItem(Styles.availableTools); + + foreach (var toolType in global) + { + toolHistoryMenu.AddItem( + new GUIContent(EditorToolUtility.GetToolName(toolType)), + false, + () => { EditorTools.EditorTools.SetActiveTool(toolType); }); + } + } - foreach (var toolType in EditorToolUtility.GetCustomEditorToolsForType(null)) + if (!foundTool) { - toolHistoryMenu.AddItem( - new GUIContent(EditorToolUtility.GetToolName(toolType)), - false, - () => { EditorTools.EditorTools.SetActiveTool(toolType); }); + toolHistoryMenu.AddDisabledItem(Styles.noToolsAvailable); } toolHistoryMenu.ShowAsContext(); diff --git a/Editor/Mono/GUI/Tools/EditorToolUtility.cs b/Editor/Mono/GUI/Tools/EditorToolUtility.cs index b5138be6ff..33e72ce19a 100644 --- a/Editor/Mono/GUI/Tools/EditorToolUtility.cs +++ b/Editor/Mono/GUI/Tools/EditorToolUtility.cs @@ -5,11 +5,25 @@ using System; using System.Collections.Generic; using System.Linq; -using UnityEngine; using UObject = UnityEngine.Object; namespace UnityEditor.EditorTools { + /// + /// An Editor instance and EditorTool type. + /// + struct CustomEditorTool + { + public Editor owner; + public Type editorToolType; + + public CustomEditorTool(Editor owner, Type tool) + { + this.owner = owner; + this.editorToolType = tool; + } + } + static class EditorToolUtility { struct CustomEditorToolAssociation @@ -123,33 +137,27 @@ internal static Type GetCustomEditorToolTargetType(EditorTool tool) return attr.targetType; } - internal static Dictionary> FindActiveCustomEditorTools() + internal static void GetEditorToolsForTracker(ActiveEditorTracker tracker, List tools) { - var selection = Selection.transforms; - var tools = new Dictionary>(); + tools.Clear(); + + var editors = tracker.activeEditors; - for (int i = 0, c = selection.Length; i < c; i++) + for (int i = 0, c = editors.Length; i < c; i++) { - foreach (var component in selection[i].GetComponents()) - { - if (component != null) - { - var eligibleToolTypes = GetCustomEditorToolsForType(component.GetType()); + var editor = editors[i]; - foreach (var type in eligibleToolTypes) - { - List targets; + if (editor == null || editor.target == null) + continue; - if (tools.TryGetValue(type, out targets)) - tools[type].Add(component); - else - tools.Add(type, new List() { component }); - } - } + var targetType = editor.target.GetType(); + var eligibleToolTypes = GetCustomEditorToolsForType(targetType); + + foreach (var type in eligibleToolTypes) + { + tools.Add(new CustomEditorTool(editor, type)); } } - - return tools; } internal static EditorTool GetEditorToolWithEnum(Tool type) diff --git a/Editor/Mono/GUI/Tools/EditorToolWindow.cs b/Editor/Mono/GUI/Tools/EditorToolWindow.cs index 53be3ccafb..1ef46e6bf3 100644 --- a/Editor/Mono/GUI/Tools/EditorToolWindow.cs +++ b/Editor/Mono/GUI/Tools/EditorToolWindow.cs @@ -57,23 +57,26 @@ static void ShowEditorToolWindow() void OnEnable() { - EditorToolContext.toolChanged += ToolChanged; - ToolChanged(null, EditorToolContext.GetActiveTool()); + EditorTools.activeToolChanged += ToolChanged; + + ToolChanged(); } void OnDisable() { - EditorToolContext.toolChanged -= ToolChanged; + EditorTools.activeToolChanged -= ToolChanged; + if (m_Editor != null) DestroyImmediate(m_Editor); } - void ToolChanged(EditorTool from, EditorTool to) + void ToolChanged() { if (m_Editor != null) DestroyImmediate(m_Editor); - m_Editor = Editor.CreateEditor(to); - titleContent = new GUIContent(EditorToolUtility.GetToolName(to)); + var activeTool = EditorToolContext.activeTool; + m_Editor = Editor.CreateEditor(activeTool); + titleContent = new GUIContent(EditorToolUtility.GetToolName(activeTool.GetType())); Repaint(); } diff --git a/Editor/Mono/GUI/Tools/EditorTools.cs b/Editor/Mono/GUI/Tools/EditorTools.cs index a35e5ef676..2124110165 100644 --- a/Editor/Mono/GUI/Tools/EditorTools.cs +++ b/Editor/Mono/GUI/Tools/EditorTools.cs @@ -3,26 +3,35 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; -using System.Linq; -using UnityEngine; using UObject = UnityEngine.Object; namespace UnityEditor.EditorTools { - [InitializeOnLoad] public static class EditorTools { - static EditorTools() + public static Type activeToolType { - EditorToolContext.toolChanged += (from, to) => + get { - // Don't expose the tool instance, but do pass along what type of tool it is. - if (activeToolChanged != null) - activeToolChanged(from != null ? from.GetType() : null, to != null ? to.GetType() : null); - }; + var tool = EditorToolContext.activeTool; + return tool != null ? tool.GetType() : null; + } + } + + public static event Action activeToolChanging; + public static event Action activeToolChanged; + + internal static void ActiveToolWillChange() + { + if (activeToolChanging != null) + activeToolChanging(); } - public static event Action activeToolChanged; + internal static void ActiveToolDidChange() + { + if (activeToolChanged != null) + activeToolChanged(); + } public static void SetActiveTool() where T : EditorTool { @@ -60,5 +69,10 @@ public static void RestorePreviousTool() { EditorToolContext.RestorePreviousTool(); } + + public static bool IsActiveTool(EditorTool tool) + { + return EditorToolContext.activeTool == tool; + } } } diff --git a/Editor/Mono/GUI/Tools/Tools.cs b/Editor/Mono/GUI/Tools/Tools.cs index bb7ec69586..2667ddaf56 100644 --- a/Editor/Mono/GUI/Tools/Tools.cs +++ b/Editor/Mono/GUI/Tools/Tools.cs @@ -58,18 +58,22 @@ static Tools get } static Tools s_Get; + +#pragma warning disable 618 + [System.Obsolete("Use EditorTools.activeToolDidChange or EditorTools.activeToolWillChange")] internal delegate void OnToolChangedFunc(Tool from, Tool to); + [System.Obsolete("Use EditorTools.activeToolDidChange or EditorTools.activeToolWillChange")] internal static OnToolChangedFunc onToolChanged; +#pragma warning restore 618 public static Tool current { - get { return get.currentTool; } + get { return EditorToolUtility.GetEnumWithEditorTool(EditorToolContext.GetActiveTool()); } set { EditorToolContext.activeTool = EditorToolUtility.GetEditorToolWithEnum(value); } } internal static void SyncToolEnum() { - get.currentTool = EditorToolUtility.GetEnumWithEditorTool(EditorToolContext.GetActiveTool()); RepaintAllToolViews(); } @@ -130,6 +134,27 @@ internal static bool viewToolActive } } + static Vector3 s_HandlePosition; + static bool s_HandlePositionComputed; + + internal static Vector3 cachedHandlePosition + { + get + { + if (!s_HandlePositionComputed) + { + s_HandlePosition = GetHandlePosition(); + s_HandlePositionComputed = true; + } + return s_HandlePosition; + } + } + + internal static void InvalidateHandlePosition() + { + s_HandlePositionComputed = false; + } + public static Vector3 handlePosition { get @@ -141,7 +166,7 @@ public static Vector3 handlePosition if (s_LockHandlePositionActive) return s_LockHandlePosition; - return GetHandlePosition(); + return cachedHandlePosition; } } @@ -274,6 +299,7 @@ public static PivotMode pivotMode { get.m_PivotMode = value; EditorPrefs.SetInt("PivotMode", (int)pivotMode); + InvalidateHandlePosition(); } } } @@ -386,16 +412,22 @@ private void OnEnable() pivotRotation = (PivotRotation)EditorPrefs.GetInt("PivotRotation", 0); visibleLayers = EditorPrefs.GetInt("VisibleLayers", -1); lockedLayers = EditorPrefs.GetInt("LockedLayers", 0); - EditorToolContext.toolChanged += (from, to) => + + EditorToolContext.activeToolChanged += (previous, active) => { +#pragma warning disable 618 if (onToolChanged != null) - onToolChanged(EditorToolUtility.GetEnumWithEditorTool(from), EditorToolUtility.GetEnumWithEditorTool(to)); + onToolChanged( + EditorToolUtility.GetEnumWithEditorTool(previous), + EditorToolUtility.GetEnumWithEditorTool(active)); +#pragma warning restore 618 }; } internal static void OnSelectionChange() { ResetGlobalHandleRotation(); + InvalidateHandlePosition(); localHandleOffset = Vector3.zero; } @@ -405,7 +437,6 @@ internal static void ResetGlobalHandleRotation() } internal Quaternion m_GlobalHandleRotation = Quaternion.identity; - Tool currentTool = Tool.Move; ViewTool m_ViewTool = ViewTool.Pan; static void SetToolMode(Tool toolMode) diff --git a/Editor/Mono/GUI/TreeView/AssetOrGameObjectTreeViewDragging.cs b/Editor/Mono/GUI/TreeView/AssetOrGameObjectTreeViewDragging.cs index df4dcb408d..a30cb88c61 100644 --- a/Editor/Mono/GUI/TreeView/AssetOrGameObjectTreeViewDragging.cs +++ b/Editor/Mono/GUI/TreeView/AssetOrGameObjectTreeViewDragging.cs @@ -112,7 +112,7 @@ public override void StartDrag(TreeViewItem draggedItem, List draggedItemID draggedItemIDs = m_TreeView.SortIDsInVisiblityOrder(draggedItemIDs); if (!draggedItemIDs.Contains(draggedItem.id)) - draggedItemIDs = new List {draggedItem.id}; + draggedItemIDs = new List { draggedItem.id }; Object[] draggedObjReferences = ProjectWindowUtil.GetDragAndDropObjects(draggedItem.id, draggedItemIDs); DragAndDrop.objectReferences = draggedObjReferences; @@ -160,20 +160,22 @@ public override void StartDrag(TreeViewItem draggedItem, List draggedItemID public override DragAndDropVisualMode DoDrag(TreeViewItem parentItem, TreeViewItem targetItem, bool perform, DropPosition dropPos) { + var hierarchyTargetItem = targetItem as GameObjectTreeViewItem; + // Allow client to handle drag if (m_CustomDragHandling != null) { - DragAndDropVisualMode dragResult = m_CustomDragHandling(parentItem as GameObjectTreeViewItem, targetItem as GameObjectTreeViewItem, dropPos, perform); + DragAndDropVisualMode dragResult = m_CustomDragHandling(parentItem as GameObjectTreeViewItem, hierarchyTargetItem, dropPos, perform); if (dragResult != DragAndDropVisualMode.None) return dragResult; } // Scene dragging logic - DragAndDropVisualMode dragSceneResult = DoDragScenes(parentItem as GameObjectTreeViewItem, targetItem as GameObjectTreeViewItem, perform, dropPos); + DragAndDropVisualMode dragSceneResult = DoDragScenes(parentItem as GameObjectTreeViewItem, hierarchyTargetItem, perform, dropPos); if (dragSceneResult != DragAndDropVisualMode.None) return dragSceneResult; - if (targetItem != null && !IsDropTargetUserModifiable(targetItem as GameObjectTreeViewItem, dropPos)) + if (targetItem != null && !IsDropTargetUserModifiable(hierarchyTargetItem, dropPos)) return DragAndDropVisualMode.Rejected; var option = InternalEditorUtility.HierarchyDropMode.kHierarchyDragNormal; @@ -194,23 +196,11 @@ public override DragAndDropVisualMode DoDrag(TreeViewItem parentItem, TreeViewIt // Simulate drag upon the last loaded scene in the hierarchy (adds as last root sibling of the last scene) Scene lastScene = dataSource.GetLastScene(); option |= InternalEditorUtility.HierarchyDropMode.kHierarchyDropUpon; - - var prop = dataSource.CreateHierarchyProperty(); - if (prop.Find(lastScene.handle, null)) - { - return InternalEditorUtility.HierarchyWindowDrag(prop, option, null, perform); - } - - Assert.IsFalse(true, "Could not find scene with handle: " + lastScene.handle); + return InternalEditorUtility.HierarchyWindowDragByID(lastScene.handle, option, null, perform); } } // Here we are hovering over items - var hierarchyProperty = dataSource.CreateHierarchyProperty(); - if (!hierarchyProperty.Find(targetItem.id, null)) - { - hierarchyProperty = null; - } var draggingUpon = dropPos == TreeViewDragging.DropPosition.Upon; @@ -221,7 +211,7 @@ public override DragAndDropVisualMode DoDrag(TreeViewItem parentItem, TreeViewIt if (draggingUpon) { - option |= InternalEditorUtility.HierarchyDropMode.kHierarchyDropUpon; + option |= InternalEditorUtility.HierarchyDropMode.kHierarchyDropUpon; } else { @@ -241,7 +231,102 @@ public override DragAndDropVisualMode DoDrag(TreeViewItem parentItem, TreeViewIt option |= InternalEditorUtility.HierarchyDropMode.kHierarchyDropAfterParent; } - return InternalEditorUtility.HierarchyWindowDrag(hierarchyProperty, option, null, perform); + int gameObjectOrSceneInstanceID = GetDropTargetInstanceID(hierarchyTargetItem, dropPos); + if (gameObjectOrSceneInstanceID == 0) + return DragAndDropVisualMode.Rejected; + + if (perform && SubSceneGUI.IsUsingSubScenes() && !IsValidSubSceneDropTarget(gameObjectOrSceneInstanceID, dropPos, DragAndDrop.objectReferences)) + return DragAndDropVisualMode.Rejected; + + return InternalEditorUtility.HierarchyWindowDragByID(gameObjectOrSceneInstanceID, option, null, perform); + } + + int GetDropTargetInstanceID(GameObjectTreeViewItem hierarchyTargetItem, DropPosition dropPosition) + { + if (SubSceneGUI.IsUsingSubScenes()) + { + var gameObjectDropTarget = hierarchyTargetItem.objectPPTR as GameObject; + if (gameObjectDropTarget != null) + { + if (dropPosition == DropPosition.Above) + return hierarchyTargetItem.id; + if (SubSceneGUI.IsSubSceneHeader(gameObjectDropTarget)) + { + Scene subScene = SubSceneGUI.GetSubScene(gameObjectDropTarget); + if (subScene.IsValid()) + return subScene.handle; + else + return 0; + } + } + } + return hierarchyTargetItem.id; + } + + bool IsValidSubSceneDropTarget(int dropTargetGameObjectOrSceneInstanceID, DropPosition dropPosition, Object[] draggedObjects) + { + if (draggedObjects == null || draggedObjects.Length == 0) + return false; + + Transform parentForDrop = GetTransformParentForDrop(dropTargetGameObjectOrSceneInstanceID, dropPosition); + if (parentForDrop == null) + { + // Drop is on a root scene which is always allowed + return true; + } + + foreach (var obj in draggedObjects) + { + var gameObject = obj as GameObject; + if (gameObject == null) + continue; + + // Require all dragged objects to be valid (since native cannot filter out invalid sub scene drags currently) + if (SubSceneGUI.IsChildOrSameAsOtherTransform(parentForDrop, gameObject.transform)) + return false; + } + + // Valid drop target for current dragged objects + return true; + } + + Transform GetTransformParentForDrop(int gameObjectOrSceneInstanceID, DropPosition dropPosition) + { + var obj = EditorUtility.InstanceIDToObject(gameObjectOrSceneInstanceID); + if (obj != null) + { + // Find transform parent from GameObject + var go = obj as GameObject; + if (go == null) + throw new InvalidOperationException("Unexpected UnityEngine.Object type in Hierarchy " + obj.GetType()); + + switch (dropPosition) + { + case DropPosition.Upon: + return go.transform; + + case DropPosition.Below: + case DropPosition.Above: + if (go.transform.parent == null) + { + var subSceneInfo = SubSceneGUI.GetSubSceneInfo(go.scene); + if (subSceneInfo.isValid) + return subSceneInfo.transform; + } + return go.transform.parent; + default: + throw new InvalidOperationException("Unhandled enum " + dropPosition); + } + } + else + { + // Find transform parent from Scene + var scene = EditorSceneManager.GetSceneByHandle(gameObjectOrSceneInstanceID); + var subSceneInfo = SubSceneGUI.GetSubSceneInfo(scene); + if (subSceneInfo.isValid) + return subSceneInfo.transform; + return null; // root scene has no transform parent + } } static bool IsDropTargetUserModifiable(GameObjectTreeViewItem targetItem, DropPosition dropPos) @@ -324,12 +409,20 @@ private DragAndDropVisualMode DoDragScenes(GameObjectTreeViewItem parentItem, Ga if (insertNewScenes) { List insertedScenes = new List(); - foreach (var sceneAsset in DragAndDrop.objectReferences) + foreach (var sceneAssetObj in DragAndDrop.objectReferences) { - string scenePath = AssetDatabase.GetAssetPath(sceneAsset); + SceneAsset sceneAsset = sceneAssetObj as SceneAsset; + string scenePath = AssetDatabase.GetAssetPath(sceneAssetObj); Scene scene = SceneManager.GetSceneByPath(scenePath); if (SceneHierarchy.IsSceneHeaderInHierarchyWindow(scene)) + { m_TreeView.Frame(scene.handle, true, true); + } + else if (SubSceneGUI.IsUsingSubScenes() && SubSceneGUI.GetSubSceneInfo(sceneAsset).isValid) + { + var subSceneInfo = SubSceneGUI.GetSubSceneInfo(sceneAsset); + m_TreeView.Frame(subSceneInfo.transform.gameObject.GetInstanceID(), true, true); + } else { bool unloaded = Event.current.alt; diff --git a/Editor/Mono/GUI/TreeView/GameObjectTreeViewDataSource.cs b/Editor/Mono/GUI/TreeView/GameObjectTreeViewDataSource.cs index 340195d3bd..062f2f8f49 100644 --- a/Editor/Mono/GUI/TreeView/GameObjectTreeViewDataSource.cs +++ b/Editor/Mono/GUI/TreeView/GameObjectTreeViewDataSource.cs @@ -36,7 +36,7 @@ internal class GameObjectTreeViewDataSource : LazyTreeViewDataSource int m_RowCount; List m_ListOfRows; // We need the generic List type in this class for Add/RemoveRange and Sorting (m_Rows is IList) List m_StickySceneHeaderItems = new List(); - + internal event System.Action beforeReloading; public HierarchySorting sortingState = new TransformSorting(); public List sceneHeaderItems { get { return m_StickySceneHeaderItems; } } @@ -202,6 +202,9 @@ internal HierarchyProperty CreateHierarchyProperty() HierarchyProperty property = new HierarchyProperty(k_HierarchyType); property.alphaSorted = IsUsingAlphaSort(); property.showSceneHeaders = PrefabStageUtility.GetCurrentPrefabStage() == null; + if (SceneHierarchyHooks.provideSubScenes != null) + property.SetSubScenes(SceneHierarchyHooks.provideSubScenes()); + if (AreScenesValid(scenes)) property.SetCustomScenes(scenes); return property; @@ -231,6 +234,8 @@ void ClearSearchFilter() public override void FetchData() { + beforeReloading?.Invoke(); + Profiler.BeginSample("SceneHierarchyWindow.FetchData"); m_RowsPartiallyInitialized = false; double fetchStartTime = EditorApplication.timeSinceStartup; @@ -349,7 +354,7 @@ private void InitializeMinimal() property.Reset(); if (SceneHierarchy.s_Debug) - Log("Init minimal (" + m_RowCount + ")"); + Log("Init minimal (" + m_RowCount + ") num scenes " + SceneManager.sceneCount); int firstRow, lastRow; m_TreeView.gui.GetFirstAndLastRowVisible(out firstRow, out lastRow); @@ -525,7 +530,6 @@ private void InitTreeViewItem(GameObjectTreeViewItem item, int itemID, Scene sce item.colorCode = colorCode; item.objectPPTR = pptrObject; - item.shouldDisplay = true; item.isSceneHeader = isSceneHeader; item.scene = scene; @@ -586,18 +590,70 @@ static void Log(string text) Debug.Log(text); } + static int FindTransformDepth(Transform transform) + { + var trans = transform.parent; + int depth = 0; + while (trans != null) + { + depth++; + trans = trans.parent; + } + return depth; + } + + override public bool IsRenamingItemAllowed(TreeViewItem item) + { + GameObjectTreeViewItem goItem = item as GameObjectTreeViewItem; + if (goItem.isSceneHeader) + return false; + + if (SubSceneGUI.IsUsingSubScenes() && SubSceneGUI.IsSubSceneHeader((GameObject)goItem.objectPPTR)) + return false; + + return true; + } + void CreateSceneHeaderItems() { m_StickySceneHeaderItems.Clear(); + int numScenesInHierarchy = EditorSceneManager.sceneCount; - for (int i = 0; i < numScenesInHierarchy; ++i) - { - Scene scene = SceneManager.GetSceneAt(i); - var item = new GameObjectTreeViewItem(0, 0, null, null); - InitTreeViewItem(item, scene.handle, scene, true, 0, null, false, 0); + if (SubSceneGUI.IsUsingSubScenes()) + { + for (int i = 0; i < numScenesInHierarchy; ++i) + { + Scene scene = SceneManager.GetSceneAt(i); + + var subSceneInfo = SubSceneGUI.GetSubSceneInfo(scene); + if (subSceneInfo.isValid) + { + var item = new GameObjectTreeViewItem(0, 0, null, null); + var transform = subSceneInfo.transform; + GameObject gameObject = transform.gameObject; + int depth = SubSceneGUI.CalculateHierarchyDepthOfSubScene(subSceneInfo); + InitTreeViewItem(item, gameObject.GetInstanceID(), subSceneInfo.scene, false, 0, gameObject, false, depth); + m_StickySceneHeaderItems.Add(item); + } + else + { + var item = new GameObjectTreeViewItem(0, 0, null, null); + InitTreeViewItem(item, scene.handle, scene, true, 0, null, false, 0); + m_StickySceneHeaderItems.Add(item); + } + } + } + else + { + for (int i = 0; i < numScenesInHierarchy; ++i) + { + Scene scene = SceneManager.GetSceneAt(i); - m_StickySceneHeaderItems.Add(item); + var item = new GameObjectTreeViewItem(0, 0, null, null); + InitTreeViewItem(item, scene.handle, scene, true, 0, null, false, 0); + m_StickySceneHeaderItems.Add(item); + } } } @@ -606,12 +662,12 @@ public Scene GetLastScene() if (scenes != null) { for (int i = scenes.Length - 1; i >= 0; i--) - if (scenes[i].isLoaded) + if (scenes[i].isLoaded && !scenes[i].isSubScene) return scenes[i]; } for (int i = SceneManager.sceneCount - 1; i >= 0; i--) - if (SceneManager.GetSceneAt(i).isLoaded) + if (SceneManager.GetSceneAt(i).isLoaded && !SceneManager.GetSceneAt(i).isSubScene) return SceneManager.GetSceneAt(i); Assert.IsTrue(false, "No loaded scene could be found"); diff --git a/Editor/Mono/GUI/TreeView/GameObjectTreeViewGUI.cs b/Editor/Mono/GUI/TreeView/GameObjectTreeViewGUI.cs index be17bf8596..617202bac0 100644 --- a/Editor/Mono/GUI/TreeView/GameObjectTreeViewGUI.cs +++ b/Editor/Mono/GUI/TreeView/GameObjectTreeViewGUI.cs @@ -10,6 +10,7 @@ using UnityEditor.IMGUI.Controls; using UnityEditor.SceneManagement; using UnityEngine; +using UnityEngine.Assertions.Comparers; using UnityEngine.SceneManagement; using Object = UnityEngine.Object; @@ -53,19 +54,30 @@ internal static class GameObjectStyles internal delegate void OnHeaderGUIDelegate(Rect availableRect, string scenePath); internal static OnHeaderGUIDelegate OnPostHeaderGUI = null; + GameObjectTreeViewDataSource dataSource + { + get { return (GameObjectTreeViewDataSource)m_TreeView.data; } + } + + bool showingSearchResults + { + get { return !string.IsNullOrEmpty(dataSource.searchString); } + } + public GameObjectTreeViewGUI(TreeViewController treeView, bool useHorizontalScroll) : base(treeView, useHorizontalScroll) { k_TopRowMargin = 0f; - k_BaseIndent += SceneVisibilityHierarchyGUI.utilityBarWidth; m_TreeView.enableItemHovering = true; } public override void OnInitialize() { SceneVisibilityManager.hiddenContentChanged += SceneVisibilityManagerOnHiddenContentChanged; + dataSource.beforeReloading += SubSceneGUI.FetchSubSceneInfo; m_PrevScollPos = m_TreeView.state.scrollPos.y; m_PrevTotalHeight = m_TreeView.GetTotalRect().height; + k_BaseIndent = SceneVisibilityHierarchyGUI.utilityBarWidth; } private void SceneVisibilityManagerOnHiddenContentChanged() @@ -142,7 +154,7 @@ void DoStickySceneHeaders() if (!isFirstItemLastInScene) rect.y = scrollY; - var sceneHeaderItem = ((GameObjectTreeViewDataSource)m_TreeView.data).sceneHeaderItems.FirstOrDefault(p => p.scene == firstItem.scene); + var sceneHeaderItem = dataSource.sceneHeaderItems.FirstOrDefault(p => p.scene == firstItem.scene); if (sceneHeaderItem != null) { bool selected = m_TreeView.IsItemDragSelectedOrSelected(sceneHeaderItem); @@ -189,8 +201,7 @@ public override void BeginRowGUI() { if (DetectUserInput()) { - var data = (GameObjectTreeViewDataSource)m_TreeView.data; - data.EnsureFullyInitialized(); + dataSource.EnsureFullyInitialized(); } base.BeginRowGUI(); @@ -242,8 +253,8 @@ override public bool BeginRename(TreeViewItem item, float delay) if (goItem.isSceneHeader) return false; - Object target = goItem.objectPPTR; - if ((target.hideFlags & HideFlags.NotEditable) != 0) + GameObject gameObject = (GameObject)goItem.objectPPTR; + if ((gameObject.hideFlags & HideFlags.NotEditable) != 0) { Debug.LogWarning("Unable to rename a GameObject with HideFlags.NotEditable."); return false; @@ -272,12 +283,39 @@ override protected void RenameEnded() } } + private bool isDragging + { + get + { + return m_TreeView.isDragging || + (m_TreeView.dragging != null && m_TreeView.dragging.GetDropTargetControlID() != -1); + } + } + override protected void DrawItemBackground(Rect rect, int row, TreeViewItem item, bool selected, bool focused) { - base.DrawItemBackground(rect, row, item, selected, focused); + var goItem = (GameObjectTreeViewItem)item; + if (goItem.isSceneHeader) + { + GUI.Label(rect, GUIContent.none, GameObjectStyles.sceneHeaderBg); + } + else + { + // Don't show indented sub scene header backgrounds when searching (as the texts are not indented here) + if (SubSceneGUI.IsUsingSubScenes() && !showingSearchResults) + { + var gameObject = (GameObject)goItem.objectPPTR; + if (gameObject != null && SubSceneGUI.IsSubSceneHeader(gameObject)) + SubSceneGUI.DrawSubSceneHeaderBackground(rect, gameObject); + } + } + if (m_TreeView.hoveredItem != item) return; + if (isDragging) + return; + using (new GUI.BackgroundColorScope(GameObjectStyles.hoveredBackgroundColor)) { GUI.Label(rect, GUIContent.none, GameObjectStyles.hoveredItemBackgroundStyle); @@ -292,38 +330,45 @@ override protected void DoItemGUI(Rect rect, int row, TreeViewItem item, bool se EnsureLazyInitialization(goItem); - // Scene header background (make it slightly transparent to hint it - // is not the normal scene header) if (goItem.isSceneHeader) { - Color oldColor = GUI.color; - GUI.color = GUI.color * new Color(1, 1, 1, 0.9f); - GUI.Label(rect, GUIContent.none, GameObjectStyles.sceneHeaderBg); - GUI.color = oldColor; - useBoldFont = (goItem.scene == SceneManager.GetActiveScene()) || IsPrefabStageHeader(goItem); } base.DoItemGUI(rect, row, item, selected, focused, useBoldFont); + SceneVisibilityHierarchyGUI.DoItemGUI(rect, goItem, selected && !IsRenaming(item.id), m_TreeView.hoveredItem == goItem, focused, isDragging); if (goItem.isSceneHeader) + { DoAdditionalSceneHeaderGUI(goItem, rect); + } else + { PrefabModeButton(goItem, rect); - - SceneVisibilityHierarchyGUI.DoItemGUI(rect, goItem, selected, m_TreeView.hoveredItem == goItem, focused); + if (SubSceneGUI.IsUsingSubScenes() && !showingSearchResults) + SubSceneGUI.DrawVerticalLine(rect, (GameObject)goItem.objectPPTR); + } if (SceneHierarchy.s_Debug) GUI.Label(new Rect(rect.xMax - 70, rect.y, 70, rect.height), "" + row + " (" + goItem.id + ")", EditorStyles.boldLabel); } + protected override Rect GetDropTargetRect(Rect rect) + { + rect.xMin += SceneVisibilityHierarchyGUI.utilityBarWidth; + + return rect; + } + protected void DoAdditionalSceneHeaderGUI(GameObjectTreeViewItem goItem, Rect rect) { // Options button const float optionsButtonWidth = 16f; const float optionsButtonHeight = 6f; const float margin = 4f; + Rect buttonRect = new Rect(rect.width - optionsButtonWidth - margin, rect.y + (rect.height - optionsButtonHeight) * 0.5f, optionsButtonWidth, rect.height); + if (Event.current.type == EventType.Repaint) GameObjectStyles.optionsButtonStyle.Draw(buttonRect, false, false, false, false); @@ -367,6 +412,7 @@ void EnsureLazyInitialization(GameObjectTreeViewItem item) if (!item.lazyInitializationDone) { item.lazyInitializationDone = true; + SetItemIcon(item); SetItemOverlayIcon(item); SetPrefabModeButtonVisibility(item); @@ -390,7 +436,10 @@ void SetItemIcon(GameObjectTreeViewItem item) } else { - item.icon = PrefabUtility.GetIconForGameObject(go); + if (SubSceneGUI.IsSubSceneHeader(go)) + item.icon = GameObjectStyles.sceneAssetIcon; + else + item.icon = PrefabUtility.GetIconForGameObject(go); } } @@ -476,28 +525,14 @@ protected override void OnContentGUI(Rect rect, int row, TreeViewItem item, stri int colorCode = goItem.colorCode; - if (string.IsNullOrEmpty(item.displayName)) - { - /* - * We refresh data between Editor and Player changes to the hierarchy. But we repaint after both has happened. - * So there is a possibility that the Player deleted a gameobject that is still cached in our DataSource. - * Due to risk mitigation for 4.5 we are working around this here. - * A proper fix should be to make sure we also fetch data after Player changes as well. - * Look into: Application.cpp and look where GetSceneTracker().TickHierarchyWindowHasChanged() is being called. - * Likely the proper fix will be adding another call to TickHierarchyWindowHasChanged after the Player had a chance to run. - */ - if (goItem.objectPPTR != null) - goItem.displayName = goItem.objectPPTR.name; - else - goItem.displayName = "deleted gameobject"; - label = goItem.displayName; - } - GUIStyle lineStyle = Styles.lineStyle; - if (!goItem.shouldDisplay) + if (SubSceneGUI.IsUsingSubScenes()) + useBoldFont = SubSceneGUI.UseBoldFontForGameObject((GameObject)goItem.objectPPTR); + + if (useBoldFont) { - lineStyle = GameObjectStyles.disabledLabel; // TODO: THis need to be a better color then just the disabled. + lineStyle = Styles.lineBoldStyle; } else { diff --git a/Editor/Mono/GUI/TreeView/GameObjectTreeViewItem.cs b/Editor/Mono/GUI/TreeView/GameObjectTreeViewItem.cs index 1f30a3e0fa..8f69ed3543 100644 --- a/Editor/Mono/GUI/TreeView/GameObjectTreeViewItem.cs +++ b/Editor/Mono/GUI/TreeView/GameObjectTreeViewItem.cs @@ -12,7 +12,6 @@ internal class GameObjectTreeViewItem : TreeViewItem { int m_ColorCode; Object m_ObjectPPTR; - bool m_ShouldDisplay; Scene m_UnityScene; // Lazy initialized together with icon. @@ -29,8 +28,19 @@ public override string displayName { get { - if (string.IsNullOrEmpty(base.displayName)) + // Lazy initilize displayName + if (base.displayName == null) { + if (SubSceneGUI.IsUsingSubScenes()) + { + var subSceneHeaderName = SubSceneGUI.GetSubSceneHeaderText((GameObject)objectPPTR); + if (subSceneHeaderName != null) + { + base.displayName = subSceneHeaderName; + return base.displayName; + } + } + if (m_ObjectPPTR != null) displayName = objectPPTR.name; else @@ -43,7 +53,6 @@ public override string displayName virtual public int colorCode { get { return m_ColorCode; } set { m_ColorCode = value; } } virtual public Object objectPPTR { get { return m_ObjectPPTR; } set { m_ObjectPPTR = value; } } - virtual public bool shouldDisplay { get { return m_ShouldDisplay; } set { m_ShouldDisplay = value; } } virtual public bool lazyInitializationDone { get { return m_LazyInitializationDone; } set { m_LazyInitializationDone = value; } } virtual public bool showPrefabModeButton { get { return m_ShowPrefabModeButton; } set { m_ShowPrefabModeButton = value; } } virtual public Texture2D overlayIcon { get { return m_OverlayIcon; } set { m_OverlayIcon = value; } } diff --git a/Editor/Mono/GUI/TreeView/SubSceneGUI.cs b/Editor/Mono/GUI/TreeView/SubSceneGUI.cs new file mode 100644 index 0000000000..ba63fac26b --- /dev/null +++ b/Editor/Mono/GUI/TreeView/SubSceneGUI.cs @@ -0,0 +1,334 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.SceneManagement; + +static class SubSceneGUI +{ + static Dictionary m_SubSceneHeadersMap = new Dictionary(); + static Dictionary m_SceneToSubSceneMap = new Dictionary(); + static Dictionary m_SceneAssetToSubSceneMap = new Dictionary(); + const int kMaxSubSceneIterations = 100; + + internal static void FetchSubSceneInfo() + { + if (SceneHierarchyHooks.provideSubScenes != null) + { + m_SubSceneHeadersMap = new Dictionary(); + m_SceneToSubSceneMap = new Dictionary(); + m_SceneAssetToSubSceneMap = new Dictionary(); + + var subSceneInfos = SceneHierarchyHooks.provideSubScenes(); + foreach (var subSceneInfo in subSceneInfos) + { + if (subSceneInfo.transform == null) + { + Debug.LogError("Invalid Transform"); + continue; + } + + m_SubSceneHeadersMap[subSceneInfo.transform.gameObject] = subSceneInfo; + + if (subSceneInfo.scene.IsValid()) + m_SceneToSubSceneMap[subSceneInfo.scene] = subSceneInfo; + if (subSceneInfo.sceneAsset) + m_SceneAssetToSubSceneMap[subSceneInfo.sceneAsset] = subSceneInfo; + } + } + } + + internal static bool IsUsingSubScenes() + { + return SceneHierarchyHooks.provideSubScenes != null; + } + + static Transform GetParentCheckSubScenes(Transform transform) + { + if (transform.parent == null) + { + SceneHierarchyHooks.SubSceneInfo subScene; + if (m_SceneToSubSceneMap.TryGetValue(transform.gameObject.scene, out subScene)) + return subScene.transform; + else + return null; // Reached root of a root scene + } + + return transform.parent; + } + + internal static bool IsChildOrSameAsOtherTransform(Transform transform, Transform otherTransform) + { + if (IsUsingSubScenes()) + { + Transform current = transform; + int i = 0; + while (current != null && i++ < kMaxSubSceneIterations) + { + if (current == otherTransform) + return true; + + current = GetParentCheckSubScenes(current); + } + + if (i >= kMaxSubSceneIterations) + Debug.LogError("Recursive SubScene setup detected. Report a bug."); + } + else + { + Transform current = transform; + while (current != null) + { + if (current == otherTransform) + return true; + + current = current.parent; + } + } + return false; + } + + internal static bool IsSubSceneHeader(GameObject gameObject) + { + return IsUsingSubScenes() && m_SubSceneHeadersMap.ContainsKey(gameObject); + } + + internal static bool HandleGameObjectContextMenu(GenericMenu menu, GameObject gameObject) + { + SceneHierarchyHooks.SubSceneInfo subScene; + if (m_SubSceneHeadersMap.TryGetValue(gameObject, out subScene)) + { + Scene scene = subScene.scene; + if (!scene.IsValid()) + return false; // use default GameObject context menu if no Scene has been specified in the SubScene component yet + + if (scene.isLoaded) + { + var content = EditorGUIUtility.TrTextContent("Set Active Scene"); + if (SceneManager.GetActiveScene() != scene) + menu.AddItem(content, false, SetSceneActive, scene); + else + menu.AddDisabledItem(content, true); + menu.AddSeparator(""); + } + + var saveSceneContent = EditorGUIUtility.TrTextContent("Save Scene"); + if (!EditorApplication.isPlaying && subScene.scene.isLoaded) + menu.AddItem(saveSceneContent, false, SaveSubSceneMenuHandler, subScene); + else + menu.AddDisabledItem(saveSceneContent); + + menu.AddSeparator(""); + var selectAssetContent = EditorGUIUtility.TrTextContent("Select Scene Asset"); + if (!string.IsNullOrEmpty(scene.path)) + menu.AddItem(selectAssetContent, false, SelectSceneAsset, subScene); + else + menu.AddDisabledItem(selectAssetContent); + + return true; + } + return false; + } + + static void SetSceneActive(object userData) + { + Scene scene = (Scene)userData; + EditorSceneManager.SetActiveScene(scene); + } + + static void SaveSubSceneMenuHandler(object userData) + { + var subScene = (SceneHierarchyHooks.SubSceneInfo)userData; + if (subScene.scene.isLoaded && subScene.scene.isDirty) + EditorSceneManager.SaveScene(subScene.scene); + } + + static void SelectSceneAsset(object userData) + { + var subScene = (SceneHierarchyHooks.SubSceneInfo)userData; + var sceneAssetObject = AssetDatabase.LoadMainAssetAtPath(subScene.scene.path); + Selection.activeObject = sceneAssetObject; + EditorGUIUtility.PingObject(sceneAssetObject); + } + + internal static string GetSubSceneHeaderText(GameObject gameObject) + { + SceneHierarchyHooks.SubSceneInfo subScene; + if (m_SubSceneHeadersMap.TryGetValue(gameObject, out subScene)) + return subScene.sceneName; + + return null; + } + + internal static bool UseBoldFontForGameObject(GameObject gameObject) + { + SceneHierarchyHooks.SubSceneInfo subScene; + if (m_SubSceneHeadersMap.TryGetValue(gameObject, out subScene)) + { + return subScene.scene == SceneManager.GetActiveScene(); + } + return false; + } + + internal static SceneHierarchyHooks.SubSceneInfo GetSubSceneInfo(Scene scene) + { + SceneHierarchyHooks.SubSceneInfo subScene; + if (m_SceneToSubSceneMap.TryGetValue(scene, out subScene)) + return subScene; + + return default(SceneHierarchyHooks.SubSceneInfo); + } + + internal static SceneHierarchyHooks.SubSceneInfo GetSubSceneInfo(SceneAsset sceneAsset) + { + SceneHierarchyHooks.SubSceneInfo subScene; + if (m_SceneAssetToSubSceneMap.TryGetValue(sceneAsset, out subScene)) + return subScene; + + return default(SceneHierarchyHooks.SubSceneInfo); + } + + internal static Color GetColorForSubScene(Scene scene) + { + SceneHierarchyHooks.SubSceneInfo subScene; + if (m_SceneToSubSceneMap.TryGetValue(scene, out subScene)) + return subScene.color; + + return Color.grey; + } + + internal static Scene GetSubScene(GameObject gameObject) + { + SceneHierarchyHooks.SubSceneInfo subScene; + if (m_SubSceneHeadersMap.TryGetValue(gameObject, out subScene)) + return subScene.scene; + + return default(Scene); + } + + internal static void DrawSubSceneHeaderBackground(Rect rect, GameObject gameObject) + { + float indent = CalcIndentOfSubSceneHeader(gameObject); + if (indent < 0) + { + Debug.LogError("Only call DrawSubSceneHeaderBackground if IsSubSceneHeader() is true"); + return; + } + Rect headerRect = rect; + headerRect.xMin += indent; + + Color oldColor = GUI.color; + GUI.color = GUI.color * new Color(1, 1, 1, 0.9f); // dimmed compared to main scene headers + GUI.Label(headerRect, GUIContent.none, GameObjectTreeViewGUI.GameObjectStyles.sceneHeaderBg); + GUI.color = oldColor; + } + + static float CalcIndentOfSubSceneHeader(GameObject gameObject) + { + SceneHierarchyHooks.SubSceneInfo subSceneInfo; + if (gameObject == null || !m_SubSceneHeadersMap.TryGetValue(gameObject, out subSceneInfo)) + return -1; // Input is not a sub scene GameObject + + int hierarchyDepth = CalculateHierarchyDepthOfSubScene(subSceneInfo); + if (hierarchyDepth > 0) + { + float indentWidth = 14f; + float indent = hierarchyDepth * indentWidth; + return indent; + } + return -1f; + } + + // Temp cache for optimizing vertical line drawing + static SceneHierarchyHooks.SubSceneInfo s_LastSubSceneInfo; + static Rect s_LastRectCalculated; + + internal static Rect GetRectForVerticalLine(Rect rowRect, Scene scene) + { + // Fast path: reuse last rect if same scene + if (s_LastSubSceneInfo.isValid && s_LastSubSceneInfo.scene == scene) + { + s_LastRectCalculated.y = rowRect.y; + return s_LastRectCalculated; + } + + // Reset and calculate new rect + s_LastRectCalculated = new Rect(); + if (!m_SceneToSubSceneMap.TryGetValue(scene, out s_LastSubSceneInfo)) + return new Rect(); + + if (s_LastSubSceneInfo.color.a == 0) + return new Rect(); + + float indent = CalcIndentOfVerticalLine(s_LastSubSceneInfo); + if (indent < 0) + return new Rect(); + + s_LastRectCalculated = rowRect; + s_LastRectCalculated.x += indent; + s_LastRectCalculated.width = 1; + + return s_LastRectCalculated; + } + + internal static void DrawVerticalLine(Rect rowRect, GameObject gameObject) + { + if (gameObject == null) + return; + + if (Event.current.type == EventType.Repaint) + { + Rect lineRect = GetRectForVerticalLine(rowRect, gameObject.scene); + if (lineRect.width > 0f) + EditorGUI.DrawRect(lineRect, GetColorForSubScene(gameObject.scene)); + } + } + + static float CalcIndentOfVerticalLine(SceneHierarchyHooks.SubSceneInfo subSceneInfo) + { + int hierarchyDepth = CalculateHierarchyDepthOfSubScene(subSceneInfo); + if (hierarchyDepth > 0) + { + float indentWidth = 14f; + float indent = hierarchyDepth * indentWidth; + return indent; + } + return -1f; + } + + internal static int CalculateHierarchyDepthOfSubScene(SceneHierarchyHooks.SubSceneInfo subSceneInfo) + { + if (!subSceneInfo.isValid) + return -1; + + int hierarchyDepth = 0; + int i = 0; + while (i++ < kMaxSubSceneIterations) + { + hierarchyDepth += FindTransformDepth(subSceneInfo.transform) + 1; // the +1 is for the SubScene header + if (!m_SceneToSubSceneMap.TryGetValue(subSceneInfo.transform.gameObject.scene, out subSceneInfo)) + break; + } + + if (i >= kMaxSubSceneIterations) + Debug.LogError("Recursive SubScene setup detected. Report a bug."); + + return hierarchyDepth; + } + + static int FindTransformDepth(Transform transform) + { + var trans = transform.parent; + int depth = 0; + while (trans != null) + { + depth++; + trans = trans.parent; + } + return depth; + } +} diff --git a/Editor/Mono/GUI/TreeView/TreeViewController.cs b/Editor/Mono/GUI/TreeView/TreeViewController.cs index 70ce4d2bb3..6794b4dd01 100644 --- a/Editor/Mono/GUI/TreeView/TreeViewController.cs +++ b/Editor/Mono/GUI/TreeView/TreeViewController.cs @@ -153,12 +153,12 @@ public bool isDragging public bool showingVerticalScrollBar { - get { return m_ContentRect.height > m_VisibleRect.height; } + get { return m_VisibleRect.height > 0 && m_ContentRect.height > m_VisibleRect.height; } } public bool showingHorizontalScrollBar { - get { return m_ContentRect.width > m_VisibleRect.width; } + get { return m_VisibleRect.width > 0 && m_ContentRect.width > m_VisibleRect.width; } } public string searchString @@ -527,28 +527,18 @@ public void OnGUI(Rect rect, int keyboardControlID) EndNameEditing(true); } - // Grab keyboard focus if requested or if we have a mousedown in entire rect - if (m_GrabKeyboardFocus || (evt.type == EventType.MouseDown && m_TotalRect.Contains(evt.mousePosition))) + // Grab keyboard focus if requested + if (m_GrabKeyboardFocus) { m_GrabKeyboardFocus = false; GUIUtility.keyboardControl = m_KeyboardControlID; - m_AllowRenameOnMouseUp = true; Repaint(); // Ensure repaint so we can show we have keyboard focus } - bool hasFocus = HasFocus(); - - // Detect got focus (ignore layout event which might get fired infront of mousedown) - if (hasFocus != m_HadFocusLastEvent && evt.type != EventType.Layout) + bool isMouseDownInTotalRect = evt.type == EventType.MouseDown && m_TotalRect.Contains(evt.mousePosition); + if (isMouseDownInTotalRect) { - m_HadFocusLastEvent = hasFocus; - - // We got focus this event - if (hasFocus) - { - if (evt.type == EventType.MouseDown) - m_AllowRenameOnMouseUp = false; // If we got focus by mouse down then we do not want to begin renaming if clicking on an already selected item - } + m_AllowRenameOnMouseUp = true; // reset value (can be changed later in this event if the TreeView gets focus) } // Might change expanded state so call before InitIfNeeded (delayed collapse until animation is done) @@ -605,7 +595,7 @@ public void OnGUI(Rect rect, int keyboardControlID) int numVisibleRows = lastRow - firstRow + 1; float rowWidth = Mathf.Max(GUIClip.visibleRect.width, m_ContentRect.width); - IterateVisibleItems(firstRow, numVisibleRows, rowWidth, hasFocus); + IterateVisibleItems(firstRow, numVisibleRows, rowWidth, HasFocus()); } // Call before gui.EndRowGUI() so stuff we render in EndRowGUI does not end up @@ -623,6 +613,9 @@ public void OnGUI(Rect rect, int keyboardControlID) HandleUnusedEvents(); KeyboardGUI(); + // Call after iterating rows since selecting a row takes keyboard focus + HandleTreeViewGotFocus(isMouseDownInTotalRect); + // Prevent controlID inconsistency for the controls following this tree view: We use the hint parameter of GetControlID to // fast forward to a fixed entry in the id list so the following controls always start from there regardless of the rows that have been // culled. @@ -632,6 +625,26 @@ public void OnGUI(Rect rect, int keyboardControlID) hoveredItem = null; } + void HandleTreeViewGotFocus(bool isMouseDownInTotalRect) + { + if (Event.current.type == EventType.Layout) + return; + + // Detect if TreeView got keyboard focus (ignore layout event which gets fired infront of mousedown) + bool hasFocus = HasFocus(); + if (hasFocus != m_HadFocusLastEvent) + { + m_HadFocusLastEvent = hasFocus; + + if (hasFocus && isMouseDownInTotalRect) + { + // If we got focus this event by mouse down then we do not want to begin renaming + // if clicking on an already selected item in the up coming MouseUp event. + m_AllowRenameOnMouseUp = false; + } + } + } + void IterateVisibleItems(int firstRow, int numVisibleRows, float rowWidth, bool hasFocus) { // We stop iterating items if datasource state changes while iterating its items. @@ -830,11 +843,18 @@ void HandleUnusedEvents() break; case EventType.MouseDown: - if (deselectOnUnhandledMouseDown && Event.current.button == 0 && m_TotalRect.Contains(Event.current.mousePosition) && state.selectedIDs.Count > 0) + bool containsMouse = m_TotalRect.Contains(Event.current.mousePosition); + if (containsMouse) + { + GUIUtility.keyboardControl = m_KeyboardControlID; + Repaint(); + } + if (deselectOnUnhandledMouseDown && containsMouse && Event.current.button == 0 && state.selectedIDs.Count > 0) { SetSelection(new int[0], false); NotifyListenersThatSelectionChanged(); } + break; case EventType.ContextClick: if (m_TotalRect.Contains(Event.current.mousePosition)) diff --git a/Editor/Mono/GUI/TreeView/TreeViewGUI.cs b/Editor/Mono/GUI/TreeView/TreeViewGUI.cs index 33e93e3c2e..146638fbe3 100644 --- a/Editor/Mono/GUI/TreeView/TreeViewGUI.cs +++ b/Editor/Mono/GUI/TreeView/TreeViewGUI.cs @@ -256,7 +256,9 @@ virtual protected void DoItemGUI(Rect rect, int row, TreeViewItem item, bool sel // Draw drop marker if (isDropTarget) - Styles.lineStyle.Draw(rect, GUIContent.none, true, true, false, false); + { + Styles.lineStyle.Draw(GetDropTargetRect(rect), GUIContent.none, true, true, false, false); + } // Show insertion marker below this item (rendered end of rows) if (m_TreeView.dragging != null && m_TreeView.dragging.GetRowMarkerControlID() == itemControlID) @@ -278,6 +280,11 @@ virtual protected void DoItemGUI(Rect rect, int row, TreeViewItem item, bool sel EditorGUIUtility.SetIconSize(Vector2.zero); } + protected virtual Rect GetDropTargetRect(Rect rect) + { + return rect; + } + float GetTopPixelOfRow(int row) { return row * k_LineHeight + topRowMargin; @@ -390,6 +397,7 @@ virtual public void BeginPingItem(TreeViewItem item, float topPixelOfRow, float topPixelOfRow, k_IconWidth + k_SpaceBetweenIconAndText + contentSize.x + iconTotalPadding, contentSize.y); + m_Ping.m_AvailableWidth = availableWidth; int row = m_TreeView.data.GetRow(item.id); diff --git a/Editor/Mono/GUI/TypeSelectionList.cs b/Editor/Mono/GUI/TypeSelectionList.cs index a5c560bac4..d02cec9b74 100644 --- a/Editor/Mono/GUI/TypeSelectionList.cs +++ b/Editor/Mono/GUI/TypeSelectionList.cs @@ -23,6 +23,9 @@ public TypeSelectionList(Object[] objects) foreach (Object o in objects) { string typeName = ObjectNames.GetTypeName(o); + if (o is GameObject && EditorUtility.IsPersistent(o)) + typeName = "Prefab"; + if (!types.ContainsKey(typeName)) types[typeName] = new List(); types[typeName].Add(o); @@ -48,7 +51,10 @@ public TypeSelection(string typeName, Object[] objects) System.Diagnostics.Debug.Assert(objects != null && objects.Length >= 1); this.objects = objects; label = new GUIContent(objects.Length + " " + ObjectNames.NicifyVariableName(typeName) + (objects.Length > 1 ? "s" : "")); - label.image = AssetPreview.GetMiniTypeThumbnail(objects[0]); + if (objects[0] is GameObject) + label.image = EditorUtility.IsPersistent(objects[0]) ? PrefabUtility.GameObjectStyles.prefabIcon : PrefabUtility.GameObjectStyles.gameObjectIcon; + else + label.image = AssetPreview.GetMiniTypeThumbnail(objects[0]); } public int CompareTo(object o) diff --git a/Editor/Mono/GUIView.cs b/Editor/Mono/GUIView.cs index 28c06b2b37..a5cff3857a 100644 --- a/Editor/Mono/GUIView.cs +++ b/Editor/Mono/GUIView.cs @@ -11,27 +11,28 @@ using UnityEngine.UIElements.StyleSheets; using UnityEngine.Scripting; -//temporary until everyone is out of experimental -using ExperimentalUI = UnityEngine.Experimental.UIElements; -using EditorExperimentalUI = UnityEditor.Experimental.UIElements; - - namespace UnityEditor { // This is what we (not users) derive from to create various views. (Main Toolbar, etc.) [StructLayout(LayoutKind.Sequential)] internal partial class GUIView : View { + [InitializeOnLoad] + static class EditorShaderLoader + { + static EditorShaderLoader() + { + // TODO: Remove this once case 1148851 has been fixed. + UnityEngine.UIElements.UIR.UIRenderDevice.getEditorShader = () => EditorShader; + } + } + internal static event Action positionChanged = null; Panel m_Panel = null; readonly EditorCursorManager m_CursorManager = new EditorCursorManager(); static EditorContextualMenuManager s_ContextualMenuManager = new EditorContextualMenuManager(); - internal ExperimentalUI.Panel m_ExperimentalPanel = null; - readonly EditorExperimentalUI.EditorCursorManager m_ExperimentalCursorManager = new EditorExperimentalUI.EditorCursorManager(); - static EditorExperimentalUI.EditorContextualMenuManager s_ExperimentalContextualMenuManager = new EditorExperimentalUI.EditorContextualMenuManager(); - static Shader s_EditorShader = null; static Shader EditorShader @@ -53,11 +54,6 @@ protected Panel panel { if (m_Panel == null) { - if (m_ExperimentalPanel != null) - { - throw new InvalidOperationException("UIElements can't run in Experimental and Public mode at the same time. Please update your code to use the UnityEngine.UIElements namespace. Use SwitchUIElementMode() to change namespaces"); - } - uieMode = GUIView.UIElementsMode.Public; m_Panel = UIElementsUtility.FindOrCreatePanel(this, ContextType.Editor); m_Panel.name = GetType().Name; m_Panel.cursorManager = m_CursorManager; @@ -75,84 +71,8 @@ protected Panel panel } } - protected ExperimentalUI.Panel experimentalPanel - { - get - { - if (m_ExperimentalPanel == null) - { - if (m_Panel != null) - { - throw new InvalidOperationException("UIElements can't run in Experimental and Public mode at the same time. Please update your code to use the UnityEngine.UIElements namespace. Use SwitchUIElementMode() to change namespaces"); - } - uieMode = UIElementsMode.Experimental; - EditorExperimentalUI.UXMLEditorFactories.RegisterAll(); - m_ExperimentalPanel = ExperimentalUI.UIElementsUtility.FindOrCreatePanel(this, ExperimentalUI.ContextType.Editor, DataWatchService.sharedInstance); - m_ExperimentalPanel.cursorManager = m_ExperimentalCursorManager; - m_ExperimentalPanel.contextualMenuManager = s_ExperimentalContextualMenuManager; - m_ExperimentalPanel.panelDebug = new EditorExperimentalUI.PanelDebug(m_ExperimentalPanel); - - if (experimentalImguiContainer != null) - m_ExperimentalPanel.visualTree.Insert(0, experimentalImguiContainer); - - m_ExperimentalPanel.visualTree.SetSize(windowPosition.size); - } - - return m_ExperimentalPanel; - } - } - - //Remove this once we remove the Experimental namespace - internal enum UIElementsMode - { - Unset, - Experimental, - Public, - } - - internal UIElementsMode m_UIElementsMode = UIElementsMode.Unset; - public UnityEditor.GUIView.UIElementsMode uieMode - { - get { return m_UIElementsMode; } - set { m_UIElementsMode = value; } - } - - internal void SwitchUIElementsMode(UIElementsMode mode) - { - if (mode == UIElementsMode.Experimental) - { - if (m_Panel != null) - { - imguiContainer.RemoveFromHierarchy(); - m_Panel.Dispose(); - m_Panel = null; - } - - if (m_ExperimentalPanel == null) - { - var p = experimentalPanel; - } - } - else - { - if (m_ExperimentalPanel != null) - { - experimentalImguiContainer.RemoveFromHierarchy(); - m_ExperimentalPanel.Dispose(); - m_ExperimentalPanel = null; - } - if (m_Panel == null) - { - var p = panel; - } - } - } - public VisualElement visualTree => panel.visualTree; - public ExperimentalUI.VisualElement experimentalVisualTree => experimentalPanel.visualTree; - protected IMGUIContainer imguiContainer { get; private set; } - protected ExperimentalUI.IMGUIContainer experimentalImguiContainer { get; private set; } int m_DepthBufferBits = 0; int m_AntiAliasing = 1; @@ -186,15 +106,7 @@ protected override void SetWindow(ContainerWindow win) Internal_SetWantsMouseMove(m_EventInterests.wantsMouseMove); Internal_SetWantsMouseEnterLeaveWindow(m_EventInterests.wantsMouseMove); - if (m_ExperimentalPanel != null) - { - m_ExperimentalPanel.visualTree.SetSize(windowPosition.size); - } - else - { - panel.visualTree.SetSize(windowPosition.size); - } - + panel.visualTree.SetSize(windowPosition.size); m_BackgroundValid = false; } @@ -211,15 +123,7 @@ public EventInterests eventInterests set { m_EventInterests = value; - - if (m_ExperimentalPanel != null) - { - m_ExperimentalPanel.IMGUIEventInterests = m_EventInterests; - } - else - { - panel.IMGUIEventInterests = m_EventInterests; - } + panel.IMGUIEventInterests = m_EventInterests; Internal_SetWantsMouseMove(wantsMouseMove); Internal_SetWantsMouseEnterLeaveWindow(wantsMouseEnterLeaveWindow); @@ -232,15 +136,7 @@ public bool wantsMouseMove set { m_EventInterests.wantsMouseMove = value; - - if (m_ExperimentalPanel != null) - { - m_ExperimentalPanel.IMGUIEventInterests = m_EventInterests; - } - else - { - panel.IMGUIEventInterests = m_EventInterests; - } + panel.IMGUIEventInterests = m_EventInterests; Internal_SetWantsMouseMove(wantsMouseMove); } @@ -252,15 +148,7 @@ public bool wantsMouseEnterLeaveWindow set { m_EventInterests.wantsMouseEnterLeaveWindow = value; - - if (m_ExperimentalPanel != null) - { - m_ExperimentalPanel.IMGUIEventInterests = m_EventInterests; - } - else - { - panel.IMGUIEventInterests = m_EventInterests; - } + panel.IMGUIEventInterests = m_EventInterests; Internal_SetWantsMouseEnterLeaveWindow(wantsMouseEnterLeaveWindow); } @@ -299,14 +187,6 @@ public int antiAlias protected virtual void OnEnable() { - { - experimentalImguiContainer = new ExperimentalUI.IMGUIContainer(OldOnGUI) { useOwnerObjectGUIState = true }; - ExperimentalUI.VisualElementExtensions.StretchToParentSize(experimentalImguiContainer); - experimentalImguiContainer.persistenceKey = "Dockarea"; - - if (m_ExperimentalPanel != null) - m_ExperimentalPanel.visualTree.Insert(0, experimentalImguiContainer); - } { imguiContainer = new IMGUIContainer(OldOnGUI) { useOwnerObjectGUIState = true }; imguiContainer.StretchToParentSize(); @@ -322,32 +202,16 @@ protected virtual void OnEnable() protected virtual void OnDisable() { - if (uieMode == UIElementsMode.Experimental) - { - if (ExperimentalUI.MouseCaptureController.HasMouseCapture(experimentalImguiContainer)) - MouseCaptureController.ReleaseMouse(); - experimentalImguiContainer.RemoveFromHierarchy(); - experimentalImguiContainer = null; + if (imguiContainer.HasMouseCapture()) + MouseCaptureController.ReleaseMouse(); + imguiContainer.RemoveFromHierarchy(); + imguiContainer = null; - if (m_ExperimentalPanel != null) - { - m_ExperimentalPanel.Dispose(); - /// We don't set m_Panel to null to prevent it from being re-created from panel. - } - } - else + if (m_Panel != null) { - if (imguiContainer.HasMouseCapture()) - MouseCaptureController.ReleaseMouse(); - imguiContainer.RemoveFromHierarchy(); - imguiContainer = null; - - if (m_Panel != null) - { - UpdateDrawChainRegistration(false); - m_Panel.Dispose(); - /// We don't set m_Panel to null to prevent it from being re-created from panel. - } + UpdateDrawChainRegistration(false); + m_Panel.Dispose(); + /// We don't set m_Panel to null to prevent it from being re-created from panel. } Panel.BeforeUpdaterChange -= OnBeforeUpdaterChange; @@ -409,14 +273,7 @@ protected override void SetPosition(Rect newPos) m_BackgroundValid = false; - if (m_ExperimentalPanel != null) - { - m_ExperimentalPanel.visualTree.SetSize(windowPosition.size); - } - else - { - panel.visualTree.SetSize(windowPosition.size); - } + panel.visualTree.SetSize(windowPosition.size); positionChanged?.Invoke(this); diff --git a/Editor/Mono/GameObjectUtility.bindings.cs b/Editor/Mono/GameObjectUtility.bindings.cs index cea5470335..488a5471ad 100644 --- a/Editor/Mono/GameObjectUtility.bindings.cs +++ b/Editor/Mono/GameObjectUtility.bindings.cs @@ -96,6 +96,12 @@ private static void SetLayerRecursively(GameObject go, int layer) SetLayerRecursively(t.GetChild(i).gameObject, layer); } + [FreeFunction] + public static extern int GetMonoBehavioursWithMissingScriptCount(GameObject go); + + [FreeFunction] + public static extern int RemoveMonoBehavioursWithMissingScript(GameObject go); + [System.Obsolete("GetNavMeshArea instead.")] public static int GetNavMeshLayer(GameObject go) { diff --git a/Editor/Mono/GameView/GameView.cs b/Editor/Mono/GameView/GameView.cs index a62b92900b..02b4df17d3 100644 --- a/Editor/Mono/GameView/GameView.cs +++ b/Editor/Mono/GameView/GameView.cs @@ -44,6 +44,8 @@ internal class GameView : EditorWindow, IHasCustomMenu, IGameViewSizeMenuUser const float kMinScale = 1f; const float kMaxScale = 5f; const float kScrollZoomSnapDelay = 0.2f; + // This will save the previous state which will be useful in case of platform switch + int prevSizeGroupType; float minScale { @@ -51,7 +53,7 @@ float minScale { var clampedMinScale = Mathf.Min(kMinScale, ScaleThatFitsTargetInView(targetSize, viewInWindow.size)); if (m_LowResolutionForAspectRatios[(int)currentSizeGroupType] && currentGameViewSize.sizeType == GameViewSizeType.AspectRatio) - clampedMinScale = Mathf.Max(clampedMinScale, EditorGUIUtility.pixelsPerPoint); + clampedMinScale = Mathf.Max(clampedMinScale, Mathf.Floor(EditorGUIUtility.pixelsPerPoint)); return clampedMinScale; } } @@ -310,6 +312,7 @@ void InitializeZoomArea() public void OnEnable() { + prevSizeGroupType = (int)currentSizeGroupType; titleContent = GetLocalizedTitleContent(); UpdateZoomAreaAndParent(); dontClearBackground = true; @@ -587,6 +590,13 @@ private void DoToolbarGUI() EditorGUILayout.GameViewSizePopup(currentSizeGroupType, selectedSizeIndex, this, EditorStyles.toolbarPopup, GUILayout.Width(160f)); DoZoomSlider(); + // If the previous platform and current does not match, update the scale + if ((int)currentSizeGroupType != prevSizeGroupType) + { + UpdateZoomAreaAndParent(); + // Update the platform to the recent one + prevSizeGroupType = (int)currentSizeGroupType; + } if (FrameDebuggerUtility.IsLocalEnabled()) { diff --git a/Editor/Mono/GameView/GameViewSizes.cs b/Editor/Mono/GameView/GameViewSizes.cs index c43dd0b614..d3dfab7c75 100644 --- a/Editor/Mono/GameView/GameViewSizes.cs +++ b/Editor/Mono/GameView/GameViewSizes.cs @@ -269,7 +269,7 @@ internal static bool DefaultLowResolutionSettingForStandalone() case BuildTarget.StandaloneOSX: return !PlayerSettings.macRetinaSupport; // if retina support enabled -> expecting LowRes setting disabled by default default: - return true; + return GUIUtility.pixelsPerPoint <= 1.0f; } } diff --git a/Editor/Mono/HostView.cs b/Editor/Mono/HostView.cs index be86bb7e40..8d61696604 100644 --- a/Editor/Mono/HostView.cs +++ b/Editor/Mono/HostView.cs @@ -7,7 +7,8 @@ using System.Reflection; using UnityEditor.UIElements.Debugger; using UnityEngine.UIElements; -using ExperimentalUI = UnityEngine.Experimental.UIElements; +using System.Linq; +using UnityEditor.ShortcutManagement; using Unity.Experimental.EditorMode; namespace UnityEditor @@ -26,6 +27,8 @@ internal class HostView : GUIView // Cached version of the static color for the actual object instance... Color m_PlayModeDarkenColor; + private IMGUIContainer m_NotificationContainer; + internal EditorWindow actualView { get { return m_ActualView; } @@ -61,24 +64,17 @@ protected void UpdateViewMargins(EditorWindow view) RectOffset margins = GetBorderSize(); - if (view.m_RootVisualContainer != null) - { - var style = view.m_RootVisualContainer.style; - style.positionTop = margins.top; - style.positionBottom = margins.bottom; - style.positionLeft = margins.left; - style.positionRight = margins.right; - style.positionType = ExperimentalUI.StyleEnums.PositionType.Absolute; - } - else - { - IStyle style = EditorModes.GetRootElement(view).style; - style.top = margins.top; - style.bottom = margins.bottom; - style.left = margins.left; - style.right = margins.right; - style.position = Position.Absolute; - } + var rootElement = EditorModes.GetRootElement(view); + + if (rootElement == null) + return; + + IStyle style = rootElement.style; + style.top = margins.top; + style.bottom = margins.bottom; + style.left = margins.left; + style.right = margins.right; + style.position = Position.Absolute; } protected override void SetPosition(Rect newPos) @@ -114,6 +110,9 @@ protected override void OnEnable() EditorPrefs.onValueWasUpdated += PlayModeTintColorChangedCallback; base.OnEnable(); background = null; + m_NotificationContainer = new IMGUIContainer(); + m_NotificationContainer.StretchToParentSize(); + m_NotificationContainer.pickingMode = PickingMode.Ignore; RegisterSelectedPane(sendEvents: true); } @@ -153,9 +152,7 @@ protected override void OldOnGUI() } finally { - if (m_ActualView != null) - if (m_ActualView.m_FadeoutTime != 0 && Event.current.type == EventType.Repaint) - m_ActualView.DrawNotification(); + CheckNotificationStatus(); DoWindowDecorationEnd(); EditorGUI.ShowRepaints(); @@ -293,18 +290,6 @@ static class HostViewStyles public void InvokeOnGUI(Rect onGUIPosition, Rect viewRect) { - // Handle window reloading. - if (Unsupported.IsDeveloperMode() && - actualView != null && - Event.current.type == EventType.KeyUp && Event.current.keyCode == KeyCode.F5) - { - if (Event.current.control) - DebugWindow(actualView); - else - Reload(actualView); - return; - } - DoWindowDecorationStart(); BeginOffsetArea(viewRect, GUIContent.none, "TabWindowBackground"); @@ -333,9 +318,7 @@ public void InvokeOnGUI(Rect onGUIPosition, Rect viewRect) // We can't reset gui state after ExitGUI we just want to bail completely if (!isExitGUIException) { - bool isRepaint = (Event.current != null && Event.current.type == EventType.Repaint); - if (actualView != null && actualView.m_FadeoutTime != 0 && isRepaint) - actualView.DrawNotification(); + CheckNotificationStatus(); EndOffsetArea(); @@ -343,7 +326,7 @@ public void InvokeOnGUI(Rect onGUIPosition, Rect viewRect) DoWindowDecorationEnd(); - if (isRepaint) + if (Event.current != null && Event.current.type == EventType.Repaint) HostViewStyles.overlay.Draw(onGUIPosition, GUIContent.none, 0); } } @@ -361,16 +344,6 @@ protected void Invoke(string methodName, object obj) mi?.Invoke(obj, null); } - internal void RegisterExperimentalUIElementWindow() - { - SwitchUIElementsMode(GUIView.UIElementsMode.Experimental); - experimentalVisualTree.Add(m_ActualView.m_RootVisualContainer); - - m_ExperimentalPanel.getViewDataDictionary = m_ActualView.GetViewDataDictionary; - m_ExperimentalPanel.savePersistentViewData = m_ActualView.SaveViewData; - m_ExperimentalPanel.name = m_ActualView.GetType().Name; - } - protected void RegisterSelectedPane(bool sendEvents) { if (!m_ActualView) @@ -378,18 +351,10 @@ protected void RegisterSelectedPane(bool sendEvents) m_ActualView.m_Parent = this; - if (m_ActualView.m_RootVisualContainer != null) - { - RegisterExperimentalUIElementWindow(); - } - else - { - SwitchUIElementsMode(GUIView.UIElementsMode.Public); - visualTree.Add(EditorModes.GetRootElement(m_ActualView)); - panel.getViewDataDictionary = m_ActualView.GetViewDataDictionary; - panel.saveViewData = m_ActualView.SaveViewData; - panel.name = m_ActualView.GetType().Name; - } + visualTree.Add(EditorModes.GetRootElement(m_ActualView)); + panel.getViewDataDictionary = m_ActualView.GetViewDataDictionary; + panel.saveViewData = m_ActualView.SaveViewData; + panel.name = m_ActualView.GetType().Name; if (GetPaneMethod("Update") != null) EditorApplication.update += SendUpdate; @@ -432,25 +397,17 @@ protected void DeregisterSelectedPane(bool clearActualView, bool sendEvents) { if (!m_ActualView) return; - if (m_ActualView.m_RootVisualContainer != null) - { - var root = m_ActualView.m_RootVisualContainer; - if (m_ExperimentalPanel != null && root.shadow.parent == m_ExperimentalPanel.visualTree) - { - root.RemoveFromHierarchy(); - experimentalPanel.getViewDataDictionary = null; - experimentalPanel.savePersistentViewData = null; - } - } - else + + var root = EditorModes.GetRootElement(m_ActualView); + + if (root == null) + return; + + if (root.hierarchy.parent == visualTree) { - var root = EditorModes.GetRootElement(m_ActualView); - if (root.hierarchy.parent == visualTree) - { - root.RemoveFromHierarchy(); - panel.getViewDataDictionary = null; - panel.saveViewData = null; - } + root.RemoveFromHierarchy(); + panel.getViewDataDictionary = null; + panel.saveViewData = null; } if (GetPaneMethod("Update") != null) @@ -468,6 +425,9 @@ protected void DeregisterSelectedPane(bool clearActualView, bool sendEvents) EditorApplication.update -= m_ActualView.CheckForWindowRepaint; } + m_NotificationContainer.onGUIHandler = null; + m_NotificationContainer.RemoveFromHierarchy(); + if (clearActualView) { EditorWindow oldActualView = m_ActualView; @@ -482,6 +442,25 @@ protected void DeregisterSelectedPane(bool clearActualView, bool sendEvents) } } + protected void CheckNotificationStatus() + { + if (m_ActualView != null && m_ActualView.m_FadeoutTime != 0) + { + if (m_NotificationContainer.parent == null) + { + m_NotificationContainer.onGUIHandler = m_ActualView.DrawNotification; + visualTree.Add(m_NotificationContainer); + + m_NotificationContainer.StretchToParentSize(); + } + } + else + { + m_NotificationContainer.onGUIHandler = null; + m_NotificationContainer.RemoveFromHierarchy(); + } + } + void SendUpdate() { Invoke("Update"); @@ -563,22 +542,6 @@ private void Inspect(object userData) Selection.activeObject = (UnityEngine.Object)userData; } - internal void DebugWindow(object userData) - { - EditorWindow window = userData as EditorWindow; - if (window == null) - return; - - if (window.m_RootVisualContainer != null) - { - UnityEditor.Experimental.UIElements.Debugger.UIElementsDebugger.OpenAndInspectWindow(window); - } - else - { - UIElementsDebugger.OpenAndInspectWindow(window); - } - } - internal void Reload(object userData) { EditorWindow window = userData as EditorWindow; @@ -695,5 +658,24 @@ protected void ClearBackground() EditorGUIUtility.kViewBackgroundColor); backgroundValid = true; } + + protected void AddUIElementsDebuggerToMenu(GenericMenu menu) + { + var itemContent = UIElementsDebugger.WindowName; + var shortcut = ShortcutIntegration.instance.directory.FindShortcutEntry(UIElementsDebugger.k_WindowPath); + if (shortcut != null && shortcut.combinations.Any()) + itemContent += $" {KeyCombination.SequenceToMenuString(shortcut.combinations)}"; + + menu.AddItem(EditorGUIUtility.TextContent(itemContent), false, DebugWindow, actualView); + } + + private void DebugWindow(object userData) + { + EditorWindow window = userData as EditorWindow; + if (window == null) + return; + + UIElementsDebugger.OpenAndInspectWindow(window); + } } } diff --git a/Editor/Mono/ImportSettings/IHVImageFormatImporterInspector.cs b/Editor/Mono/ImportSettings/IHVImageFormatImporterInspector.cs index 32fa54d37c..43c35ee786 100644 --- a/Editor/Mono/ImportSettings/IHVImageFormatImporterInspector.cs +++ b/Editor/Mono/ImportSettings/IHVImageFormatImporterInspector.cs @@ -29,7 +29,7 @@ internal class Styles public static readonly GUIContent sRGBTexture = EditorGUIUtility.TrTextContent("sRGB (Color Texture)", "Texture content is stored in gamma space. Non-HDR color textures should enable this flag (except if used for IMGUI)."); public static readonly GUIContent wrapMode = EditorGUIUtility.TrTextContent("Wrap Mode"); public static readonly GUIContent filterMode = EditorGUIUtility.TrTextContent("Filter Mode"); - public static readonly GUIContent streamingMipmaps = EditorGUIUtility.TrTextContent("Streaming Mip Maps", "Only load larger mip maps as needed to render the current game cameras."); + public static readonly GUIContent streamingMipmaps = EditorGUIUtility.TrTextContent("Streaming MipMaps", "Only load larger mipmaps as needed to render the current game cameras."); public static readonly GUIContent streamingMipmapsPriority = EditorGUIUtility.TrTextContent("Mip Map Priority", "Mip map streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127."); public static readonly int[] filterModeValues = diff --git a/Editor/Mono/ImportSettings/SpeedTreeImporterInspector.cs b/Editor/Mono/ImportSettings/SpeedTreeImporterInspector.cs index e9b3f30547..02147bde1a 100644 --- a/Editor/Mono/ImportSettings/SpeedTreeImporterInspector.cs +++ b/Editor/Mono/ImportSettings/SpeedTreeImporterInspector.cs @@ -24,14 +24,12 @@ private static class Styles private SerializedProperty m_MaterialLocation; private SerializedProperty m_Materials; - private SerializedProperty m_ExternalObjects; private bool m_HasRemappedMaterials = false; public override void OnEnable() { m_MaterialLocation = serializedObject.FindProperty("m_MaterialLocation"); m_Materials = serializedObject.FindProperty("m_Materials"); - m_ExternalObjects = serializedObject.FindProperty("m_ExternalObjects"); if (tabs == null) { @@ -78,6 +76,24 @@ internal bool upgradeMaterials get { return importers.Any(i => i.materialsShouldBeRegenerated); } } + internal GUIContent GetGenButtonText(bool modified, bool upgrade) + { + if (modified || upgrade) + { + if (m_MaterialLocation.intValue == (int)SpeedTreeImporter.MaterialLocation.External) + return Styles.ApplyAndGenerate; + else + return Styles.ApplyAndGenerateRemapped; + } + else + { + if (m_MaterialLocation.intValue == (int)SpeedTreeImporter.MaterialLocation.External) + return Styles.Regenerate; + else + return Styles.RegenerateRemapped; + } + } + protected override bool OnApplyRevertGUI() { bool applied; @@ -87,37 +103,14 @@ protected override bool OnApplyRevertGUI() applied = ApplyButton(); } - if (HasRemappedMaterials()) + bool doMatsHaveDifferentShaders = (tabs[0] as SpeedTreeImporterModelEditor).doMaterialsHaveDifferentShader; + + if (HasRemappedMaterials() || doMatsHaveDifferentShaders) { bool upgrade = upgradeMaterials; - GUIContent genButtonText = null; - if (HasModified() || upgrade) + bool hasModified = HasModified(); + if (GUILayout.Button(GetGenButtonText(hasModified, upgrade))) { - if (m_MaterialLocation.intValue == (int)SpeedTreeImporter.MaterialLocation.External) - { - genButtonText = Styles.ApplyAndGenerate; - } - else - { - genButtonText = Styles.ApplyAndGenerateRemapped; - } - } - else - { - if (m_MaterialLocation.intValue == (int)SpeedTreeImporter.MaterialLocation.External) - { - genButtonText = Styles.Regenerate; - } - else - { - genButtonText = Styles.RegenerateRemapped; - } - } - - if (GUILayout.Button(genButtonText)) - { - bool hasModified = HasModified(); - // Apply the changes and generate the materials before importing so that asset previews are up-to-date. if (hasModified) Apply(); @@ -182,13 +175,12 @@ private bool HasRemappedMaterials() return true; // if the m_ExternalObjecs map has any unapplied changes, keep the state of the button as is - if (m_ExternalObjects.serializedObject.hasModifiedProperties) + if (serializedObject.hasModifiedProperties) return m_HasRemappedMaterials; m_HasRemappedMaterials = true; - foreach (var t in m_ExternalObjects.serializedObject.targetObjects) + foreach (var importer in importers) { - var importer = t as SpeedTreeImporter; var externalObjectMap = importer.GetExternalObjectMap(); var materialsList = importer.sourceMaterials; @@ -200,6 +192,8 @@ private bool HasRemappedMaterials() } m_HasRemappedMaterials = m_HasRemappedMaterials && remappedMaterialCount != 0; + if (!m_HasRemappedMaterials) + break; } return m_HasRemappedMaterials; } diff --git a/Editor/Mono/ImportSettings/SpeedTreeImporterModelEditor.cs b/Editor/Mono/ImportSettings/SpeedTreeImporterModelEditor.cs index dc5e0ee08a..6502c0f46a 100644 --- a/Editor/Mono/ImportSettings/SpeedTreeImporterModelEditor.cs +++ b/Editor/Mono/ImportSettings/SpeedTreeImporterModelEditor.cs @@ -66,6 +66,8 @@ private class Styles private readonly AnimBool m_ShowSmoothLODOptions = new AnimBool(); private readonly AnimBool m_ShowCrossFadeWidthOptions = new AnimBool(); + public bool doMaterialsHaveDifferentShader = false; + public SpeedTreeImporterModelEditor(AssetImporterEditor panelContainer) : base(panelContainer) {} @@ -146,6 +148,40 @@ public bool CanUnifyLODConfig() && !m_LODSettings.FindPropertyRelative("Array.size").hasMultipleDifferentValues; } + private bool DoMaterialsHaveDifferentShader() + { + var importerArray = importers.ToArray(); + var prefabs = assetTargets?.Cast().ToArray(); + + // In tests assetTargets can become null + for (int i = 0; i < Math.Min(importerArray.Length, prefabs?.Length ?? 0); ++i) + { + var im = importerArray[i]; + var defaultShader = im.defaultShader; + var defaultBillboardShader = im.defaultBillboardShader; + + foreach (var mr in prefabs[i].transform.GetComponentsInChildren()) + { + foreach (var mat in mr.sharedMaterials) + { + if (mat.shader != defaultShader) + return true; + } + } + + if (defaultBillboardShader != null) + { + foreach (var br in prefabs[i].transform.GetComponentsInChildren()) + { + if (br.billboard.material.shader != defaultBillboardShader) + return true; + } + } + } + + return false; + } + public override void OnInspectorGUI() { ShowMeshGUI(); @@ -154,8 +190,15 @@ public override void OnInspectorGUI() EditorGUILayout.Space(); - if (upgradeMaterials) + bool materialsNeedToBeUpgraded = upgradeMaterials; + doMaterialsHaveDifferentShader = !materialsNeedToBeUpgraded && DoMaterialsHaveDifferentShader(); + + if (materialsNeedToBeUpgraded) EditorGUILayout.HelpBox(String.Format("SpeedTree materials need to be upgraded. Please back them up (if modified manually) then hit the \"{0}\" button below.", Styles.ApplyAndGenerate.text), MessageType.Warning); + + if (doMaterialsHaveDifferentShader) + EditorGUILayout.HelpBox(String.Format("There is a different SpeedTree shader provided by the current render pipeline which probably is more suitable for rendering. Hit the \"{0}\" button to regenerate the materials.", + (panelContainer as SpeedTreeImporterInspector).GetGenButtonText(HasModified(), materialsNeedToBeUpgraded).text), MessageType.Warning); } private void ShowMeshGUI() diff --git a/Editor/Mono/ImportSettings/TextureImporterInspector.cs b/Editor/Mono/ImportSettings/TextureImporterInspector.cs index 5115fa5ad1..ab74bde02a 100644 --- a/Editor/Mono/ImportSettings/TextureImporterInspector.cs +++ b/Editor/Mono/ImportSettings/TextureImporterInspector.cs @@ -223,7 +223,7 @@ internal class Styles public readonly GUIContent[] cubemapOptions = { EditorGUIUtility.TrTextContent("Auto"), - EditorGUIUtility.TrTextContent("6 Frames Layout (Cubic Environment)", "Texture contains 6 images arranged in one of the standard cubemap layouts - cross or sequence (+x,-x, +y, -y, +z, -z). Texture can be in vertical or horizontal orientation."), + EditorGUIUtility.TrTextContent("6 Frames Layout (Cubic Environment)", "Texture contains 6 images arranged in one of the standard cubemap layouts - cross or sequence (+x, -x, +y, -y, +z, -z). Texture can be in vertical or horizontal orientation."), EditorGUIUtility.TrTextContent("Latitude-Longitude Layout (Cylindrical)", "Texture contains an image of a ball unwrapped such that latitude and longitude are mapped to horizontal and vertical dimensions (as on a globe)."), EditorGUIUtility.TrTextContent("Mirrored Ball (Spheremap)", "Texture contains an image of a mirrored ball.") }; @@ -256,7 +256,7 @@ internal class Styles public readonly GUIContent mipmapFadeOutToggle = EditorGUIUtility.TrTextContent("Fadeout Mip Maps"); public readonly GUIContent mipmapFadeOut = EditorGUIUtility.TrTextContent("Fade Range"); public readonly GUIContent readWrite = EditorGUIUtility.TrTextContent("Read/Write Enabled", "Enable to be able to access the raw pixel data from code."); - public readonly GUIContent streamingMipmaps = EditorGUIUtility.TrTextContent("Streaming Mip Maps", "Only load larger mip maps as needed to render the current game cameras. Requires texture streaming to be enabled in quality settings."); + public readonly GUIContent streamingMipmaps = EditorGUIUtility.TrTextContent("Streaming MipMaps", "Only load larger mipmaps as needed to render the current game cameras. Requires texture streaming to be enabled in quality settings."); public readonly GUIContent streamingMipmapsPriority = EditorGUIUtility.TrTextContent("Mip Map Priority", "Mip map streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127."); public readonly GUIContent alphaSource = EditorGUIUtility.TrTextContent("Alpha Source", "How is the alpha generated for the imported texture."); @@ -296,7 +296,7 @@ internal class Styles EditorGUIUtility.TrTextContent("Box"), EditorGUIUtility.TrTextContent("Kaiser"), }; - public readonly GUIContent npot = EditorGUIUtility.TrTextContent("Non Power of 2", "How non-power-of-two textures are scaled on import."); + public readonly GUIContent npot = EditorGUIUtility.TrTextContent("Non-Power of 2", "How non-power-of-two textures are scaled on import."); public readonly GUIContent generateCubemap = EditorGUIUtility.TrTextContent("Generate Cubemap"); public readonly GUIContent compressionQuality = EditorGUIUtility.TrTextContent("Compressor Quality"); @@ -944,7 +944,12 @@ private void SpriteGUI(TextureInspectorGUIElement guiElements) m_ShowGenericSpriteSettings.target = (m_SpriteMode.intValue != 0); if (EditorGUILayout.BeginFadeGroup(m_ShowGenericSpriteSettings.faded)) { - EditorGUILayout.PropertyField(m_SpritePackingTag, s_Styles.spritePackingTag); + if (EditorSettings.spritePackerMode == SpritePackerMode.AlwaysOn || + EditorSettings.spritePackerMode == SpritePackerMode.BuildTimeOnly) + { + EditorGUILayout.PropertyField(m_SpritePackingTag, s_Styles.spritePackingTag); + } + EditorGUILayout.PropertyField(m_SpritePixelsToUnits, s_Styles.spritePixelsPerUnit); m_ShowSpriteMeshTypeOption.target = ShouldShowSpriteMeshTypeOption(); diff --git a/Editor/Mono/Inspector/AddComponent/ComponentDropdownItem.cs b/Editor/Mono/Inspector/AddComponent/ComponentDropdownItem.cs index d939e8e148..e66b2ffb12 100644 --- a/Editor/Mono/Inspector/AddComponent/ComponentDropdownItem.cs +++ b/Editor/Mono/Inspector/AddComponent/ComponentDropdownItem.cs @@ -5,18 +5,11 @@ using System; using UnityEditor.IMGUI.Controls; using UnityEngine; -using UnityEditorInternal; namespace UnityEditor.AddComponent { internal class ComponentDropdownItem : AdvancedDropdownItem { - struct ComponentMenuCommandInfo - { - public int instanceID; - public string guid; - }; - private string m_MenuPath; private bool m_IsLegacy; private string m_LocalizedName; @@ -62,15 +55,7 @@ public ComponentDropdownItem(string name, string menuPath, string command) : bas m_MenuPath = menuPath; m_IsLegacy = menuPath.Contains("Legacy"); - if (command.StartsWith("ASSET")) - { - var info = JsonUtility.FromJson(command.Substring(5)); - var obj = EditorUtility.InstanceIDToObject(info.instanceID); - var icon = AssetPreview.GetMiniThumbnail(obj); - base.name = name; - base.icon = icon; - } - else if (command.StartsWith("SCRIPT")) + if (command.StartsWith("SCRIPT")) { var scriptId = int.Parse(command.Substring(6)); var obj = EditorUtility.InstanceIDToObject(scriptId); diff --git a/Editor/Mono/Inspector/AdvancedDropdown/EditorGUI/StatelessAdvancedDropdown.cs b/Editor/Mono/Inspector/AdvancedDropdown/EditorGUI/StatelessAdvancedDropdown.cs index 9d2cb3e2c6..66bf0a70cf 100644 --- a/Editor/Mono/Inspector/AdvancedDropdown/EditorGUI/StatelessAdvancedDropdown.cs +++ b/Editor/Mono/Inspector/AdvancedDropdown/EditorGUI/StatelessAdvancedDropdown.cs @@ -87,7 +87,7 @@ private static void InitMultiselectPopupWindow(Rect rect, MultiselectDataSource internal static int DoSearchablePopup(Rect rect, int selectedIndex, string[] displayedOptions, GUIStyle style) { - string contentLabel = null; + string contentLabel = ""; if (selectedIndex >= 0) { contentLabel = displayedOptions[selectedIndex]; diff --git a/Editor/Mono/Inspector/AnimationClipEditor.cs b/Editor/Mono/Inspector/AnimationClipEditor.cs index f37d3f6514..c64a8f025a 100644 --- a/Editor/Mono/Inspector/AnimationClipEditor.cs +++ b/Editor/Mono/Inspector/AnimationClipEditor.cs @@ -48,7 +48,7 @@ private static class Styles public static GUIContent HasAdditiveReferencePose = EditorGUIUtility.TrTextContent("Additive Reference Pose", "Enable to define the additive reference pose frame."); public static GUIContent AdditiveReferencePoseFrame = EditorGUIUtility.TrTextContent("Pose Frame", "Pose Frame."); - public static GUIContent LoopTime = EditorGUIUtility.TrTextContent("Loop Time", "Enable to make the animation plays through and then restarts when the end is reached."); + public static GUIContent LoopTime = EditorGUIUtility.TrTextContent("Loop Time", "Enable to make the animation play through and then restart when the end is reached."); public static GUIContent LoopPose = EditorGUIUtility.TrTextContent("Loop Pose", "Enable to make the animation loop seamlessly."); public static GUIContent LoopCycleOffset = EditorGUIUtility.TrTextContent("Cycle Offset", "Offset to the cycle of a looping animation, if we want to start it at a different time."); public static GUIContent RootTransformRotation = EditorGUIUtility.TrTextContent("Root Transform Rotation"); diff --git a/Editor/Mono/Inspector/AssemblyDefinitionImporterInspector.cs b/Editor/Mono/Inspector/AssemblyDefinitionImporterInspector.cs index d1baa7459a..a8b4e9919a 100644 --- a/Editor/Mono/Inspector/AssemblyDefinitionImporterInspector.cs +++ b/Editor/Mono/Inspector/AssemblyDefinitionImporterInspector.cs @@ -829,11 +829,20 @@ static AssemblyDefintionState LoadAssemblyDefintionState(string path) if (asset == null) return null; - var data = CustomScriptAssemblyData.FromJson(asset.text); + var data = CustomScriptAssemblyData.FromJsonNoFieldValidation(asset.text); if (data == null) return null; + try + { + data.ValidateFields(); + } + catch (Exception e) + { + Debug.LogException(e, asset); + } + var state = new AssemblyDefintionState(); state.asset = asset; diff --git a/Editor/Mono/Inspector/AudioClipInspector.cs b/Editor/Mono/Inspector/AudioClipInspector.cs index 4c0a30c4a4..2752e4b8d8 100644 --- a/Editor/Mono/Inspector/AudioClipInspector.cs +++ b/Editor/Mono/Inspector/AudioClipInspector.cs @@ -11,19 +11,19 @@ namespace UnityEditor internal class AudioClipInspector : Editor { private PreviewRenderUtility m_PreviewUtility; - - // Any number of AudioClip inspectors can be docked in addition to the object browser, and they are all showing and modifying the same shared state. - static AudioClipInspector m_PlayingInspector; - static AudioClip m_PlayingClip; - static bool playing { get { return m_PlayingClip != null && AudioUtil.IsClipPlaying(m_PlayingClip); } } - static bool m_bAutoPlay; - static bool m_bLoop; - + private AudioClip m_Clip; + private bool playing => s_PlayingInstance == this && m_Clip != null && AudioUtil.IsClipPlaying(m_Clip); Vector2 m_Position = Vector2.zero; - Rect m_wantedRect; + private bool m_MultiEditing; static GUIStyle s_PreButton; + static Rect s_WantedRect; + static bool s_AutoPlay; + static bool s_Loop; + static bool s_PlayFirst; + static AudioClipInspector s_PlayingInstance; + static GUIContent[] s_PlayIcons = {null, null}; static GUIContent[] s_AutoPlayIcons = {null, null}; static GUIContent[] s_LoopIcons = {null, null}; @@ -32,8 +32,10 @@ internal class AudioClipInspector : Editor private Material m_HandleLinesMaterial; - override public void OnInspectorGUI() + public override void OnInspectorGUI() { + // We can't always check this from preview methods + m_MultiEditing = targets.Length > 1; // Override with inspector that doesn't show anything } @@ -43,7 +45,8 @@ static void Init() return; s_PreButton = "preButton"; - m_bAutoPlay = EditorPrefs.GetBool("AutoPlayAudio", false); + s_AutoPlay = EditorPrefs.GetBool("AutoPlayAudio", false); + s_Loop = false; s_AutoPlayIcons[0] = EditorGUIUtility.TrIconContent("preAudioAutoPlayOff", "Turn Auto Play on"); s_AutoPlayIcons[1] = EditorGUIUtility.TrIconContent("preAudioAutoPlayOn", "Turn Auto Play off"); @@ -57,14 +60,13 @@ static void Init() public void OnDisable() { - // This check is necessary because the order of OnEnable/OnDisable varies depending on whether the inspector is embedded in the project browser or object selector. - if (m_PlayingInspector == this) + if (s_PlayingInstance == this) { AudioUtil.StopAllClips(); - m_PlayingClip = null; + s_PlayingInstance = null; } - EditorPrefs.SetBool("AutoPlayAudio", m_bAutoPlay); + EditorPrefs.SetBool("AutoPlayAudio", s_AutoPlay); if (m_PreviewUtility != null) { @@ -77,11 +79,9 @@ public void OnDisable() public void OnEnable() { - AudioUtil.StopAllClips(); - m_PlayingClip = null; - m_PlayingInspector = this; - - m_bAutoPlay = EditorPrefs.GetBool("AutoPlayAudio", false); + s_AutoPlay = EditorPrefs.GetBool("AutoPlayAudio", false); + if (s_AutoPlay) + s_PlayFirst = true; m_HandleLinesMaterial = EditorGUIUtility.LoadRequired("SceneView/HandleLines.mat") as Material; } @@ -119,64 +119,45 @@ public override void OnPreviewSettings() if (s_DefaultIcon == null) Init(); AudioClip clip = target as AudioClip; - - bool isEditingMultipleObjects = targets.Length > 1; + m_MultiEditing = targets.Length > 1; using (new EditorGUI.DisabledScope(AudioUtil.IsMovieAudio(clip))) { - bool oldAutoPlay = m_bAutoPlay; - bool newAutoPlay = PreviewGUI.CycleButton(oldAutoPlay ? 1 : 0, s_AutoPlayIcons) != 0; - if (oldAutoPlay != newAutoPlay) + using (new EditorGUI.DisabledScope(m_MultiEditing)) { - m_bAutoPlay = newAutoPlay; - InspectorWindow.RepaintAllInspectors(); + s_AutoPlay = s_AutoPlay && !m_MultiEditing; + s_AutoPlay = PreviewGUI.CycleButton(s_AutoPlay ? 1 : 0, s_AutoPlayIcons) != 0; } - bool oldLoop = m_bLoop; - bool newLoop = PreviewGUI.CycleButton(oldLoop ? 1 : 0, s_LoopIcons) != 0; - if (oldLoop != newLoop) - { - m_bLoop = newLoop; - if (playing) - AudioUtil.LoopClip(clip, newLoop); - InspectorWindow.RepaintAllInspectors(); - } + bool loop = s_Loop; + s_Loop = PreviewGUI.CycleButton(s_Loop ? 1 : 0, s_LoopIcons) != 0; + if ((loop != s_Loop) && playing) + AudioUtil.LoopClip(clip, s_Loop); - using (new EditorGUI.DisabledScope(isEditingMultipleObjects && !playing && m_PlayingInspector != this)) + using (new EditorGUI.DisabledScope(m_MultiEditing && !playing)) { - bool curPlaying = m_PlayingInspector == this && playing; - bool newPlaying = PreviewGUI.CycleButton(curPlaying ? 1 : 0, s_PlayIcons) != 0; + bool newPlaying = PreviewGUI.CycleButton(playing ? 1 : 0, s_PlayIcons) != 0; - if (newPlaying != curPlaying) + if (newPlaying != playing) { - AudioUtil.StopAllClips(); - m_PlayingClip = null; - m_PlayingInspector = null; - - if (newPlaying && !isEditingMultipleObjects) + if (newPlaying) + PlayClip(clip, 0, s_Loop); + else { - AudioUtil.PlayClip(clip, 0, m_bLoop); - m_PlayingClip = clip; - m_PlayingInspector = this; + AudioUtil.StopAllClips(); + m_Clip = null; } } } } + } - // autoplay start? - if (m_bAutoPlay && m_PlayingClip != clip && m_PlayingInspector == this && !isEditingMultipleObjects) - { - AudioUtil.StopAllClips(); - m_PlayingClip = null; - m_PlayingInspector = null; - - if (!isEditingMultipleObjects) - { - AudioUtil.PlayClip(clip, 0, m_bLoop); - m_PlayingClip = clip; - m_PlayingInspector = this; - } - } + void PlayClip(AudioClip clip, int startSample = 0, bool loop = false) + { + AudioUtil.StopAllClips(); + AudioUtil.PlayClip(clip, startSample, loop); + m_Clip = clip; + s_PlayingInstance = this; } // Passing in clip and importer separately as we're not completely done with the asset setup at the time we're asked to generate the preview. @@ -228,8 +209,6 @@ public override void OnPreviewGUI(Rect r, GUIStyle background) Event evt = Event.current; if (evt.type != EventType.Repaint && evt.type != EventType.Layout && evt.type != EventType.Used) { - int px2sample = (AudioUtil.GetSampleCount(clip) / (int)r.width); - switch (evt.type) { case EventType.MouseDrag: @@ -237,14 +216,11 @@ public override void OnPreviewGUI(Rect r, GUIStyle background) { if (r.Contains(evt.mousePosition) && !AudioUtil.IsMovieAudio(clip)) { - if (m_PlayingClip != clip || !AudioUtil.IsClipPlaying(clip)) - { - AudioUtil.StopAllClips(); - AudioUtil.PlayClip(clip, 0, m_bLoop); - m_PlayingClip = clip; - m_PlayingInspector = this; - } - AudioUtil.SetClipSamplePosition(clip, px2sample * (int)evt.mousePosition.x); + var startSample = (int)(evt.mousePosition.x * (AudioUtil.GetSampleCount(clip) / (int)r.width)); + if (!AudioUtil.IsClipPlaying(clip) || clip != m_Clip) + PlayClip(clip, startSample, s_Loop); + else + AudioUtil.SetClipSamplePosition(clip, startSample); evt.Use(); } } @@ -257,8 +233,8 @@ public override void OnPreviewGUI(Rect r, GUIStyle background) background.Draw(r, false, false, false, false); int c = AudioUtil.GetChannelCount(clip); - m_wantedRect = new Rect(r.x, r.y , r.width, r.height); - float sec2px = ((float)m_wantedRect.width / clip.length); + s_WantedRect = new Rect(r.x, r.y , r.width, r.height); + float sec2px = ((float)s_WantedRect.width / clip.length); bool previewAble = AudioUtil.HasPreview(clip) || !(AudioUtil.IsTrackerFile(clip) || AudioUtil.IsMovieAudio(clip)); if (!previewAble) @@ -284,50 +260,57 @@ public override void OnPreviewGUI(Rect r, GUIStyle background) EditorGUI.DropShadowLabel(new Rect(r.x, labelY, r.width, 20), "Can not show PCM data for this file"); } - if (m_PlayingInspector == this && m_PlayingClip == clip) + if (m_Clip == clip) { float t = AudioUtil.GetClipPosition(clip); System.TimeSpan ts = new System.TimeSpan(0, 0, 0, 0, (int)(t * 1000.0f)); - EditorGUI.DropShadowLabel(new Rect(m_wantedRect.x, m_wantedRect.y, m_wantedRect.width, 20), string.Format("Playing - {0:00}:{1:00}.{2:000}", ts.Minutes, ts.Seconds, ts.Milliseconds)); + EditorGUI.DropShadowLabel(new Rect(s_WantedRect.x, s_WantedRect.y, s_WantedRect.width, 20), string.Format("Playing - {0:00}:{1:00}.{2:000}", ts.Minutes, ts.Seconds, ts.Milliseconds)); } } else { - PreviewGUI.BeginScrollView(m_wantedRect, m_Position, m_wantedRect, "PreHorizontalScrollbar", "PreHorizontalScrollbarThumb"); + PreviewGUI.BeginScrollView(s_WantedRect, m_Position, s_WantedRect, "PreHorizontalScrollbar", "PreHorizontalScrollbarThumb"); if (Event.current.type == EventType.Repaint) { - DoRenderPreview(true, clip, AudioUtil.GetImporterFromClip(clip), m_wantedRect, 1.0f); + DoRenderPreview(true, clip, AudioUtil.GetImporterFromClip(clip), s_WantedRect, 1.0f); } for (int i = 0; i < c; ++i) { if (c > 1 && r.width > 64) { - var labelRect = new Rect(m_wantedRect.x + 5, m_wantedRect.y + (m_wantedRect.height / c) * i, 30, 20); + var labelRect = new Rect(s_WantedRect.x + 5, s_WantedRect.y + (s_WantedRect.height / c) * i, 30, 20); EditorGUI.DropShadowLabel(labelRect, "ch " + (i + 1).ToString()); } } - if (m_PlayingInspector == this && m_PlayingClip == clip) + if (m_Clip == clip) { float t = AudioUtil.GetClipPosition(clip); System.TimeSpan ts = new System.TimeSpan(0, 0, 0, 0, (int)(t * 1000.0f)); - GUI.DrawTexture(new Rect(m_wantedRect.x + (int)(sec2px * t), m_wantedRect.y, 2, m_wantedRect.height), EditorGUIUtility.whiteTexture); + GUI.DrawTexture(new Rect(s_WantedRect.x + (int)(sec2px * t), s_WantedRect.y, 2, s_WantedRect.height), EditorGUIUtility.whiteTexture); if (r.width > 64) - EditorGUI.DropShadowLabel(new Rect(m_wantedRect.x, m_wantedRect.y, m_wantedRect.width, 20), string.Format("{0:00}:{1:00}.{2:000}", ts.Minutes, ts.Seconds, ts.Milliseconds)); + EditorGUI.DropShadowLabel(new Rect(s_WantedRect.x, s_WantedRect.y, s_WantedRect.width, 20), string.Format("{0:00}:{1:00}.{2:000}", ts.Minutes, ts.Seconds, ts.Milliseconds)); else - EditorGUI.DropShadowLabel(new Rect(m_wantedRect.x, m_wantedRect.y, m_wantedRect.width, 20), string.Format("{0:00}:{1:00}", ts.Minutes, ts.Seconds)); + EditorGUI.DropShadowLabel(new Rect(s_WantedRect.x, s_WantedRect.y, s_WantedRect.width, 20), string.Format("{0:00}:{1:00}", ts.Minutes, ts.Seconds)); } - PreviewGUI.EndScrollView(); } + + if (!m_MultiEditing && (s_PlayFirst || (s_AutoPlay && m_Clip != clip))) + { + // Autoplay preview + PlayClip(clip, 0, s_Loop); + s_PlayFirst = false; + } + // force update GUI if (playing) GUIView.current.Repaint(); diff --git a/Editor/Mono/Inspector/AudioHighPassFIlterInspector.cs b/Editor/Mono/Inspector/AudioHighPassFIlterInspector.cs index abd6afede8..91b7f2e311 100644 --- a/Editor/Mono/Inspector/AudioHighPassFIlterInspector.cs +++ b/Editor/Mono/Inspector/AudioHighPassFIlterInspector.cs @@ -8,7 +8,27 @@ namespace UnityEditor { [CustomEditor(typeof(AudioHighPassFilter))] + [CanEditMultipleObjects] class AudioHighPassFilterEditor : Editor { + SerializedProperty m_HighpassResonanceQ; + SerializedProperty m_CutoffFrequency; + + void OnEnable() + { + m_HighpassResonanceQ = serializedObject.FindProperty("m_HighpassResonanceQ"); + m_CutoffFrequency = serializedObject.FindProperty("m_CutoffFrequency"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.Slider(m_CutoffFrequency, 10.0f, 22000.0f, EditorGUIUtility.TrTextContent("CutOffFrequency", "Sets the cut off frequency of High Pass filter")); + + EditorGUILayout.PropertyField(m_HighpassResonanceQ); + + serializedObject.ApplyModifiedProperties(); + } } } diff --git a/Editor/Mono/Inspector/AudioManagerInspector.cs b/Editor/Mono/Inspector/AudioManagerInspector.cs index 1e8868d7f3..517d27e005 100644 --- a/Editor/Mono/Inspector/AudioManagerInspector.cs +++ b/Editor/Mono/Inspector/AudioManagerInspector.cs @@ -21,11 +21,13 @@ private class Styles public static GUIContent SampleRate = EditorGUIUtility.TrTextContent("System Sample Rate", "Sample rate at which the output device of the audio system runs. Individual sounds may run at different sample rates and will be slowed down/sped up accordingly to match the output rate."); public static GUIContent DSPBufferSize = EditorGUIUtility.TrTextContent("DSP Buffer Size", "Length of mixing buffer. This determines the output latency of the game."); public static GUIContent VirtualVoiceCount = EditorGUIUtility.TrTextContent("Max Virtual Voices", "Maximum number of sounds managed by the system. Even though at most RealVoiceCount of the loudest sounds will be physically playing, the remaining sounds will still be updating their play position."); - public static GUIContent RealVoiceCount = EditorGUIUtility.TrTextContent("Max Real Voices", "Maximum number of actual simultanously playing sounds."); + public static GUIContent RealVoiceCount = EditorGUIUtility.TrTextContent("Max Real Voices", "Maximum number of actual simultaneously playing sounds."); public static GUIContent SpatializerPlugin = EditorGUIUtility.TrTextContent("Spatializer Plugin", "Native audio plugin performing spatialized filtering of 3D sources."); public static GUIContent AmbisonicDecoderPlugin = EditorGUIUtility.TrTextContent("Ambisonic Decoder Plugin", "Native audio plugin performing ambisonic-to-binaural filtering of sources."); public static GUIContent DisableAudio = EditorGUIUtility.TrTextContent("Disable Unity Audio", "Prevent allocating the output device in the runtime. Use this if you want to use other sound systems than the built-in one."); - public static GUIContent VirtualizeEffects = EditorGUIUtility.TrTextContent("Virtualize Effects", "When enabled dynamically turn off effects and spatializers on AudioSources that are culled in order to save CPU."); + public static GUIContent VirtualizeEffects = EditorGUIUtility.TrTextContent("Virtualize Effects", "When enabled, dynamically turn off effects and spatializers on AudioSources that are culled in order to save CPU."); + + public static GUIContent DSPBufferSizeInfo = EditorGUIUtility.TrTextContent("The requested buffer size ({0}) has been overridden to {1} by the operating system"); } private SerializedProperty m_Volume; @@ -33,7 +35,8 @@ private class Styles private SerializedProperty m_DopplerFactor; private SerializedProperty m_DefaultSpeakerMode; private SerializedProperty m_SampleRate; - private SerializedProperty m_DSPBufferSize; + private SerializedProperty m_RequestedDSPBufferSize; + private SerializedProperty m_ActualDSPBufferSize; private SerializedProperty m_VirtualVoiceCount; private SerializedProperty m_RealVoiceCount; private SerializedProperty m_SpatializerPlugin; @@ -48,7 +51,8 @@ private void OnEnable() m_DopplerFactor = serializedObject.FindProperty("Doppler Factor"); m_DefaultSpeakerMode = serializedObject.FindProperty("Default Speaker Mode"); m_SampleRate = serializedObject.FindProperty("m_SampleRate"); - m_DSPBufferSize = serializedObject.FindProperty("m_DSPBufferSize"); + m_RequestedDSPBufferSize = serializedObject.FindProperty("m_RequestedDSPBufferSize"); + m_ActualDSPBufferSize = serializedObject.FindProperty("m_DSPBufferSize"); m_VirtualVoiceCount = serializedObject.FindProperty("m_VirtualVoiceCount"); m_RealVoiceCount = serializedObject.FindProperty("m_RealVoiceCount"); m_SpatializerPlugin = serializedObject.FindProperty("m_SpatializerPlugin"); @@ -79,7 +83,13 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(m_DopplerFactor, Styles.DopplerFactor); EditorGUILayout.PropertyField(m_DefaultSpeakerMode, Styles.DefaultSpeakerMode); EditorGUILayout.PropertyField(m_SampleRate, Styles.SampleRate); - EditorGUILayout.PropertyField(m_DSPBufferSize, Styles.DSPBufferSize); + EditorGUILayout.PropertyField(m_RequestedDSPBufferSize, Styles.DSPBufferSize); + if (m_RequestedDSPBufferSize.intValue != m_ActualDSPBufferSize.intValue) + EditorGUILayout.HelpBox( + string.Format(Styles.DSPBufferSizeInfo.text, + m_RequestedDSPBufferSize.intValue == 0 ? "default" : m_RequestedDSPBufferSize.intValue.ToString(), + m_ActualDSPBufferSize.intValue), + MessageType.Info); EditorGUILayout.PropertyField(m_VirtualVoiceCount, Styles.VirtualVoiceCount); EditorGUILayout.PropertyField(m_RealVoiceCount, Styles.RealVoiceCount); diff --git a/Editor/Mono/Inspector/AudioSourceInspector.cs b/Editor/Mono/Inspector/AudioSourceInspector.cs index 428a8ee663..d30de59e14 100644 --- a/Editor/Mono/Inspector/AudioSourceInspector.cs +++ b/Editor/Mono/Inspector/AudioSourceInspector.cs @@ -87,7 +87,7 @@ internal static class Styles public static GUIContent rolloffLabel = EditorGUIUtility.TrTextContent("Volume Rolloff", "Which type of rolloff curve to use"); public static string controlledByCurveLabel = "Controlled by curve"; public static GUIContent audioClipLabel = EditorGUIUtility.TrTextContent("AudioClip", "The AudioClip asset played by the AudioSource. Can be undefined if the AudioSource is generating a live stream of audio via OnAudioFilterRead."); - public static GUIContent panStereoLabel = EditorGUIUtility.TrTextContent("Stereo Pan", "Only valid for Mono and Stereo AudioClips. Mono sounds will be panned at constant power left and right. Stereo sounds will Stereo sounds have each left/right value faded up and down according to the specified pan value."); + public static GUIContent panStereoLabel = EditorGUIUtility.TrTextContent("Stereo Pan", "Only valid for Mono and Stereo AudioClips. Mono sounds will be panned at constant power left and right. Stereo sounds will have each left/right value faded up and down according to the specified pan value."); public static GUIContent spatialBlendLabel = EditorGUIUtility.TrTextContent("Spatial Blend", "Sets how much this AudioSource is treated as a 3D source. 3D sources are affected by spatial position and spread. If 3D Pan Level is 0, all spatial attenuation is ignored."); public static GUIContent reverbZoneMixLabel = EditorGUIUtility.TrTextContent("Reverb Zone Mix", "Sets how much of the signal this AudioSource is mixing into the global reverb associated with the zones. [0, 1] is a linear range (like volume) while [1, 1.1] lets you boost the reverb mix by 10 dB."); public static GUIContent dopplerLevelLabel = EditorGUIUtility.TrTextContent("Doppler Level", "Specifies how much the pitch is changed based on the relative velocity between AudioListener and AudioSource."); diff --git a/Editor/Mono/Inspector/Avatar/AvatarMappingEditor.cs b/Editor/Mono/Inspector/Avatar/AvatarMappingEditor.cs index 9cf9bfb61a..0a401c9782 100644 --- a/Editor/Mono/Inspector/Avatar/AvatarMappingEditor.cs +++ b/Editor/Mono/Inspector/Avatar/AvatarMappingEditor.cs @@ -58,8 +58,8 @@ internal class Styles public GUIContent enforceTPose = EditorGUIUtility.TrTextContent("Enforce T-Pose"); public GUIContent bipedPose = EditorGUIUtility.TrTextContent("Biped Pose"); - public GUIContent ShowError = EditorGUIUtility.TrTextContent("Show Error (s)..."); - public GUIContent CloseError = EditorGUIUtility.TrTextContent("Close Error (s)"); + public GUIContent ShowError = EditorGUIUtility.TrTextContent("Show Error(s)..."); + public GUIContent CloseError = EditorGUIUtility.TrTextContent("Close Error(s)"); public GUIContent dotFill = EditorGUIUtility.IconContent("AvatarInspector/DotFill"); public GUIContent dotFrame = EditorGUIUtility.IconContent("AvatarInspector/DotFrame"); diff --git a/Editor/Mono/Inspector/Avatar/AvatarSetupTool.cs b/Editor/Mono/Inspector/Avatar/AvatarSetupTool.cs index 7805f7c37f..e204835ac9 100644 --- a/Editor/Mono/Inspector/Avatar/AvatarSetupTool.cs +++ b/Editor/Mono/Inspector/Avatar/AvatarSetupTool.cs @@ -631,6 +631,7 @@ private static void SetupHumanSkeleton(GameObject modelPrefab, ref HumanBone[] h { BoneWrapper bone = humanBones[i]; if (mapping.ContainsKey(i)) + { humanBoneMappings.Add( new HumanBone() { @@ -638,6 +639,8 @@ private static void SetupHumanSkeleton(GameObject modelPrefab, ref HumanBone[] h humanName = bone.humanBoneName, limit = new HumanLimit() { useDefaultValues = true } }); + humanBones[i].bone = mapping[i]; + } } humanBoneMappingArray = humanBoneMappings.ToArray(); SimpleProfiler.End(); diff --git a/Editor/Mono/Inspector/AvatarMaskInspector.cs b/Editor/Mono/Inspector/AvatarMaskInspector.cs index 833754b968..8e26aacf61 100644 --- a/Editor/Mono/Inspector/AvatarMaskInspector.cs +++ b/Editor/Mono/Inspector/AvatarMaskInspector.cs @@ -162,10 +162,10 @@ internal class AvatarMaskInspector : Editor private static class Styles { // Model Importer related options - public static GUIContent MaskDefinition = EditorGUIUtility.TrTextContent("Definition", "Choose between Create From This Model, Copy From Other Avatar. The first one create a Mask for this file and the second one use a Mask from another file to import animation."); + public static GUIContent MaskDefinition = EditorGUIUtility.TrTextContent("Definition", "Choose between Create From This Model, Copy From Other Avatar. The first one creates a Mask for this file and the second one uses a Mask from another file to import animation."); public static GUIContent[] MaskDefinitionOpt = { - EditorGUIUtility.TrTextContent("Create From This Model", "Create a Mask based on the model from this file. For Humanoid rig all the human transform are always imported and converted to muscle curve, thus they cannot be unchecked."), + EditorGUIUtility.TrTextContent("Create From This Model", "Create a Mask based on the model from this file. For Humanoid rig all the human transforms are always imported and converted to muscle curve, thus they cannot be unchecked."), EditorGUIUtility.TrTextContent("Copy From Other Mask", "Copy a Mask from another file to import animation clip."), EditorGUIUtility.TrTextContent("None ", " Import Everything") }; diff --git a/Editor/Mono/Inspector/AvatarPreview.cs b/Editor/Mono/Inspector/AvatarPreview.cs index f3817ae084..c88a36b6f1 100644 --- a/Editor/Mono/Inspector/AvatarPreview.cs +++ b/Editor/Mono/Inspector/AvatarPreview.cs @@ -897,11 +897,12 @@ protected void HandleViewTool(Event evt, EventType eventType, int id, Rect previ } } - public void DoAvatarPreviewDrag(EventType type) + public void DoAvatarPreviewDrag(Event evt, EventType type) { if (type == EventType.DragUpdated) { DragAndDrop.visualMode = DragAndDropVisualMode.Link; + evt.Use(); } else if (type == EventType.DragPerform) { @@ -913,6 +914,8 @@ public void DoAvatarPreviewDrag(EventType type) DragAndDrop.AcceptDrag(); SetPreview(newPreviewObject); } + + evt.Use(); } } @@ -1016,7 +1019,7 @@ public void DoAvatarPreview(Rect rect, GUIStyle background) int previewSceneID = GUIUtility.GetControlID(m_PreviewSceneHint, FocusType.Passive); type = evt.GetTypeForControl(previewSceneID); - DoAvatarPreviewDrag(type); + DoAvatarPreviewDrag(evt, type); HandleViewTool(evt, type, previewSceneID, previewRect); DoAvatarPreviewFrame(evt, type, previewRect); diff --git a/Editor/Mono/Inspector/BoxColliderEditor.cs b/Editor/Mono/Inspector/BoxColliderEditor.cs index f799393a69..8abf235907 100644 --- a/Editor/Mono/Inspector/BoxColliderEditor.cs +++ b/Editor/Mono/Inspector/BoxColliderEditor.cs @@ -15,7 +15,7 @@ internal class BoxColliderEditor : PrimitiveCollider3DEditor SerializedProperty m_Size; private readonly BoxBoundsHandle m_BoundsHandle = new BoxBoundsHandle(); - protected GUIContent centerContent = EditorGUIUtility.TrTextContent("Center", "The position of the Collider in the object’s local space."); + protected GUIContent centerContent = EditorGUIUtility.TrTextContent("Center", "The position of the Collider in the object's local space."); protected GUIContent sizeContent = EditorGUIUtility.TrTextContent("Size", "The size of the Collider in the X, Y, Z directions."); diff --git a/Editor/Mono/Inspector/CameraEditor.cs b/Editor/Mono/Inspector/CameraEditor.cs index 9b9a5ea68f..a81b713e6d 100644 --- a/Editor/Mono/Inspector/CameraEditor.cs +++ b/Editor/Mono/Inspector/CameraEditor.cs @@ -27,17 +27,17 @@ private static class Styles public static GUIContent background = EditorGUIUtility.TrTextContent("Background", "The Camera clears the screen to this color before rendering."); public static GUIContent projection = EditorGUIUtility.TrTextContent("Projection", "How the Camera renders perspective.\n\nChoose Perspective to render objects with perspective.\n\nChoose Orthographic to render objects uniformly, with no sense of perspective."); public static GUIContent size = EditorGUIUtility.TrTextContent("Size", "The vertical size of the camera view."); - public static GUIContent fieldOfView = EditorGUIUtility.TrTextContent("Field of View", "The camera’s view angle measured in degrees along the selected axis."); - public static GUIContent viewportRect = EditorGUIUtility.TrTextContent("Viewport Rect", "Four values that indicate where on the screen this camera view will be drawn. Measured in Viewport Coordinates (values 0–1)."); + public static GUIContent fieldOfView = EditorGUIUtility.TrTextContent("Field of View", "The camera's view angle measured in degrees along the selected axis."); + public static GUIContent viewportRect = EditorGUIUtility.TrTextContent("Viewport Rect", "Four values that indicate where on the screen this camera view will be drawn. Measured in Viewport Coordinates (values 0-1)."); public static GUIContent sensorSize = EditorGUIUtility.TrTextContent("Sensor Size", "The size of the camera sensor in millimeters."); public static GUIContent lensShift = EditorGUIUtility.TrTextContent("Lens Shift", "Offset from the camera sensor. Use these properties to simulate a shift lens. Measured as a multiple of the sensor size."); public static GUIContent physicalCamera = EditorGUIUtility.TrTextContent("Physical Camera", "Enables Physical camera mode. When checked, the field of view is calculated from properties for simulating physical attributes (focal length, sensor size, and lens shift)"); public static GUIContent cameraType = EditorGUIUtility.TrTextContent("Sensor Type", "Common sensor sizes. Choose an item to set Sensor Size, or edit Sensor Size for your custom settings."); - public static GUIContent renderingPath = EditorGUIUtility.TrTextContent("Rendering Path", "Choose a rendering method for this camera.\n\nUse Graphics Settings to use the rendering path specified in Player settings.\n\nUse Forward to render all objects with one pass per material.\n\nUse Deferred to draw all objects once without lighting and then draw the lighting of all objects at the end of the render queue.\n\nUse Legacy Vertex Lit to to render all lights in a single pass, calculated in vertices.\n\nLegacy Deferred has been deprecated."); + public static GUIContent renderingPath = EditorGUIUtility.TrTextContent("Rendering Path", "Choose a rendering method for this camera.\n\nUse Graphics Settings to use the rendering path specified in Player settings.\n\nUse Forward to render all objects with one pass per material.\n\nUse Deferred to draw all objects once without lighting and then draw the lighting of all objects at the end of the render queue.\n\nUse Legacy Vertex Lit to render all lights in a single pass, calculated in vertices.\n\nLegacy Deferred has been deprecated."); public static GUIContent focalLength = EditorGUIUtility.TrTextContent("Focal Length", "The simulated distance between the lens and the sensor of the physical camera. Larger values give a narrower field of view."); public static GUIContent allowOcclusionCulling = EditorGUIUtility.TrTextContent("Occlusion Culling", "Occlusion Culling means that objects that are hidden behind other objects are not rendered, for example if they are behind walls."); public static GUIContent allowHDR = EditorGUIUtility.TrTextContent("HDR", "High Dynamic Range gives you a wider range of light intensities, so your lighting looks more realistic. With it, you can still see details and experience less saturation even with bright light."); - public static GUIContent allowMSAA = EditorGUIUtility.TrTextContent("MSAA", "Use Multi Sample Anti-Aliasing to reduce aliasing."); + public static GUIContent allowMSAA = EditorGUIUtility.TrTextContent("MSAA", "Use Multi Sample Anti-aliasing to reduce aliasing."); public static GUIContent gateFit = EditorGUIUtility.TrTextContent("Gate Fit", "Determines how the rendered area (resolution gate) fits into the sensor area (film gate)."); public static GUIContent allowDynamicResolution = EditorGUIUtility.TrTextContent("Allow Dynamic Resolution", "Scales render textures to support dynamic resolution if the target platform/graphics API supports it."); public static GUIContent FOVAxisMode = EditorGUIUtility.TrTextContent("FOV Axis", "Field of view axis."); diff --git a/Editor/Mono/Inspector/ClothInspector.cs b/Editor/Mono/Inspector/ClothInspector.cs index 5ae644c0e4..0a59ddf08f 100644 --- a/Editor/Mono/Inspector/ClothInspector.cs +++ b/Editor/Mono/Inspector/ClothInspector.cs @@ -1369,8 +1369,6 @@ void OnPreSceneGUI() return; } - // Disable Scene view tools, so we can use our own. - Tools.current = Tool.None; if (state.ToolMode == (ToolMode)(-1)) state.ToolMode = ToolMode.Select; diff --git a/Editor/Mono/Inspector/Collider2DEditorBase.cs b/Editor/Mono/Inspector/Collider2DEditorBase.cs index afe94e682a..3ffd2c3f36 100644 --- a/Editor/Mono/Inspector/Collider2DEditorBase.cs +++ b/Editor/Mono/Inspector/Collider2DEditorBase.cs @@ -16,7 +16,7 @@ internal abstract class Collider2DEditorBase : ColliderEditorBase protected class Styles { public static readonly GUIContent s_ColliderEditDisableHelp = EditorGUIUtility.TrTextContent("Collider cannot be edited because it is driven by SpriteRenderer's tiling properties."); - public static readonly GUIContent s_AutoTilingLabel = EditorGUIUtility.TrTextContent("Auto Tiling ", " When enabled, the collider's shape will update automaticaly based on the SpriteRenderer's tiling properties"); + public static readonly GUIContent s_AutoTilingLabel = EditorGUIUtility.TrTextContent("Auto Tiling ", " When enabled, the collider's shape will update automatically based on the SpriteRenderer's tiling properties"); } private SerializedProperty m_Density; diff --git a/Editor/Mono/Inspector/CompositeCollider2DEditor.cs b/Editor/Mono/Inspector/CompositeCollider2DEditor.cs index 2b5cb66a1c..9e9cf73bda 100644 --- a/Editor/Mono/Inspector/CompositeCollider2DEditor.cs +++ b/Editor/Mono/Inspector/CompositeCollider2DEditor.cs @@ -17,6 +17,7 @@ internal class CompositeCollider2DEditor : Collider2DEditorBase private SerializedProperty m_GenerationType; private SerializedProperty m_VertexDistance; private SerializedProperty m_EdgeRadius; + private SerializedProperty m_OffsetDistance; readonly AnimBool m_ShowEdgeRadius = new AnimBool(); readonly AnimBool m_ShowManualGenerationButton = new AnimBool(); @@ -28,6 +29,7 @@ public override void OnEnable() m_GenerationType = serializedObject.FindProperty("m_GenerationType"); m_VertexDistance = serializedObject.FindProperty("m_VertexDistance"); m_EdgeRadius = serializedObject.FindProperty("m_EdgeRadius"); + m_OffsetDistance = serializedObject.FindProperty("m_OffsetDistance"); m_ShowEdgeRadius.value = targets.Where(x => (x as CompositeCollider2D).geometryType == CompositeCollider2D.GeometryType.Polygons).Count() == 0; m_ShowEdgeRadius.valueChanged.AddListener(Repaint); m_ShowManualGenerationButton.value = targets.Where(x => (x as CompositeCollider2D).generationType != CompositeCollider2D.GenerationType.Manual).Count() == 0; @@ -49,6 +51,7 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(m_GeometryType); EditorGUILayout.PropertyField(m_GenerationType); EditorGUILayout.PropertyField(m_VertexDistance); + EditorGUILayout.PropertyField(m_OffsetDistance); m_ShowManualGenerationButton.target = targets.Where(x => (x as CompositeCollider2D).generationType != CompositeCollider2D.GenerationType.Manual).Count() == 0; if (EditorGUILayout.BeginFadeGroup(m_ShowManualGenerationButton.faded)) diff --git a/Editor/Mono/Inspector/CubemapInspector.cs b/Editor/Mono/Inspector/CubemapInspector.cs index 0749b6d37f..a5878d5369 100644 --- a/Editor/Mono/Inspector/CubemapInspector.cs +++ b/Editor/Mono/Inspector/CubemapInspector.cs @@ -109,7 +109,7 @@ public override void OnInspectorGUI() bool streamingMipmaps = TextureUtil.GetCubemapStreamingMipmaps(c); if (useMipMap) { - streamingMipmaps = EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Streaming Mip Maps", "Don't load image data immediately, but wait till image data is requested from script."), streamingMipmaps); + streamingMipmaps = EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Streaming MipMaps", "Don't load image data immediately but wait till image data is requested from script."), streamingMipmaps); } bool linear = TextureUtil.GetLinearSampled(c); diff --git a/Editor/Mono/Inspector/CustomRenderTextureEditor.cs b/Editor/Mono/Inspector/CustomRenderTextureEditor.cs index 1e480b89e4..11b8675cef 100644 --- a/Editor/Mono/Inspector/CustomRenderTextureEditor.cs +++ b/Editor/Mono/Inspector/CustomRenderTextureEditor.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.IO; using AnimatedBool = UnityEditor.AnimatedValues.AnimBool; +using UnityEngine.Experimental.Rendering; namespace UnityEditor { @@ -433,8 +434,8 @@ static void SaveToDisk(MenuCommand command) int depth = texture.volumeDepth; // This has its TextureFormat helper equivalent in C++ but since we are going to try to refactor TextureFormat/RenderTextureFormat into a single type so let's not bloat Scripting APIs with stuff that will get useless soon(tm). - bool isFormatHDR = IsHDRFormat(texture.format); - bool isFloatFormat = (texture.format == RenderTextureFormat.ARGBFloat || texture.format == RenderTextureFormat.RFloat); + bool isFormatHDR = GraphicsFormatUtility.IsIEEE754Format(texture.graphicsFormat); + bool isFloatFormat = GraphicsFormatUtility.IsFloatFormat(texture.graphicsFormat); TextureFormat format = isFormatHDR ? TextureFormat.RGBAFloat : TextureFormat.RGBA32; int finalWidth = width; diff --git a/Editor/Mono/Inspector/EditMode.cs b/Editor/Mono/Inspector/EditMode.cs index 094c848b55..b4909c830d 100644 --- a/Editor/Mono/Inspector/EditMode.cs +++ b/Editor/Mono/Inspector/EditMode.cs @@ -16,34 +16,38 @@ namespace UnityEditorInternal [InitializeOnLoad] public class EditMode { + internal const int k_OwnerIdNone = 0; + private static class Styles { public static readonly GUIStyle multiButtonStyle = "Command"; public static readonly GUIStyle singleButtonStyle = "EditModeSingleButton"; } - private const string kEditModeStringKey = "EditModeState"; - private const string kPrevToolStringKey = "EditModePrevTool"; - private const string kOwnerStringKey = "EditModeOwner"; - private static bool s_Debug = false; + const string kOwnerStringKey = "EditModeOwner"; + const string kEditModeStringKey = "EditModeState"; static EditMode() { ownerID = SessionState.GetInt(kOwnerStringKey, ownerID); - editMode = (SceneViewEditMode)SessionState.GetInt(kEditModeStringKey, (int)editMode); + s_EditMode = (SceneViewEditMode)SessionState.GetInt(kEditModeStringKey, (int)s_EditMode); Selection.selectionChanged += OnSelectionChange; + EditorTools.activeToolChanging += ToolChanging; } private const float k_EditColliderbuttonWidth = 33; private const float k_EditColliderbuttonHeight = 23; private const float k_SpaceBetweenLabelAndButton = 5; + // todo Obsolete, use editModeEnded public static OnEditModeStopFunc onEditModeEndDelegate; public delegate void OnEditModeStopFunc(Editor editor); - internal static event Action editModeEnded; + // todo Obsolete, use editModeStarted public static OnEditModeStartFunc onEditModeStartDelegate; public delegate void OnEditModeStartFunc(Editor editor, SceneViewEditMode mode); + + internal static event Action editModeEnded; internal static event Action editModeStarted; private static int s_OwnerID; @@ -78,6 +82,24 @@ public enum SceneViewEditMode ParticleSystemShapeModuleScale } + static EditorTool GetTool(IToolModeOwner owner, SceneViewEditMode mode) + { + var editor = owner as Editor; + + if (editor == null) + return null; + + var editorType = editor.GetType(); + + return EditorToolContext.GetCustomEditorTool(x => + { + var tool = x as EditModeTool; + return tool != null + && tool.editorType == editorType + && tool.target == editor.target; + }, true); + } + public static bool IsOwner(Editor editor) { return IsOwner((IToolModeOwner)editor); @@ -88,7 +110,7 @@ internal static bool IsOwner(IToolModeOwner owner) return owner.GetInstanceID() == s_OwnerID; } - private static int ownerID + internal static int ownerID { get { @@ -98,40 +120,19 @@ private static int ownerID { s_OwnerID = value; SessionState.SetInt(kOwnerStringKey, s_OwnerID); - if (s_Debug) - Debug.Log("Set ownerID " + value); } } public static SceneViewEditMode editMode { - get - { - return s_EditMode; - } + get { return s_EditMode; } private set { - if (s_EditMode == SceneViewEditMode.None && value != SceneViewEditMode.None) - { - // EditorToolContext remembers the last persistent tool used - Tools.current = Tool.None; - } - else if (s_EditMode != SceneViewEditMode.None && value == SceneViewEditMode.None) - { - EditorToolContext.RestorePreviousTool(); - } s_EditMode = value; SessionState.SetInt(kEditModeStringKey, (int)s_EditMode); - if (s_Debug) - Debug.Log("Set editMode " + s_EditMode); } } - static void EndSceneViewEditing() - { - ChangeEditMode(SceneViewEditMode.None, new Bounds(Vector3.zero, Vector3.positiveInfinity), null); - } - public static void OnSelectionChange() { IToolModeOwner owner = InternalEditorUtility.GetObjectFromInstanceID(ownerID) as IToolModeOwner; @@ -140,12 +141,59 @@ public static void OnSelectionChange() QuitEditMode(); } + static void ToolChanging() + { + var previousToolType = EditorToolUtility.GetEnumWithEditorTool(EditorToolContext.activeTool); + + if (previousToolType == Tool.None && ownerID != k_OwnerIdNone) + ChangeEditModeFromToolContext(null, SceneViewEditMode.None); + } + public static void QuitEditMode() { - if (Tools.current == Tool.None && editMode != SceneViewEditMode.None) - EditorToolContext.RestorePreviousTool(); + if (ownerID != k_OwnerIdNone) + ChangeEditMode(SceneViewEditMode.None, new Bounds(Vector3.zero, Vector3.positiveInfinity), null); + } + + internal static void ChangeEditModeFromToolContext(IToolModeOwner owner, SceneViewEditMode mode) + { + // In cases of domain reloads the EditorTool can be deserialized prior to the target Inspector being + // created. The EditMode tools do not expect an editModeStarted callback on reloads. + if (owner == null && mode != SceneViewEditMode.None) + { + editMode = mode; + return; + } + + IToolModeOwner oldOwner = InternalEditorUtility.GetObjectFromInstanceID(ownerID) as IToolModeOwner; + + editMode = mode; + + if (oldOwner != null) + { + if (onEditModeEndDelegate != null && oldOwner is Editor) + onEditModeEndDelegate(oldOwner as Editor); + + if (editModeEnded != null) + editModeEnded(oldOwner); + } - EndSceneViewEditing(); + ownerID = mode != SceneViewEditMode.None ? owner.GetInstanceID() : k_OwnerIdNone; + + if (editMode != SceneViewEditMode.None) + { + if (onEditModeStartDelegate != null && owner is Editor) + onEditModeStartDelegate(owner as Editor, editMode); + + if (editModeStarted != null) + editModeStarted(owner, editMode); + } + + EditModeChanged((mode != SceneViewEditMode.None && owner != null) + ? owner.GetWorldBoundsOfTargets() + : new Bounds(Vector3.zero, Vector3.positiveInfinity)); + + InspectorWindow.RepaintAllInspectors(); } [Obsolete("Obsolete msg (UnityUpgradable) -> UnityEditor.EditorTools.EditorTools.RestorePreviousTool()")] @@ -155,12 +203,6 @@ public static void ResetToolToPrevious() EditorToolContext.RestorePreviousTool(); } - static void DetectMainToolChange() - { - if (Tools.current != Tool.None && editMode != SceneViewEditMode.None) - EndSceneViewEditing(); - } - [Obsolete("Use signature passing Func rather than Bounds.")] public static void DoEditModeInspectorModeButton(SceneViewEditMode mode, string label, GUIContent icon, Bounds bounds, Editor caller) { @@ -179,8 +221,6 @@ internal static void DoEditModeInspectorModeButton(SceneViewEditMode mode, strin private static void DoEditModeInspectorModeButton(SceneViewEditMode mode, string label, GUIContent icon, Func getBoundsOfTargets, IToolModeOwner owner) { - DetectMainToolChange(); - Rect rect = EditorGUILayout.GetControlRect(true, k_EditColliderbuttonHeight, Styles.singleButtonStyle); Rect buttonRect = new Rect(rect.xMin + EditorGUIUtility.labelWidth, rect.yMin, k_EditColliderbuttonWidth, k_EditColliderbuttonHeight); @@ -193,8 +233,7 @@ private static void DoEditModeInspectorModeButton(SceneViewEditMode mode, string labelSize.x, rect.height); - int callerID = owner.GetInstanceID(); - bool modeEnabled = editMode == mode && ownerID == callerID; + bool modeEnabled = IsOwner(owner); EditorGUI.BeginChangeCheck(); @@ -229,8 +268,6 @@ internal static void DoInspectorToolbar(SceneViewEditMode[] modes, GUIContent[] private static void DoInspectorToolbar(SceneViewEditMode[] modes, GUIContent[] guiContents, Func getBoundsOfTargets, IToolModeOwner owner) { - DetectMainToolChange(); - int callerID = owner.GetInstanceID(); int selectedIndex = ArrayUtility.IndexOf(modes, editMode); @@ -260,28 +297,26 @@ internal static void ChangeEditMode(SceneViewEditMode mode, IToolModeOwner owner internal static void ChangeEditMode(SceneViewEditMode mode, Bounds bounds, IToolModeOwner owner) { - IToolModeOwner oldOwner = InternalEditorUtility.GetObjectFromInstanceID(ownerID) as IToolModeOwner; - - editMode = mode; + if (mode == SceneViewEditMode.None) + { + if (s_EditMode != SceneViewEditMode.None && (EditorToolContext.activeTool is EditModeTool || EditorToolContext.activeTool is NoneTool)) + EditorTools.RestorePreviousTool(); - ownerID = mode != SceneViewEditMode.None ? owner.GetInstanceID() : 0; + return; + } - if (onEditModeEndDelegate != null && oldOwner is Editor) - onEditModeEndDelegate(oldOwner as Editor); - if (editModeEnded != null) - editModeEnded(oldOwner); + var tool = GetTool(owner, mode); - if (editMode != SceneViewEditMode.None) + if (tool != null) { - if (onEditModeStartDelegate != null && owner is Editor) - onEditModeStartDelegate(owner as Editor, editMode); - if (editModeStarted != null) - editModeStarted(owner, editMode); + EditorTools.SetActiveTool(tool); + } + else + { + // SceneViewEditModeTool doesn't exist, use old path + EditorTools.SetActiveTool(); + ChangeEditModeFromToolContext(owner, mode); } - - EditModeChanged(bounds); - - InspectorWindow.RepaintAllInspectors(); } // We make sure edited object is seen by the camera. We need object bounds to do that check. diff --git a/Editor/Mono/Inspector/Editor.cs b/Editor/Mono/Inspector/Editor.cs index 510bdef1a3..d31fd320c0 100644 --- a/Editor/Mono/Inspector/Editor.cs +++ b/Editor/Mono/Inspector/Editor.cs @@ -328,7 +328,25 @@ public partial class Editor : ScriptableObject, IPreviewable, IToolModeOwner internal SerializedObject m_SerializedObject = null; internal SerializedProperty m_EnabledProperty = null; - internal InspectorMode m_InspectorMode = InspectorMode.Normal; + private InspectorMode m_InspectorMode = InspectorMode.Normal; + internal InspectorMode inspectorMode + { + get + { + return m_InspectorMode; + } + set + { + if (m_InspectorMode != value) + { + m_InspectorMode = value; + m_SerializedObject = null; + m_EnabledProperty = null; + } + } + } + + internal const float kLineHeight = 16; internal bool hideInspector = false; @@ -454,6 +472,14 @@ internal bool isInspectorDirty set { m_IsDirty = value ? 1 : 0; } } + public static Editor CreateEditorWithContext(UnityObject[] targetObjects, UnityObject context, [DefaultValue("null")] Type editorType) + { + if (editorType != null && !editorType.IsSubclassOf(typeof(Editor))) + throw new ArgumentException($"Editor type '{editorType}' does not derive from UnityEditor.Editor", "editorType"); + + return CreateEditorWithContextInternal(targetObjects, context, editorType); + } + [ExcludeFromDocs] public static Editor CreateEditorWithContext(UnityObject[] targetObjects, UnityObject context) { @@ -529,7 +555,7 @@ internal virtual SerializedObject GetSerializedObjectInternal() if (m_SerializedObject == null) { m_SerializedObject = new SerializedObject(targets, m_Context); - m_SerializedObject.inspectorMode = m_InspectorMode; + m_SerializedObject.inspectorMode = inspectorMode; m_EnabledProperty = m_SerializedObject.FindProperty("m_Enabled"); } @@ -958,17 +984,24 @@ public virtual void ReloadPreviewInstances() preview.ReloadPreviewInstances(); } + // Some custom editors manually display SerializedObjects with only private properties + // Setting this to true allows them to properly toggling the visibility via the standard header foldout + internal bool alwaysAllowExpansion {get; set;} + // Auxiliary method that determines whether this editor has a set of public properties and, as thus, // can be expanded via a foldout. This is used in order to determine whether a foldout needs to be // rendered on top of the inspector title bar or not. Some examples of editors that don't require // a foldout are GUI Layer and Audio Listener. internal bool CanBeExpandedViaAFoldout() { + if (alwaysAllowExpansion) + return true; + if (m_SerializedObject == null) m_SerializedObject = new SerializedObject(targets, m_Context); else m_SerializedObject.Update(); - m_SerializedObject.inspectorMode = m_InspectorMode; + m_SerializedObject.inspectorMode = inspectorMode; SerializedProperty property = m_SerializedObject.GetIterator(); diff --git a/Editor/Mono/Inspector/EditorDragging.cs b/Editor/Mono/Inspector/EditorDragging.cs index 2d7f10ee01..138465c2e7 100644 --- a/Editor/Mono/Inspector/EditorDragging.cs +++ b/Editor/Mono/Inspector/EditorDragging.cs @@ -51,31 +51,62 @@ public void HandleDraggingToEditor(Editor[] editors, int editorIndex, Rect dragR HandleEditorDragging(editors, editorIndex, targetRect, markerY, false); } + int m_BottomAreaDropIndex = -1; + Rect m_BottomArea; + public void HandleDraggingInBottomArea(Editor[] editors, Rect bottomRect, Rect contentRect) { + HandleNativeDragDropInBottomArea(editors, bottomRect); + if (m_LastIndex >= 0 && m_LastIndex < editors.Length) { m_BottomArea = bottomRect; + m_BottomAreaDropIndex = m_LastIndex; HandleEditorDragging(editors, m_LastIndex, bottomRect, contentRect.yMax, true); } else { + m_BottomAreaDropIndex = -1; m_BottomArea = Rect.zero; } } - Rect m_BottomArea; - - internal void HandleDragPerformInBottomArea(Editor[] editors, Rect targetRect) + internal void HandleDragPerformInBottomArea(Editor[] editors, Rect bottomRect, Rect targetRect) { + HandleNativeDragDropInBottomArea(editors, bottomRect); + if (m_LastIndex >= 0 && m_LastIndex < editors.Length) { HandleEditorDragging(editors, m_LastIndex, GetTargetRect(targetRect), targetRect.yMax, true); } + m_BottomAreaDropIndex = -1; m_BottomArea = Rect.zero; } + void HandleNativeDragDropInBottomArea(Editor[] editors, Rect rect) + { + if (!DraggingOverRect(rect)) + { + return; + } + + Editor editor = InspectorWindowUtils.GetFirstNonImportInspectorEditor(editors); + if (editor == null) + { + return; + } + + DragAndDrop.visualMode = InternalEditorUtility.InspectorWindowDrag(editor.targets, Event.current.type == EventType.DragPerform); + + if (Event.current.type == EventType.DragPerform) + { + DragAndDrop.AcceptDrag(); + m_TargetIndex = -1; + GUIUtility.ExitGUI(); + } + } + void HandleEditorDragging(Editor[] editors, int editorIndex, Rect targetRect, float markerY, bool bottomTarget) { var evt = Event.current; @@ -102,6 +133,7 @@ void HandleEditorDragging(Editor[] editors, int editorIndex, Rect targetRect, fl DragAndDrop.SetGenericData(k_DraggingModeKey, draggingMode); } + if (draggingMode.Value != DraggingMode.NotApplicable) { if (bottomTarget) @@ -128,7 +160,7 @@ void HandleEditorDragging(Editor[] editors, int editorIndex, Rect targetRect, fl } } - if (m_TargetAbove && m_InspectorWindow.EditorHasLargeHeader(m_TargetIndex, editors)) + if (m_TargetAbove && InspectorWindow.EditorHasLargeHeader(m_TargetIndex, editors)) { m_TargetIndex--; while (m_TargetIndex >= 0 && m_InspectorWindow.ShouldCullEditor(editors, m_TargetIndex)) @@ -187,10 +219,10 @@ void HandleEditorDragging(Editor[] editors, int editorIndex, Rect targetRect, fl break; case EventType.Repaint: - if (m_TargetIndex != -1 && + if (m_TargetIndex != -1 && editorIndex == m_TargetIndex && (targetRect.Contains(evt.mousePosition) || m_BottomArea.Contains(GUIClip.UnclipToWindow(evt.mousePosition)) && - editorIndex == editors.Length - 1)) + m_BottomAreaDropIndex == editors.Length - 1)) { Styles.insertionMarker.Draw(GetMarkerRect(targetRect, markerY, m_TargetAbove), false, false, false, false); } @@ -198,6 +230,11 @@ void HandleEditorDragging(Editor[] editors, int editorIndex, Rect targetRect, fl } } + static bool DraggingOverRect(Rect rect) + { + return (Event.current.type == EventType.DragUpdated || Event.current.type == EventType.DragPerform) && rect.Contains(Event.current.mousePosition); + } + void HandleDragPerformEvent(Editor[] editors, Event evt, ref int targetIndex) { if (targetIndex != -1) @@ -255,8 +292,14 @@ void HandleDragPerformEvent(Editor[] editors, Event evt, ref int targetIndex) // Move added components relative to target components if (!ComponentUtility.MoveComponentsRelativeToComponents(addedComponents, targetComponents, m_TargetAbove)) { - // Revert added components if move operation fails (e.g. user aborts when asked to break prefab instance) + // Ensure we have the same selection after calling RevertAllDownToGroup below (MoveComponentsRelativeToComponents can have opened a Prefab in Prefab Mode and changed selection to that root) + var wantedSelectedGameObject = Selection.activeGameObject; + + // Revert added components if move operation fails (e.g. user has been shown the dialog with 'prefab instance restructuring is not posssible' or object is not editable) Undo.RevertAllDownToGroup(undoGroup); + + if (wantedSelectedGameObject != Selection.activeGameObject) + Selection.activeGameObject = wantedSelectedGameObject; } } } diff --git a/Editor/Mono/Inspector/EditorElement.cs b/Editor/Mono/Inspector/EditorElement.cs new file mode 100644 index 0000000000..d39a8722d8 --- /dev/null +++ b/Editor/Mono/Inspector/EditorElement.cs @@ -0,0 +1,435 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditorInternal; +using UnityEngine; +using UnityEngine.UIElements; +using Object = UnityEngine.Object; + +namespace UnityEditor.UIElements +{ + internal class EditorElement : VisualElement + { + readonly InspectorWindow inspectorWindow; + + internal Editor[] m_Editors => inspectorWindow.tracker.activeEditors; + int m_EditorIndex; + public Editor editor + { + get + { + if (m_EditorIndex < m_Editors.Length) + { + return m_Editors[m_EditorIndex]; + } + return null; + } + } + + private bool IsEditorValid() + { + if (m_EditorIndex < m_Editors.Length) + { + return m_Editors[m_EditorIndex] != null; + } + return false; + } + + Rect m_DragRect; + Rect m_ContentRect; + + VisualElement m_PrefabElement; + + IMGUIContainer m_Header; + internal InspectorElement m_InspectorElement { get; private set; } + IMGUIContainer m_Footer; + + static class Styles + { + public static GUIStyle importedObjectsHeaderStyle = new GUIStyle("IN BigTitle"); + + static Styles() + { + importedObjectsHeaderStyle.font = EditorStyles.label.font; + importedObjectsHeaderStyle.fontSize = EditorStyles.label.fontSize; + importedObjectsHeaderStyle.alignment = TextAnchor.UpperLeft; + } + } + + internal EditorElement(int editorIndex, InspectorWindow iw) + { + m_EditorIndex = editorIndex; + inspectorWindow = iw; + + Init(); + + Add(m_Header); + // If the editor targets contain many target and the multi editing is not supported, we should not add this inspector. + // However, the header and footer are kept since these are showing information regarding this state. + if ((editor.targets.Length <= 1) || (iw.IsMultiEditingSupported(editor, editor.target))) + { + Add(m_InspectorElement); + } + + Add(m_Footer); + } + + void Init() + { + Object editorTarget = editor.targets[0]; + string editorTitle = ObjectNames.GetInspectorTitle(editorTarget); + + var inspectorElementMode = InspectorElement.GetModeFromInspectorMode(inspectorWindow.inspectorMode); + if (inspectorWindow.m_UseUIElementsDefaultInspector) + inspectorElementMode &= ~(InspectorElement.Mode.IMGUIDefault); + + m_InspectorElement = new InspectorElement(editor, inspectorElementMode) + { + focusable = false + }; + + + m_Header = BuildHeaderElement(editorTitle); + m_Footer = BuildFooterElement(editorTitle); + + m_InspectorElement.name = editorTitle + "Inspector"; + m_InspectorElement.style.paddingBottom = InspectorWindow.kEditorElementPaddingBottom; + + if (EditorNeedsVerticalOffset(editorTarget)) + { + // This is madness + m_InspectorElement.cacheAsBitmap = false; + m_InspectorElement.style.overflow = Overflow.Hidden; + } + } + + internal void Reinit(int editorIndex) + { + Object editorTarget = editor.targets[0]; + string editorTitle = ObjectNames.GetInspectorTitle(editorTarget); + + m_EditorIndex = editorIndex; + + m_Header.onGUIHandler = HeaderOnGUI; + m_Footer.onGUIHandler = FooterOnGUI; + m_InspectorElement.editor = editor; + + name = editorTitle; + m_InspectorElement.name = editorTitle + "Inspector"; + m_Header.name = editorTitle + "Header"; + m_Footer.name = editorTitle + "Footer"; + } + + internal void AddPrefabComponent(VisualElement comp) + { + if (m_PrefabElement != null) + { + m_PrefabElement.RemoveFromHierarchy(); + m_PrefabElement = null; + } + + if (comp != null) + { + m_PrefabElement = comp; + Insert(0, m_PrefabElement); + } + } + + #region Header + + IMGUIContainer BuildHeaderElement(string editorTitle) + { + //Create and IMGUIContainer to enclose the header + // This also needs to validate the state of the editor tracker (stuff that was already done in the original DrawEditors + var headerElement = inspectorWindow.CreateIMGUIContainer(HeaderOnGUI, editorTitle + "Header"); + return headerElement; + } + + private static UQueryState ImguiContainersQuery = new UQueryBuilder(null).SingleBaseType().Build(); + + + internal static void InvalidateIMGUILayouts(VisualElement element) + { + if (element != null) + { + var q = ImguiContainersQuery.RebuildOn(element); + q.ForEach(e => e.MarkDirtyLayout()); + } + } + + void HeaderOnGUI() + { + if (!IsEditorValid()) + { + SetElementVisible(m_InspectorElement, false); + return; + } + + var target = editor.target; + + // Avoid drawing editor if native target object is not alive, unless it's a MonoBehaviour/ScriptableObject + // We want to draw the generic editor with a warning about missing/invalid script + // Case 891450: + // - ActiveEditorTracker will automatically create editors for materials of components on tracked game objects + // - UnityEngine.UI.Mask will destroy this material in OnDisable (e.g. disabling it with the checkbox) causing problems when drawing the material editor + if (target == null && !NativeClassExtensionUtilities.ExtendsANativeType(target)) + { + SetElementVisible(m_InspectorElement, false); + return; + } + + bool wasVisible = inspectorWindow.WasEditorVisible(m_Editors, m_EditorIndex, target); + + GUIUtility.GetControlID(target.GetInstanceID(), FocusType.Passive); + EditorGUIUtility.ResetGUIState(); + + if (editor.target is AssetImporter) + inspectorWindow.editorsWithImportedObjectLabel.Add(m_EditorIndex + 1); + + //set the current PropertyHandlerCache to the current editor + ScriptAttributeUtility.propertyHandlerCache = editor.propertyHandlerCache; + using (new InspectorWindowUtils.LayoutGroupChecker()) + { + m_DragRect = DrawEditorHeader(target, ref wasVisible); + } + + if (GUI.changed) + { + // If the header changed something, we must trigger a layout calculating on imgui children + // Fixes Material editor toggling layout issues (case 1148706) + InvalidateIMGUILayouts(this); + } + + if (wasVisible != IsElementVisible(m_InspectorElement)) + { + SetElementVisible(m_InspectorElement, wasVisible); + } + + var multiEditingSupported = inspectorWindow.IsMultiEditingSupported(editor, target); + + if (!multiEditingSupported && wasVisible) + { + GUILayout.Label("Multi-object editing not supported.", EditorStyles.helpBox); + return; + } + + InspectorWindowUtils.DisplayDeprecationMessageIfNecessary(editor); + + // Reset dirtiness when repainting + if (Event.current.type == EventType.Repaint) + { + editor.isInspectorDirty = false; + } + + bool excludedClass = InspectorWindowUtils.IsExcludedClass(target); + if (excludedClass) + EditorGUILayout.HelpBox( + "The module which implements this component type has been force excluded in player settings. This object will be removed in play mode and from any builds you make.", + MessageType.Warning); + + if (IsElementVisible(m_InspectorElement)) + { + m_ContentRect = m_InspectorElement.layout; + } + else + { + Rect r = m_Header.layout; + r.y = r.y + r.height - 1; + r.height = kFooterDefaultHeight; + m_ContentRect = r; + } + } + + Rect DrawEditorHeader(Object target, ref bool wasVisible) + { + var largeHeader = DrawEditorLargeHeader(ref wasVisible); + + // Dragging handle used for editor reordering + var dragRect = largeHeader + ? new Rect() + : DrawEditorSmallHeader(target, wasVisible); + return dragRect; + } + + bool DrawEditorLargeHeader(ref bool wasVisible) + { + if (!IsEditorValid()) + { + return true; + } + + bool largeHeader = InspectorWindow.EditorHasLargeHeader(m_EditorIndex, m_Editors); + + // Draw large headers before we do the culling of unsupported editors below, + // so the large header is always shown even when the editor can't be. + if (largeHeader) + { + String message = String.Empty; + bool IsOpenForEdit = editor.IsOpenForEdit(out message); + wasVisible = true; + + if (inspectorWindow.editorsWithImportedObjectLabel.Contains(m_EditorIndex)) + { + var importedObjectBarRect = GUILayoutUtility.GetRect(16, 16); + importedObjectBarRect.height = 17; + + var headerText = m_Editors[0] is PrefabImporterEditor ? "Root in Prefab Asset" : "Imported Object"; + GUILayout.Label(headerText, Styles.importedObjectsHeaderStyle, GUILayout.ExpandWidth(true)); + GUILayout.Space(-7f); // Ensures no spacing between this header and the next header + } + + // Header + using (new EditorGUI.DisabledScope(!IsOpenForEdit)) // Only disable the entire header if the asset is locked by VCS + { + editor.DrawHeader(); + } + } + + return largeHeader; + } + + // Draw small headers (the header above each component) after the culling above + // so we don't draw a component header for all the components that can't be shown. + Rect DrawEditorSmallHeader(Object target, bool wasVisible) + { + var currentEditor = editor; + + if (currentEditor == null) + return GUILayoutUtility.GetLastRect(); + + // ensure first component's title bar is flush with the header + if (EditorNeedsVerticalOffset(target)) + { + // TODO: Check if we can fix this in the GameObjectInspector instead + GUILayout.Space( + -1f // move back up so line overlaps + - EditorStyles.inspectorBig.margin.bottom - + EditorStyles.inspectorTitlebar.margin.top // move back up margins + ); + } + + using (new EditorGUI.DisabledScope(!currentEditor.IsEnabled())) + { + bool isVisible = EditorGUILayout.InspectorTitlebar(wasVisible, currentEditor); + if (wasVisible != isVisible) + { + inspectorWindow.tracker.SetVisible(m_EditorIndex, isVisible ? 1 : 0); + InternalEditorUtility.SetIsInspectorExpanded(target, isVisible); + if (isVisible) + { + inspectorWindow.lastInteractedEditor = currentEditor; + } + else if (inspectorWindow.lastInteractedEditor == currentEditor) + { + inspectorWindow.lastInteractedEditor = null; + } + } + } + return GUILayoutUtility.GetLastRect(); + } + + private bool IsElementVisible(VisualElement ve) + { + return (ve.resolvedStyle.display == DisplayStyle.Flex); + } + + internal static void SetElementVisible(InspectorElement ve, bool visible) + { + if (visible) + { + ve.style.display = DisplayStyle.Flex; + SetInspectorElementChildIMGUIContainerFocusable(ve, true); + } + else + { + ve.style.display = DisplayStyle.None; + SetInspectorElementChildIMGUIContainerFocusable(ve, false); + } + } + + static void SetInspectorElementChildIMGUIContainerFocusable(InspectorElement ve, bool focusable) + { + foreach (var child in ve.Children()) + { + var imguiContainer = child as IMGUIContainer; + if (imguiContainer != null) + { + imguiContainer.focusable = focusable; + } + } + } + + #endregion Header + + #region Footer + const float kFooterDefaultHeight = 3; + IMGUIContainer BuildFooterElement(string editorTitle) + { + IMGUIContainer footerElement = inspectorWindow.CreateIMGUIContainer(FooterOnGUI, editorTitle + "Footer"); + footerElement.style.height = kFooterDefaultHeight; + return footerElement; + } + + void FooterOnGUI() + { + var ed = editor; + + if (ed == null) + { + return; + } + + m_ContentRect.y = -m_ContentRect.height; + inspectorWindow.editorDragging.HandleDraggingToEditor(m_Editors, m_EditorIndex, m_DragRect, m_ContentRect); + HandleComponentScreenshot(m_ContentRect, ed); + + var target = ed.target; + var comp = target as Component; + + if (EditorGUI.ShouldDrawOverrideBackground(ed.targets, Event.current, comp)) + { + var rect = GUILayoutUtility.kDummyRect; + bool wasVisible = inspectorWindow.WasEditorVisible(m_Editors, m_EditorIndex, target); + // if the inspector is currently visible then the override background drawn by the footer needs to be slightly larger than if the inspector is collapsed + if (wasVisible) + { + rect.y -= 1; + rect.height += 1; + } + else + { + rect.y += 1; + rect.height -= 1; + } + + EditorGUI.DrawOverrideBackground(rect, true); + } + } + + void HandleComponentScreenshot(Rect content, Editor editor) + { + if (ScreenShots.s_TakeComponentScreenshot) + { + content.yMin -= 16; + if (content.Contains(Event.current.mousePosition)) + { + Rect globalComponentRect = GUIClip.Unclip(content); + globalComponentRect.position = + globalComponentRect.position + inspectorWindow.m_Parent.screenPosition.position; + ScreenShots.ScreenShotComponent(globalComponentRect, editor.target); + } + } + } + + #endregion Footer + + internal bool EditorNeedsVerticalOffset(Object target) + { + return m_EditorIndex > 0 && IsEditorValid() && m_Editors[m_EditorIndex - 1].target is GameObject && target is Component; + } + } +} diff --git a/Editor/Mono/Inspector/EditorSettingsInspector.cs b/Editor/Mono/Inspector/EditorSettingsInspector.cs index bdce751a0e..85512514e4 100644 --- a/Editor/Mono/Inspector/EditorSettingsInspector.cs +++ b/Editor/Mono/Inspector/EditorSettingsInspector.cs @@ -34,10 +34,11 @@ class Content public static GUIContent workOffline = EditorGUIUtility.TrTextContent("Work Offline"); public static GUIContent allowAsyncUpdate = EditorGUIUtility.TrTextContent("Allow Async Update"); public static GUIContent showFailedCheckouts = EditorGUIUtility.TrTextContent("Show Failed Checkouts"); + public static GUIContent overwriteFailedCheckoutAssets = EditorGUIUtility.TrTextContent("Overwrite Failed Checkout Assets", "When on, assets that can not be checked out will get saved anyway."); public static GUIContent assetSerialization = EditorGUIUtility.TrTextContent("Asset Serialization"); - public static GUIContent defaultBehaviorMode = EditorGUIUtility.TrTextContent("Default Behavior Mode"); + public static GUIContent defaultBehaviorMode = EditorGUIUtility.TrTextContent("Default Behaviour Mode"); public static GUIContent spritePacker = EditorGUIUtility.TrTextContent("Sprite Packer"); public static GUIContent cSharpProjectGeneration = EditorGUIUtility.TrTextContent("C# Project Generation"); @@ -45,7 +46,7 @@ class Content public static GUIContent rootNamespace = EditorGUIUtility.TrTextContent("Root namespace"); public static GUIContent etcTextureCompressor = EditorGUIUtility.TrTextContent("ETC Texture Compressor"); - public static GUIContent behavior = EditorGUIUtility.TrTextContent("Behavior"); + public static GUIContent behavior = EditorGUIUtility.TrTextContent("Behaviour"); public static GUIContent fast = EditorGUIUtility.TrTextContent("Fast"); public static GUIContent normal = EditorGUIUtility.TrTextContent("Normal"); public static GUIContent best = EditorGUIUtility.TrTextContent("Best"); @@ -58,6 +59,9 @@ class Content public static GUIContent streamingSettings = EditorGUIUtility.TrTextContent("Streaming Settings"); public static GUIContent enablePlayModeTextureStreaming = EditorGUIUtility.TrTextContent("Enable Texture Streaming In Play Mode", "Texture Streaming must be enabled in Quality Settings for mipmap streaming to function in Play Mode"); public static GUIContent enableEditModeTextureStreaming = EditorGUIUtility.TrTextContent("Enable Texture Streaming In Edit Mode", "Texture Streaming must be enabled in Quality Settings for mipmap streaming to function in Edit Mode"); + + public static GUIContent shaderCompilation = EditorGUIUtility.TrTextContent("Shader Compilation"); + public static GUIContent asyncShaderCompilation = EditorGUIUtility.TrTextContent("Asynchronous Shader Compilation", "Enables async shader compilation in Game and Scene view. Async compilation for custom editor tools can be achieved via script API and is not affected by this option."); } struct PopupElement @@ -187,6 +191,8 @@ public PopupElement(string content, bool requiresTeamLicense) SerializedProperty m_EnableTextureStreamingInPlayMode; SerializedProperty m_EnableTextureStreamingInEditMode; + SerializedProperty m_AsyncShaderCompilation; + public void OnEnable() { Plugin[] availvc = Plugin.availablePlugins; @@ -205,6 +211,8 @@ public void OnEnable() m_EnableTextureStreamingInPlayMode = serializedObject.FindProperty("m_EnableTextureStreamingInPlayMode"); m_EnableTextureStreamingInEditMode = serializedObject.FindProperty("m_EnableTextureStreamingInEditMode"); + + m_AsyncShaderCompilation = serializedObject.FindProperty("m_AsyncShaderCompilation"); } public void OnDisable() @@ -374,7 +382,10 @@ public override void OnInspectorGUI() } if (Provider.hasCheckoutSupport) + { EditorUserSettings.showFailedCheckout = EditorGUILayout.Toggle(Content.showFailedCheckouts, EditorUserSettings.showFailedCheckout); + EditorUserSettings.overwriteFailedCheckoutAssets = EditorGUILayout.Toggle(Content.overwriteFailedCheckoutAssets, EditorUserSettings.overwriteFailedCheckoutAssets); + } GUI.enabled = editorEnabled; @@ -451,6 +462,7 @@ public override void OnInspectorGUI() DoEtcTextureCompressionSettings(); DoLineEndingsSettings(); DoStreamingSettings(); + DoShaderCompilationSettings(); serializedObject.ApplyModifiedProperties(); } @@ -514,6 +526,14 @@ private void DoStreamingSettings() EditorGUILayout.PropertyField(m_EnableTextureStreamingInEditMode, Content.enableEditModeTextureStreaming); } + private void DoShaderCompilationSettings() + { + GUILayout.Space(10); + GUILayout.Label(Content.shaderCompilation, EditorStyles.boldLabel); + + EditorGUILayout.PropertyField(m_AsyncShaderCompilation, Content.asyncShaderCompilation); + } + static int GetIndexById(DevDevice[] elements, string id, int defaultIndex) { for (int i = 0; i < elements.Length; i++) diff --git a/Editor/Mono/Inspector/GameObjectInspector.cs b/Editor/Mono/Inspector/GameObjectInspector.cs index 5ec350061f..653d55c2b0 100644 --- a/Editor/Mono/Inspector/GameObjectInspector.cs +++ b/Editor/Mono/Inspector/GameObjectInspector.cs @@ -126,6 +126,7 @@ public void Dispose() bool m_IsMissing; bool m_IsPrefabInstanceAnyRoot; bool m_IsPrefabInstanceOutermostRoot; + bool m_IsAssetRoot; bool m_AllOfSamePrefabType = true; public void OnEnable() @@ -158,6 +159,7 @@ void CalculatePrefabStatus() m_IsPrefabInstanceAnyRoot = true; m_IsPrefabInstanceOutermostRoot = true; m_AllOfSamePrefabType = true; + m_IsAssetRoot = false; PrefabAssetType firstType = PrefabUtility.GetPrefabAssetType(targets[0]); PrefabInstanceStatus firstStatus = PrefabUtility.GetPrefabInstanceStatus(targets[0]); @@ -174,8 +176,14 @@ void CalculatePrefabStatus() m_IsPrefabInstanceAnyRoot = false; // Conservative is false if any is false if (!m_IsPrefabInstanceAnyRoot || !PrefabUtility.IsOutermostPrefabInstanceRoot(go)) m_IsPrefabInstanceOutermostRoot = false; // Conservative is false if any is false + if (PrefabUtility.IsPartOfPrefabAsset(go)) + { m_IsAsset = true; // Conservative is true if any is true + if (go.transform.parent == null) + m_IsAssetRoot = true; + } + if (m_IsAsset && PrefabUtility.IsPartOfImmutablePrefab(go)) m_ImmutableSelf = true; // Conservative is true if any is true GameObject originalSourceOrVariant = PrefabUtility.GetOriginalSourceOrVariantRoot(go); @@ -196,6 +204,12 @@ void OnDisable() m_PreviewCache = null; } + internal override void OnForceReloadInspector() + { + base.OnForceReloadInspector(); + CalculatePrefabStatus(); + } + void ClearPreviewCache() { foreach (var texture in m_PreviewCache.Values) @@ -269,8 +283,12 @@ internal bool DrawInspector() } EditorGUILayout.EndHorizontal(); - // Name - EditorGUILayout.DelayedTextField(m_Name, GUIContent.none); + // Disable the name field of root GO in prefab asset + using (new EditorGUI.DisabledScope(m_IsAsset && m_IsAssetRoot)) + { + // Name + EditorGUILayout.DelayedTextField(m_Name, GUIContent.none); + } // Static flags toggle DoStaticToggleField(go); @@ -307,7 +325,7 @@ internal bool DrawInspector() private void DoPrefabButtons() { - if (!m_IsPrefabInstanceAnyRoot) + if (!m_IsPrefabInstanceAnyRoot || m_IsAsset) return; using (new EditorGUI.DisabledScope(m_PlayModeObjects)) @@ -818,7 +836,9 @@ public override void OnPreviewGUI(Rect r, GUIStyle background) DoRenderPreview(); previewUtility.EndAndDrawPreview(r); var copy = new RenderTexture(previewUtility.renderTexture); - Graphics.CopyTexture(previewUtility.renderTexture, copy); + var previous = RenderTexture.active; + Graphics.Blit(previewUtility.renderTexture, copy); + RenderTexture.active = previous; m_PreviewCache.Add(referenceTargetIndex, copy); } } diff --git a/Editor/Mono/Inspector/GenericInspector.cs b/Editor/Mono/Inspector/GenericInspector.cs index cb3445a6f9..97f0c41174 100644 --- a/Editor/Mono/Inspector/GenericInspector.cs +++ b/Editor/Mono/Inspector/GenericInspector.cs @@ -16,8 +16,8 @@ private enum OptimizedBlockState } private AudioFilterGUI m_AudioFilterGUI; - private float m_LastHeight; + private Rect m_LastVisibleRect; private OptimizedBlockState m_OptimizedBlockState = OptimizedBlockState.CheckOptimizedBlock; internal override bool GetOptimizedGUIBlock(bool isDirty, bool isVisible, out float height) @@ -26,7 +26,6 @@ internal override bool GetOptimizedGUIBlock(bool isDirty, bool isVisible, out fl // Don't use optimizedGUI for audio filters var behaviour = target as MonoBehaviour; - var generatorAsset = ScriptGeneratorAsset.FromMonoBehaviour(behaviour); if (behaviour != null && AudioUtil.HasAudioCallback(behaviour) && AudioUtil.GetCustomFilterChannelCount(behaviour) > 0) return false; @@ -53,74 +52,58 @@ internal override bool GetOptimizedGUIBlock(bool isDirty, bool isVisible, out fl // Update serialized object representation if (m_SerializedObject == null) - m_SerializedObject = new SerializedObject(targets, m_Context) {inspectorMode = m_InspectorMode}; + m_SerializedObject = new SerializedObject(targets, m_Context) {inspectorMode = inspectorMode}; else { m_SerializedObject.Update(); - m_SerializedObject.inspectorMode = m_InspectorMode; + m_SerializedObject.inspectorMode = inspectorMode; } height = 0; SerializedProperty property = m_SerializedObject.GetIterator(); - var isInspectorModeNormal = m_InspectorMode == InspectorMode.Normal; - var isAssetBased = behaviour != null && generatorAsset != null; - while (property.NextVisible(height <= 0)) + bool childrenAreExpanded = true; + while (property.NextVisible(childrenAreExpanded)) { - if (isAssetBased && "m_Script" == property.propertyPath && isInspectorModeNormal) - continue; - if (!isAssetBased && "m_GeneratorAsset" == property.propertyPath && isInspectorModeNormal) - continue; var handler = ScriptAttributeUtility.GetHandler(property); - if (!handler.CanCacheInspectorGUI(property)) - return ResetOptimizedBlock(OptimizedBlockState.NoOptimizedBlock); + height += handler.GetHeight(property, null, false) + EditorGUI.kControlVerticalSpacing; - // Allocate height for control plus spacing below it - height += handler.GetHeight(property, null, true) + EditorGUI.kControlVerticalSpacing; + childrenAreExpanded = property.isExpanded; } - // Allocate height for spacing above first control - if (height > 0) - height += EditorGUI.kControlVerticalSpacing; - m_LastHeight = height; m_OptimizedBlockState = OptimizedBlockState.HasOptimizedBlock; + return true; } internal override bool OnOptimizedInspectorGUI(Rect contentRect) { + m_SerializedObject.UpdateIfRequiredOrScript(); + bool childrenAreExpanded = true; bool wasEnabled = GUI.enabled; var visibleRect = GUIClip.visibleRect; var contentOffset = contentRect.y; + if (Event.current.type != EventType.Repaint) + visibleRect = m_LastVisibleRect; + + // Release keyboard focus before scrolling so that the virtual scrolling focus wrong control. + if (Event.current.type == EventType.ScrollWheel) + GUIUtility.keyboardControl = 0; - contentRect.xMin += InspectorWindow.kInspectorPaddingLeft; - contentRect.xMax -= InspectorWindow.kInspectorPaddingRight; - contentRect.y += EditorGUI.kControlVerticalSpacing; var property = m_SerializedObject.GetIterator(); - var isInspectorModeNormal = m_InspectorMode == InspectorMode.Normal; - var behaviour = target as MonoBehaviour; - var generatorAsset = ScriptGeneratorAsset.FromMonoBehaviour(behaviour); - var isAssetBased = behaviour != null && generatorAsset != null; + var isInspectorModeNormal = inspectorMode == InspectorMode.Normal; while (property.NextVisible(childrenAreExpanded)) { - if (isAssetBased && "m_Script" == property.propertyPath && isInspectorModeNormal) - continue; - if (!isAssetBased && "m_GeneratorAsset" == property.propertyPath && isInspectorModeNormal) - continue; var handler = ScriptAttributeUtility.GetHandler(property); contentRect.height = handler.GetHeight(property, null, false); if (contentRect.Overlaps(visibleRect)) { EditorGUI.indentLevel = property.depth; - if (isAssetBased) - using (new EditorGUI.DisabledScope(isInspectorModeNormal && "m_GeneratorAsset" == property.propertyPath)) - childrenAreExpanded = handler.OnGUI(contentRect, property, null, false, visibleRect); - else - using (new EditorGUI.DisabledScope(isInspectorModeNormal && "m_Script" == property.propertyPath)) - childrenAreExpanded = handler.OnGUI(contentRect, property, null, false, visibleRect); + using (new EditorGUI.DisabledScope(isInspectorModeNormal && "m_Script" == property.propertyPath)) + childrenAreExpanded = handler.OnGUI(contentRect, property, null, false, visibleRect) && property.isExpanded; } else childrenAreExpanded = property.isExpanded; @@ -128,7 +111,18 @@ internal override bool OnOptimizedInspectorGUI(Rect contentRect) contentRect.y += contentRect.height + EditorGUI.kControlVerticalSpacing; } - m_LastHeight = contentRect.y - contentOffset; + // Fix new height + if (Event.current.type == EventType.Repaint) + { + m_LastVisibleRect = visibleRect; + var newHeight = contentRect.y - contentOffset; + if (newHeight != m_LastHeight) + { + m_LastHeight = contentRect.y - contentOffset; + Repaint(); + } + } + GUI.enabled = wasEnabled; return m_SerializedObject.ApplyModifiedProperties(); } @@ -136,27 +130,25 @@ internal override bool OnOptimizedInspectorGUI(Rect contentRect) public bool MissingMonoBehaviourGUI() { serializedObject.Update(); - var behaviour = target as MonoBehaviour; - var assetGenerator = ScriptGeneratorAsset.FromMonoBehaviour(behaviour); - if (behaviour != null && assetGenerator != null) - { - var newValue = EditorGUILayout.ObjectField(assetGenerator, assetGenerator.GetType(), true); - if (newValue != assetGenerator) - { - ScriptGeneratorAsset.SetGeneratorAsset(behaviour, newValue as ScriptGeneratorAsset); - } - - if (serializedObject.ApplyModifiedProperties()) - EditorUtility.ForceRebuildInspectors(); - } - SerializedProperty scriptProperty = serializedObject.FindProperty("m_Script"); if (scriptProperty == null) return false; + bool scriptLoaded = CheckIfScriptLoaded(scriptProperty); + bool oldGUIEnabled = GUI.enabled; + if (!GUI.enabled && !scriptLoaded) + { + GUI.enabled = true; + } + EditorGUILayout.PropertyField(scriptProperty); - CheckIfScriptLoaded(scriptProperty); + if (!scriptLoaded) + { + ShowScriptNotLoadedWarning(); + } + + GUI.enabled = oldGUIEnabled; if (serializedObject.ApplyModifiedProperties()) EditorUtility.ForceRebuildInspectors(); @@ -164,24 +156,32 @@ public bool MissingMonoBehaviourGUI() return true; } - internal static void CheckIfScriptLoaded(SerializedProperty scriptProperty) + private static bool CheckIfScriptLoaded(SerializedProperty scriptProperty) { - MonoScript targetScript = scriptProperty.objectReferenceValue as MonoScript; - bool showScriptWarning = - targetScript == null || !targetScript.GetScriptTypeWasJustCreatedFromComponentMenu(); - if (showScriptWarning) + MonoScript targetScript = scriptProperty?.objectReferenceValue as MonoScript; + return targetScript != null && targetScript.GetScriptTypeWasJustCreatedFromComponentMenu(); + } + + private static void ShowScriptNotLoadedWarning() + { + var text = L10n.Tr( + "The associated script can not be loaded.\nPlease fix any compile errors\nand assign a valid script."); + EditorGUILayout.HelpBox(text, MessageType.Warning, true); + } + + internal static void ShowScriptNotLoadedWarning(SerializedProperty scriptProperty) + { + bool scriptLoaded = CheckIfScriptLoaded(scriptProperty); + if (!scriptLoaded) { - var text = L10n.Tr( - "The associated script can not be loaded.\nPlease fix any compile errors\nand assign a valid script."); - EditorGUILayout.HelpBox(text, MessageType.Warning, true); + ShowScriptNotLoadedWarning(); } } - private bool ResetOptimizedBlock(OptimizedBlockState resetState = OptimizedBlockState.CheckOptimizedBlock) + private void ResetOptimizedBlock(OptimizedBlockState resetState = OptimizedBlockState.CheckOptimizedBlock) { m_LastHeight = -1; m_OptimizedBlockState = resetState; - return m_OptimizedBlockState == OptimizedBlockState.HasOptimizedBlock; } internal void OnDisableINTERNAL() @@ -194,15 +194,6 @@ internal static bool ObjectIsMonoBehaviourOrScriptableObject(Object obj) { if (obj) // This test for native reference state first. { - var behaviour = obj as MonoBehaviour; - if (behaviour != null) - { - var generatorAsset = ScriptGeneratorAsset.FromMonoBehaviour(behaviour); - if (generatorAsset != null) - { - return false; - } - } return obj.GetType() == typeof(MonoBehaviour) || obj.GetType() == typeof(ScriptableObject); } return obj is MonoBehaviour || obj is ScriptableObject; diff --git a/Editor/Mono/Inspector/InspectorElement.cs b/Editor/Mono/Inspector/InspectorElement.cs index 8bc912d941..7f683bfbfb 100644 --- a/Editor/Mono/Inspector/InspectorElement.cs +++ b/Editor/Mono/Inspector/InspectorElement.cs @@ -52,11 +52,23 @@ internal enum Mode internal Mode mode { get; private set; } - internal Editor Editor { get; private set; } + internal Editor editor + { + get { return m_Editor; } + set + { + if (m_Editor != value) + { + DestroyOwnedEditor(); + m_Editor = value; + PartialReset(); + } + } + } - internal bool OwnsEditor { get; private set; } = false; + internal bool ownsEditor { get; private set; } = false; - internal SerializedObject BoundObject { get; private set; } + internal SerializedObject boundObject { get; private set; } internal VisualElement prefabOverrideBlueBarsContainer { get; private set; } @@ -106,7 +118,7 @@ internal InspectorElement(Editor editor, Mode mode) this.mode = mode; - Editor = editor; + this.editor = editor; if (editor.targets.Length == 0) { @@ -127,11 +139,16 @@ internal InspectorElement(Editor editor, Mode mode) void OnDetachFromPanel(DetachFromPanelEvent evt) { - if (OwnsEditor && Editor != null) + DestroyOwnedEditor(); + } + + void DestroyOwnedEditor() + { + if (ownsEditor && editor != null) { - Object.DestroyImmediate(Editor); - Editor = null; - OwnsEditor = false; + Object.DestroyImmediate(editor); + editor = null; + ownsEditor = false; RegisterCallback(OnAttachToPanel); } @@ -140,10 +157,23 @@ void OnDetachFromPanel(DetachFromPanelEvent evt) void OnAttachToPanel(AttachToPanelEvent evt) { - Reset(BoundObject); + Reset(boundObject); UnregisterCallback(OnAttachToPanel); } + internal static Mode GetModeFromInspectorMode(InspectorMode mode) + { + switch (mode) + { + case InspectorMode.Debug: + return Mode.Debug; + case InspectorMode.DebugInternal: + return Mode.DebugInternal; + default: + return Mode.Normal; + } + } + private void Reset(SerializedObject bindObject) { Clear(); @@ -172,7 +202,7 @@ private void Reset(SerializedObject bindObject) return; } - BoundObject = bindObject; + boundObject = bindObject; var customInspector = CreateInspectorElementFromEditor(editor); if (customInspector == null) @@ -184,6 +214,25 @@ private void Reset(SerializedObject bindObject) hierarchy.Add(customInspector); } + private void PartialReset() + { + if (boundObject == null) + { + Reset(null); + return; + } + + var customInspector = CreateInspectorElementFromEditor(editor, true); + if (customInspector == null) + { + customInspector = CreateDefaultInspector(boundObject); + } + + Clear(); + if (customInspector != null && customInspector != this) + hierarchy.Add(customInspector); + } + protected internal override void ExecuteDefaultActionAtTarget(EventBase evt) { base.ExecuteDefaultActionAtTarget(evt); @@ -197,8 +246,8 @@ protected internal override void ExecuteDefaultActionAtTarget(EventBase evt) private Editor GetOrCreateEditor(SerializedObject serializedObject) { - if (Editor != null) - return Editor; + if (editor != null) + return editor; var target = serializedObject?.targetObject; @@ -208,14 +257,14 @@ private Editor GetOrCreateEditor(SerializedObject serializedObject) { if (trackerEditor.target == target || trackerEditor.serializedObject == serializedObject) { - return Editor = trackerEditor; + return editor = trackerEditor; } } } RegisterCallback(OnDetachFromPanel); - OwnsEditor = true; - return Editor = Editor.CreateEditor(serializedObject?.targetObject); + ownsEditor = true; + return editor = Editor.CreateEditor(serializedObject?.targetObject); } private VisualElement CreateDefaultInspector(SerializedObject serializedObject) @@ -239,6 +288,10 @@ private VisualElement CreateDefaultInspector(SerializedObject serializedObject) { AddMissingScriptLabel(serializedObject); } + else + { + SetEnabled(false); + } AddToClassList(uIEDefaultVariantUssClassName); AddToClassList(uIEInspectorVariantUssClassName); @@ -251,14 +304,45 @@ bool AddMissingScriptLabel(SerializedObject serializedObject) SerializedProperty scriptProperty = serializedObject.FindProperty("m_Script"); if (scriptProperty != null) { - hierarchy.Add(new IMGUIContainer(() => GenericInspector.CheckIfScriptLoaded(scriptProperty))); + hierarchy.Add(new IMGUIContainer(() => GenericInspector.ShowScriptNotLoadedWarning(scriptProperty))); return true; } return false; } - private VisualElement CreateIMGUIInspectorFromEditor(SerializedObject serializedObject, Editor editor) + static internal bool SetWideModeForWidth(VisualElement displayElement) + { + var previousWideMode = EditorGUIUtility.wideMode; + + float inspectorWidth = 0; + + // the inspector's width can be NaN if this is our first layout check. + // or when the inspector display is changed from none to flex, the width will be zero during the measuring phase. + // we try to find a parent with a a width. If none are found, we'll set wideMode to true to avoid computing + // too tall an inspector on the first layout calculation + while (displayElement != null && (float.IsNaN(inspectorWidth) || inspectorWidth == 0)) + { + inspectorWidth = displayElement.layout.width; + displayElement = displayElement.hierarchy.parent; + } + + if (!float.IsNaN(inspectorWidth) && inspectorWidth > 0) + { + EditorGUIUtility.wideMode = inspectorWidth > Editor.k_WideModeMinWidth; + } + else + { + EditorGUIUtility.wideMode = true; + } + + return previousWideMode; + } + + IMGUIContainer m_IMGUIContainer; + + private VisualElement CreateIMGUIInspectorFromEditor(SerializedObject serializedObject, Editor editor, + bool reuseIMGUIContainer) { if ((mode & (Mode.IMGUICustom | Mode.IMGUIDefault)) == 0) return null; @@ -279,12 +363,12 @@ private VisualElement CreateIMGUIInspectorFromEditor(SerializedObject serialized if ((mode & Mode.DebugMod) > 0) { AddToClassList(debugVariantUssClassName); - editor.m_InspectorMode = InspectorMode.Debug; + editor.inspectorMode = InspectorMode.Debug; } else if ((mode & Mode.DebugInternalMod) > 0) { AddToClassList(debugInternalVariantUssClassName); - editor.m_InspectorMode = InspectorMode.DebugInternal; + editor.inspectorMode = InspectorMode.DebugInternal; } } else @@ -292,10 +376,20 @@ private VisualElement CreateIMGUIInspectorFromEditor(SerializedObject serialized AddToClassList(iMGUICustomVariantUssClassName); } - IMGUIContainer inspector = null; - inspector = new IMGUIContainer(() => + IMGUIContainer inspector; + // Reusing the existing IMGUIContainer allows us to re-use the existing gui state, when we are drawing the same inspector this will let us keep the same control ids + if (reuseIMGUIContainer && m_IMGUIContainer != null) + { + inspector = m_IMGUIContainer; + } + else { - if (!editor.serializedObject.isValid) + inspector = new IMGUIContainer(); + } + inspector.onGUIHandler = () => + { + if ((editor.target == null && !GenericInspector.ObjectIsMonoBehaviourOrScriptableObject(editor.target)) || + !editor.serializedObject.isValid) { return; } @@ -309,13 +403,13 @@ private VisualElement CreateIMGUIInspectorFromEditor(SerializedObject serialized switch (mode) { case Mode.Normal: - genericEditor.m_InspectorMode = InspectorMode.Normal; + genericEditor.inspectorMode = InspectorMode.Normal; break; case Mode.Default: - genericEditor.m_InspectorMode = InspectorMode.Debug; + genericEditor.inspectorMode = InspectorMode.Debug; break; case Mode.Custom: - genericEditor.m_InspectorMode = InspectorMode.DebugInternal; + genericEditor.inspectorMode = InspectorMode.DebugInternal; break; case Mode.IMGUI: break; @@ -325,23 +419,14 @@ private VisualElement CreateIMGUIInspectorFromEditor(SerializedObject serialized //set the current PropertyHandlerCache to the current editor ScriptAttributeUtility.propertyHandlerCache = editor.propertyHandlerCache; - var originalWideMode = EditorGUIUtility.wideMode; var originalHierarchyMode = EditorGUIUtility.hierarchyMode; - EditorGUIUtility.hierarchyMode = true; - var inspectorWidth = inspector.layout.width; - // the inspector's width can be NaN if this is our first layout check. - // If that's the case we'll set wideMode to true to avoid computing too tall an inspector on the first layout calculation - if (!float.IsNaN(inspectorWidth)) - { - EditorGUIUtility.wideMode = inspectorWidth > Editor.k_WideModeMinWidth; - } - else - { - EditorGUIUtility.wideMode = true; - } - GUIStyle editorWrapper = (editor.UseDefaultMargins() ? EditorStyles.inspectorDefaultMargins : GUIStyle.none); + var originalWideMode = SetWideModeForWidth(inspector); + + GUIStyle editorWrapper = (editor.UseDefaultMargins() + ? EditorStyles.inspectorDefaultMargins + : GUIStyle.none); try { GUI.changed = false; @@ -396,13 +481,22 @@ private VisualElement CreateIMGUIInspectorFromEditor(SerializedObject serialized } finally { + if (GUI.changed) + { + // This forces a relayout of all imguicontainers in this inspector window. + // fixes part of case 1148706 + var element = inspector.GetFirstAncestorOfType(); + if (element != null) + EditorElement.InvalidateIMGUILayouts(element.parent); + } EditorGUIUtility.wideMode = originalWideMode; EditorGUIUtility.hierarchyMode = originalHierarchyMode; } } - }); + }; inspector.style.overflow = Overflow.Visible; + m_IMGUIContainer = inspector; if (!(editor is GenericInspector)) inspector.AddToClassList(customInspectorUssClassName); @@ -414,7 +508,7 @@ private VisualElement CreateIMGUIInspectorFromEditor(SerializedObject serialized return inspector; } - private VisualElement CreateInspectorElementFromEditor(Editor editor) + private VisualElement CreateInspectorElementFromEditor(Editor editor, bool reuseIMGUIContainer = false) { var serializedObject = editor.serializedObject; var target = editor.targets[0]; @@ -440,7 +534,7 @@ private VisualElement CreateInspectorElementFromEditor(Editor editor) } if (inspectorElement == null) - inspectorElement = CreateIMGUIInspectorFromEditor(serializedObject, editor); + inspectorElement = CreateIMGUIInspectorFromEditor(serializedObject, editor, reuseIMGUIContainer); if (inspectorElement == null && (mode & Mode.UIEDefault) > 0) inspectorElement = CreateDefaultInspector(serializedObject); @@ -457,6 +551,7 @@ private VisualElement CreateInspectorElementFromEditor(Editor editor) bool m_IsOpenForEdit; bool m_InvalidateGUIBlockCache = true; + Editor m_Editor; private bool GetRebuildOptimizedGUIBlocks(Object inspectedObject) { diff --git a/Editor/Mono/Inspector/InspectorWindow.cs b/Editor/Mono/Inspector/InspectorWindow.cs index b14830cf88..89cf650fbd 100644 --- a/Editor/Mono/Inspector/InspectorWindow.cs +++ b/Editor/Mono/Inspector/InspectorWindow.cs @@ -22,16 +22,23 @@ using Object = UnityEngine.Object; using Overflow = UnityEngine.UIElements.Overflow; -using Visibility = UnityEngine.UIElements.Visibility; using AssetImporterEditor = UnityEditor.Experimental.AssetImporters.AssetImporterEditor; +using UnityEditor.SceneManagement; namespace UnityEditor { [EditorWindowTitle(title = "Inspector", useTypeNameAsIconName = true)] internal class InspectorWindow : EditorWindow, IHasCustomMenu { - internal InspectorMode m_InspectorMode = InspectorMode.Normal; + InspectorMode m_InspectorMode = InspectorMode.Normal; + + internal InspectorMode inspectorMode + { + get { return m_InspectorMode; } + set { SetMode(value); } + } + internal bool m_UseUIElementsDefaultInspector = false; static readonly List m_AllInspectors = new List(); @@ -41,7 +48,7 @@ internal class InspectorWindow : EditorWindow, IHasCustomMenu const float kAddComponentButtonHeight = 45f; internal const int kInspectorPaddingLeft = 4 + 10; internal const int kInspectorPaddingRight = 4; - const float kEditorElementPaddingBottom = 2f; + internal const float kEditorElementPaddingBottom = 2f; const float k_MinAreaAbovePreview = 130; const float k_InspectorPreviewMinHeight = 130; @@ -65,7 +72,7 @@ internal class InspectorWindow : EditorWindow, IHasCustomMenu [SerializeField] EditorGUIUtility.EditorLockTrackerWithActiveEditorTracker m_LockTracker = new EditorGUIUtility.EditorLockTrackerWithActiveEditorTracker(); - Editor m_LastInteractedEditor; + internal Editor lastInteractedEditor { get; set; } int m_LastInitialEditorInstanceID; Component[] m_ComponentsInPrefabSource; HashSet m_RemovedComponents; @@ -85,28 +92,29 @@ internal class InspectorWindow : EditorWindow, IHasCustomMenu private Dictionary> m_PreviewableTypes; private IPreviewable m_SelectedPreview; - readonly HashSet m_EditorsWithImportedObjectLabel = new HashSet(); + internal HashSet editorsWithImportedObjectLabel { get; } = new HashSet(); - private EditorDragging editorDragging; + internal EditorDragging editorDragging { get; } IMGUIContainer m_TrackerResetter; VisualElement m_EditorsElement; - VisualElement editorsElement => m_EditorsElement ?? (m_EditorsElement = FindVisualElementInTreeByName("editorsList")); + VisualElement editorsElement => m_EditorsElement ?? (m_EditorsElement = FindVisualElementInTreeByClassName(s_EditorListClassName)); + VisualElement m_RemovedPrefabComponentsElement; VisualElement m_PreviewAndLabelElement; - VisualElement previewAndLabelElement => m_PreviewAndLabelElement ?? (m_PreviewAndLabelElement = FindVisualElementInTreeByName("footerInfo")); + VisualElement previewAndLabelElement => m_PreviewAndLabelElement ?? (m_PreviewAndLabelElement = FindVisualElementInTreeByClassName(s_FooterInfoClassName)); VisualElement m_MultiEditLabel; - VisualElement FindVisualElementInTreeByName(string elementName) + VisualElement FindVisualElementInTreeByClassName(string elementClassName) { - var element = rootVisualElement.Q(elementName); + var element = rootVisualElement.Q(className: elementClassName); if (element == null) { LoadVisualTreeFromUxml(); - element = rootVisualElement.Q(elementName); + element = rootVisualElement.Q(className: elementClassName); } return element; @@ -143,6 +151,15 @@ internal static class Styles ); } + + internal static readonly string s_MultiEditClassName = "unity-inspector-no-multi-edit-warning"; + internal static readonly string s_MultiEditLabelClassName = "unity-inspector-no-multi-edit-warning__label"; + internal static readonly string s_ScrollViewClassName = "unity-inspector-root-scrollview"; + internal static readonly string s_EditorListClassName = "unity-inspector-editors-list"; + internal static readonly string s_AddComponentClassName = "unity-inspector-add-component-button"; + internal static readonly string s_FooterInfoClassName = "unity-inspector-footer-info"; + internal static readonly string s_MainContainerClassName = "unity-inspector-main-container"; + internal InspectorWindow() { editorDragging = new EditorDragging(this); @@ -200,12 +217,14 @@ private void LoadVisualTreeFromUxml() { var tpl = EditorGUIUtility.Load("UXML/InspectorWindow/InspectorWindow.uxml") as VisualTreeAsset; var container = tpl.CloneTree(); - container.AddToClassList("mainContainer"); + container.AddToClassList(s_MainContainerClassName); rootVisualElement.hierarchy.Add(container); - var label = rootVisualElement.Q("nomultieditwarning"); - m_MultiEditLabel = label; - label.RemoveFromHierarchy(); + var multiContainer = rootVisualElement.Q(className: s_MultiEditClassName); + multiContainer.Query().ForEach((label) => label.text = L10n.Tr(label.text)); + multiContainer.RemoveFromHierarchy(); + + m_MultiEditLabel = multiContainer; rootVisualElement.RegisterCallback(OnGeometryChanged); @@ -273,16 +292,15 @@ internal static List GetInspectors() } [UsedByNativeCode] - static private void RedrawFromNative() + private static void RedrawFromNative() { foreach (var inspector in m_AllInspectors) { - inspector.tracker.ForceRebuild(); inspector.RebuildContentsContainers(); } } - static internal InspectorWindow[] GetAllInspectorWindows() + internal static InspectorWindow[] GetAllInspectorWindows() { return m_AllInspectors.ToArray(); } @@ -326,30 +344,37 @@ void RefreshTitle() void SetUseUIEDefaultInspector() { m_UseUIElementsDefaultInspector = !m_UseUIElementsDefaultInspector; + // Clear the editors Element so that a real rebuild is done + editorsElement.Clear(); RebuildContentsContainers(); } void SetMode(InspectorMode mode) { - m_InspectorMode = mode; - RefreshTitle(); - tracker.inspectorMode = mode; - m_ResetKeyboardControl = true; + if (m_InspectorMode != mode) + { + m_InspectorMode = mode; + RefreshTitle(); + // Clear the editors Element so that a real rebuild is done + editorsElement.Clear(); + tracker.inspectorMode = mode; + m_ResetKeyboardControl = true; + } } void SetDebug() { - SetMode(InspectorMode.Debug); + inspectorMode = InspectorMode.Debug; } void SetNormal() { - SetMode(InspectorMode.Normal); + inspectorMode = InspectorMode.Normal; } void SetDebugInternal() { - SetMode(InspectorMode.DebugInternal); + inspectorMode = InspectorMode.DebugInternal; } public bool isLocked @@ -413,15 +438,19 @@ void ExtractPrefabComponents() return; if (m_Tracker.activeEditors[0].targets.Length != 1) return; + GameObject go = m_Tracker.activeEditors[0].target as GameObject; + if (go == null && m_Tracker.activeEditors[0] is PrefabImporterEditor) + go = m_Tracker.activeEditors[1].target as GameObject; if (go == null) return; - GameObject sourceGo = PrefabUtility.GetCorrespondingObjectFromSource(go); + + GameObject sourceGo = PrefabUtility.GetCorrespondingConnectedObjectFromSource(go); if (sourceGo == null) return; m_ComponentsInPrefabSource = sourceGo.GetComponents(); - var removedComponentsList = PrefabUtility.GetRemovedComponents(PrefabUtility.GetOutermostPrefabInstanceRoot(go)); + var removedComponentsList = PrefabOverridesUtility.GetRemovedComponentsForSingleGameObject(go); for (int i = 0; i < removedComponentsList.Count; i++) { m_RemovedComponents.Add(removedComponentsList[i].assetComponent); @@ -516,11 +545,9 @@ private void ClearTrackerDirtyOnRepaint() } } - static internal InspectorWindow s_CurrentInspectorWindow; - private bool m_TrackerResetInserted; - IMGUIContainer CreateIMGUIContainer(Action onGUIHandler, string name = null) + internal IMGUIContainer CreateIMGUIContainer(Action onGUIHandler, string name = null) { IMGUIContainer result = null; if (m_TrackerResetInserted) @@ -552,24 +579,29 @@ internal virtual void RebuildContentsContainers() m_Previews = null; m_SelectedPreview = null; m_TypeSelectionList = null; - m_TrackerResetInserted = false; m_FirstInitialize = false; - m_EditorsWithImportedObjectLabel.Clear(); + editorsWithImportedObjectLabel.Clear(); m_LastInitialEditorInstanceID = 0; + if (m_RemovedPrefabComponentsElement != null) + { + m_RemovedPrefabComponentsElement.RemoveFromHierarchy(); + m_RemovedPrefabComponentsElement = null; + } + FlushAllOptimizedGUIBlocksIfNeeded(); ResetKeyboardControl(); - s_CurrentInspectorWindow = this; - var addComponentButton = rootVisualElement.Q("addComponentButton"); + var addComponentButton = rootVisualElement.Q(className: s_AddComponentClassName); addComponentButton.Clear(); previewAndLabelElement.Clear(); if (m_TrackerResetter == null) { + m_TrackerResetInserted = false; m_TrackerResetter = CreateIMGUIContainer(() => {}, "activeEditorTrackerResetter"); - rootVisualElement.Add(m_TrackerResetter); + rootVisualElement.Insert(0, m_TrackerResetter); } Editor[] editors = tracker.activeEditors; @@ -577,14 +609,13 @@ internal virtual void RebuildContentsContainers() DrawEditors(editors); Profiler.EndSample(); - var label = rootVisualElement.Q("noMultiEditWarning"); - var labelMustBeAdded = false; + var labelMustBeAdded = m_MultiEditLabel.parent != editorsElement; - if (label == null) - { - label = m_MultiEditLabel; - labelMustBeAdded = true; - } + // The PrefabImporterEditor can hide its imported objects if it detects missing scripts. In this case + // do not add the multi editing warning + var assetImporter = GetAssetImporter(editors); + if (assetImporter != null && !assetImporter.showImportedObject) + labelMustBeAdded = false; if (tracker.hasComponentsWhichCannotBeMultiEdited) { @@ -597,18 +628,16 @@ internal virtual void RebuildContentsContainers() { if (labelMustBeAdded) { - editorsElement.Add(label); + editorsElement.Add(m_MultiEditLabel); } } Profiler.EndSample(); } else { - label.RemoveFromHierarchy(); + m_MultiEditLabel.RemoveFromHierarchy(); } - s_CurrentInspectorWindow = null; - if (editors.Any()) { Profiler.BeginSample("InspectorWindow.RebuildContentsContainers()::addComponentButton"); @@ -641,8 +670,6 @@ internal virtual void RebuildContentsContainers() rootVisualElement.MarkDirtyRepaint(); - if (m_Parent != null) // parent may be null in some situations (case 970700, 851988) - m_Parent.ClearKeyboardControl(); ScriptAttributeUtility.ClearGlobalCache(); rootVisualElement.RegisterCallback(DragOverBottomArea); @@ -657,9 +684,9 @@ private Rect DropRectangle get { return new Rect( - rootVisualElement.rect.x, - rootVisualElement.rect.y + editorsElement.rect.height, - rootVisualElement.rect.width, + editorsElement.rect.x, + editorsElement.rect.y + editorsElement.rect.height, + editorsElement.rect.width, rootVisualElement.rect.height - editorsElement.rect.height); } } @@ -696,7 +723,7 @@ void DragPerformInBottomArea(DragPerformEvent dragPerformedEvent) return; } - editorDragging.HandleDragPerformInBottomArea(tracker.activeEditors, lastChild.layout); + editorDragging.HandleDragPerformInBottomArea(tracker.activeEditors, DropRectangle, lastChild.layout); } protected bool m_FirstInitialize; @@ -710,7 +737,7 @@ protected virtual void OnGUI() internal virtual Editor GetLastInteractedEditor() { - return m_LastInteractedEditor; + return lastInteractedEditor; } internal IPreviewable GetEditorThatControlsPreview(IPreviewable[] editors) @@ -1248,81 +1275,77 @@ protected static void DrawVCSShortInfoAsset(Asset asset, string tooltip, Rect re EditorGUI.LabelField(textRect, content, Styles.preToolbar2); } - private void SetElementVisible(VisualElement ve, bool visible) + HashSet m_DrawnSelection = new HashSet(); + void DrawEditors(Editor[] editors) { - if (visible) + Dictionary mapping = null; + + var selection = new HashSet(Selection.instanceIDs); + if (m_DrawnSelection.SetEquals(selection)) { - ve.style.position = Position.Relative; - ve.style.visibility = Visibility.Visible; - SetInspectorElementChildIMGUIContainerFocusable(ve, true); + if (editorsElement.childCount > 0 && m_DrawnSelection.Any()) // do we already have a hierarchy + { + mapping = ProcessEditorElementsToRebuild(editors); + } } else { - ve.style.position = Position.Absolute; - ve.style.visibility = Visibility.Hidden; - SetInspectorElementChildIMGUIContainerFocusable(ve, false); + m_DrawnSelection.Clear(); + m_DrawnSelection = selection; } - } - private void SetInspectorElementChildIMGUIContainerFocusable(VisualElement ve, bool focusable) - { - var inspectorElement = ve as InspectorElement; - if (inspectorElement != null) + if (mapping == null) { - foreach (var child in inspectorElement.Children()) - { - var imguiContainer = child as IMGUIContainer; - if (imguiContainer != null) - { - imguiContainer.focusable = focusable; - } - } + editorsElement.Clear(); } - } - - private void DrawEditors(Editor[] editors) - { - editorsElement.Clear(); if (editors.Length == 0) + { return; - - // We need to force optimized GUI to dirty when object becomes open for edit - // e.g. after checkout in version control. If this is not done the optimized - // GUI will need an extra repaint before it gets ungrayed out. + } Editor.m_AllowMultiObjectAccess = true; - VisualElement editorContainer = editorsElement; - if (editors.Length > 0 && editors[0].GetInstanceID() != m_LastInitialEditorInstanceID) OnTrackerRebuilt(); + if (m_RemovedComponents == null) + ExtractPrefabComponents(); // needed after assembly reload (due to HashSet not being serializable) + + bool checkForRemovedComponents = m_ComponentsInPrefabSource != null; int prefabComponentIndex = -1; + int targetGameObjectIndex = -1; + GameObject targetGameObject = null; + if (checkForRemovedComponents) + { + targetGameObjectIndex = editors[0] is PrefabImporterEditor ? 1 : 0; + targetGameObject = (GameObject)editors[targetGameObjectIndex].target; + } + for (int editorIndex = 0; editorIndex < editors.Length; editorIndex++) { - if (m_ComponentsInPrefabSource != null && editorIndex != 0) + VisualElement prefabsComponentElement = new VisualElement() { name = "PrefabComponentElement" }; + if (checkForRemovedComponents && editorIndex > targetGameObjectIndex) { + if (prefabComponentIndex == -1) + prefabComponentIndex = 0; while (prefabComponentIndex < m_ComponentsInPrefabSource.Length) { Object target = editors[editorIndex].target; - // This is possible if there's a component with a missing script. if (target != null) { Object correspondingSource = PrefabUtility.GetCorrespondingObjectFromSource(target); Component nextInSource = m_ComponentsInPrefabSource[prefabComponentIndex]; + if (correspondingSource == nextInSource) break; - - AddRemovedPrefabComponentElement(editors, nextInSource, editorContainer); + AddRemovedPrefabComponentElement(targetGameObject, nextInSource, prefabsComponentElement); } - prefabComponentIndex++; } + prefabComponentIndex++; } - prefabComponentIndex++; - if (ShouldCullEditor(editors, editorIndex)) { editors[editorIndex].isInspectorDirty = false; @@ -1330,167 +1353,48 @@ private void DrawEditors(Editor[] editors) } var editor = editors[editorIndex]; - Object editorTarget = editor.targets[0]; string editorTitle = ObjectNames.GetInspectorTitle(editorTarget); + EditorElement editorContainer; - var inspectorElementMode = InspectorElement.Mode.Normal; - if (m_UseUIElementsDefaultInspector) - inspectorElementMode ^= InspectorElement.Mode.IMGUIDefault; - - VisualElement editorElement = new InspectorElement(editor, inspectorElementMode) - { - focusable = false - }; - VisualElement footerElement = null; + if (mapping == null || !mapping.TryGetValue(editors[editorIndex].target.GetInstanceID(), out editorContainer)) { - var i = editorIndex; - Rect dragRect = new Rect(); - Rect contentRect = new Rect(); - - //Create and IMGUIcontainer to enclose the header - // This also needs to validate the state of the editor tracker (stuff that was already done in the original DrawEditors - var headerElement = CreateIMGUIContainer(() => // Dragging handle used for editor reordering - { - var edits = tracker.activeEditors; - - if (edits.Length <= i) - { - SetElementVisible(editorElement, false); - return; - } - - var thisEditor = edits[i]; - - var target = thisEditor?.target; - - // Avoid drawing editor if native target object is not alive, unless it's a MonoBehaviour/ScriptableObject - // We want to draw the generic editor with a warning about missing/invalid script - // Case 891450: - // - ActiveEditorTracker will automatically create editors for materials of components on tracked game objects - // - UnityEngine.UI.Mask will destroy this material in OnDisable (e.g. disabling it with the checkbox) causing problems when drawing the material editor - if (target == null && !NativeClassExtensionUtilities.ExtendsANativeType(target)) - { - SetElementVisible(editorElement, false); - return; - } - - bool wasVisible = WasEditorVisible(editors, editor, i, target); - - GUIUtility.GetControlID(target.GetInstanceID(), FocusType.Passive); - EditorGUIUtility.ResetGUIState(); - - if (editor.target is AssetImporter) - m_EditorsWithImportedObjectLabel.Add(i + 1); - - //set the current PropertyHandlerCache to the current editor - ScriptAttributeUtility.propertyHandlerCache = editor.propertyHandlerCache; - using (new InspectorWindowUtils.LayoutGroupChecker()) - { - dragRect = DrawEditorHeader(edits, i, thisEditor, target, ref wasVisible); - } - - if (wasVisible != editorElement.visible) - { - SetElementVisible(editorElement, wasVisible); - } - - var multiEditingSupported = IsMultiEditingSupported(editor, target); - - if (!multiEditingSupported && wasVisible) - { - GUILayout.Label("Multi-object editing not supported.", EditorStyles.helpBox); - return; - } - - InspectorWindowUtils.DisplayDeprecationMessageIfNecessary(editor); - - // Reset dirtiness when repainting - if (Event.current.type == EventType.Repaint) - { - thisEditor.isInspectorDirty = false; - } - - bool excludedClass = InspectorWindowUtils.IsExcludedClass(target); - if (excludedClass) - EditorGUILayout.HelpBox("The module which implements this component type has been force excluded in player settings. This object will be removed in play mode and from any builds you make.", MessageType.Warning); - - contentRect = editorElement.layout; - }, editorTitle + "Header"); - - editorContainer.Add(headerElement); - - footerElement = CreateIMGUIContainer(() => - { - var edits = tracker.activeEditors; - - if (edits.Length <= i) - { - return; - } - - var ed = edits[i]; - - contentRect.y = -contentRect.height; - editorDragging.HandleDraggingToEditor(edits, i, dragRect, contentRect); - HandleComponentScreenshot(contentRect, ed); - - var target = ed.target; - var comp = target as Component; - - if (EditorGUI.ShouldDrawOverrideBackground(ed.targets, Event.current, comp)) - { - var rect = GUILayoutUtility.kDummyRect; - bool wasVisible = WasEditorVisible(editors, editor, i, target); - // if the inspector is currently visible then the override background drawn by the footer needs to be slightly larger than if the inspector is collapsed - if (wasVisible) - { - rect.y -= 1; - rect.height += 1; - } - else - { - rect.y += 1; - rect.height -= 1; - } - - EditorGUI.DrawOverrideBackground(rect, true); - } - }, editorTitle + "Footer"); - footerElement.style.height = 3; + editorContainer = new EditorElement(editorIndex, this) { name = editorTitle }; + editorsElement.Add(editorContainer); } - editorElement.name = editorTitle; - - editorElement.style.paddingBottom = kEditorElementPaddingBottom; - - if (EditorNeedsVerticalOffset(editors, editorIndex, editorTarget)) + if (prefabsComponentElement.childCount > 0) { - // This is madness - editorElement.cacheAsBitmap = false; - editorElement.style.overflow = Overflow.Hidden; + editorContainer.AddPrefabComponent(prefabsComponentElement); + } + else + { + editorContainer.AddPrefabComponent(null); } - - editorContainer.Add(editorElement); - editorContainer.Add(footerElement); } // Make sure to display any remaining removed components that come after the last component on the GameObject. - if (m_ComponentsInPrefabSource != null) + if (checkForRemovedComponents) { + VisualElement prefabsComponentElement = new VisualElement() { name = "RemainingPrefabComponentElement" }; while (prefabComponentIndex < m_ComponentsInPrefabSource.Length) { Component nextInSource = m_ComponentsInPrefabSource[prefabComponentIndex]; - AddRemovedPrefabComponentElement(editors, nextInSource, editorContainer); + AddRemovedPrefabComponentElement(targetGameObject, nextInSource, prefabsComponentElement); prefabComponentIndex++; } + + if (prefabsComponentElement.childCount > 0) + { + editorsElement.Add(prefabsComponentElement); + m_RemovedPrefabComponentsElement = prefabsComponentElement; + } } } - void AddRemovedPrefabComponentElement(Editor[] editors, Component nextInSource, VisualElement editorContainer) + void AddRemovedPrefabComponentElement(GameObject targetGameObject, Component nextInSource, VisualElement element) { - var targetGameObject = editors[0].target as GameObject; if (ShouldDisplayRemovedComponent(targetGameObject, nextInSource)) { string missingComponentTitle = ObjectNames.GetInspectorTitle(nextInSource); @@ -1498,7 +1402,7 @@ void AddRemovedPrefabComponentElement(Editor[] editors, Component nextInSource, CreateIMGUIContainer(() => DisplayRemovedComponent(targetGameObject, nextInSource), missingComponentTitle); removedComponentElement.style.paddingBottom = kEditorElementPaddingBottom; - editorContainer.Add(removedComponentElement); + element.Add(removedComponentElement); } } @@ -1518,13 +1422,13 @@ bool ShouldDisplayRemovedComponent(GameObject go, Component comp) return true; } - void DisplayRemovedComponent(GameObject go, Component comp) + static void DisplayRemovedComponent(GameObject go, Component comp) { Rect rect = GUILayoutUtility.GetRect(GUIContent.none, EditorStyles.inspectorTitlebar); EditorGUI.RemovedComponentTitlebar(rect, go, comp); } - private bool WasEditorVisible(Editor[] editors, Editor editor, int editorIndex, Object target) + internal bool WasEditorVisible(Editor[] editors, int editorIndex, Object target) { int wasVisibleState = tracker.GetVisible(editorIndex); bool wasVisible; @@ -1534,7 +1438,7 @@ private bool WasEditorVisible(Editor[] editors, Editor editor, int editorIndex, // Some inspectors (MaterialEditor) needs to be told when they are the main visible asset. if (editorIndex == 0 || (editorIndex == 1 && ShouldCullEditor(editors, 0))) { - editor.firstInspectedEditor = true; + editors[editorIndex].firstInspectedEditor = true; } // Init our state with last state @@ -1551,89 +1455,7 @@ private bool WasEditorVisible(Editor[] editors, Editor editor, int editorIndex, return wasVisible; } - Rect DrawEditorHeader(Editor[] editors, int editorIndex, Editor editor, Object target, ref bool wasVisible) - { - var largeHeader = DrawEditorLargeHeader(editors, editorIndex, editor, ref wasVisible); - - // Dragging handle used for editor reordering - var dragRect = largeHeader ? new Rect() : DrawEditorSmallHeader(editors, editorIndex, target, editor, wasVisible); - return dragRect; - } - - bool DrawEditorLargeHeader(Editor[] editors, int editorIndex, Editor editor, ref bool wasVisible) - { - bool largeHeader = EditorHasLargeHeader(editorIndex, editors); - - // Draw large headers before we do the culling of unsupported editors below, - // so the large header is always shown even when the editor can't be. - if (largeHeader) - { - String message = String.Empty; - bool IsOpenForEdit = editor.IsOpenForEdit(out message); - wasVisible = true; - - if (m_EditorsWithImportedObjectLabel.Contains(editorIndex)) - { - var importedObjectBarRect = GUILayoutUtility.GetRect(16, 16); - importedObjectBarRect.height = 17; - - // Clip the label to avoid a black border at the bottom - GUI.BeginGroup(importedObjectBarRect); - GUI.Label(new Rect(0, 0, importedObjectBarRect.width, importedObjectBarRect.height), "Imported Object", "OL Title"); - GUI.EndGroup(); - } - - // Header - using (new EditorGUI.DisabledScope(!IsOpenForEdit)) // Only disable the entire header if the asset is locked by VCS - { - editor.DrawHeader(); - } - } - - return largeHeader; - } - - private bool EditorNeedsVerticalOffset(Editor[] editors, int editorIndex, Object target) - { - return editorIndex > 0 && editors[editorIndex - 1].target is GameObject && target is Component; - } - - // Draw small headers (the header above each component) after the culling above - // so we don't draw a component header for all the components that can't be shown. - Rect DrawEditorSmallHeader(Editor[] editors, int editorIndex, Object target, Editor editor, bool wasVisible) - { - // ensure first component's title bar is flush with the header - if (EditorNeedsVerticalOffset(editors, editorIndex, target)) - { - // TODO: Check if we can fix this in the GameObjectInspector instead - GUILayout.Space( - -1f // move back up so line overlaps - - EditorStyles.inspectorBig.margin.bottom - EditorStyles.inspectorTitlebar.margin.top // move back up margins - ); - } - - using (new EditorGUI.DisabledScope(!editor.IsEnabled())) - { - bool isVisible = EditorGUILayout.InspectorTitlebar(wasVisible, editor); - if (wasVisible != isVisible) - { - tracker.SetVisible(editorIndex, isVisible ? 1 : 0); - InternalEditorUtility.SetIsInspectorExpanded(target, isVisible); - if (isVisible) - { - m_LastInteractedEditor = editor; - } - else if (m_LastInteractedEditor == editor) - { - m_LastInteractedEditor = null; - } - } - } - - return GUILayoutUtility.GetLastRect(); - } - - bool IsMultiEditingSupported(Editor editor, Object target) + internal bool IsMultiEditingSupported(Editor editor, Object target) { // Culling of editors that can't be properly shown. // If the current editor is a GenericInspector even though a custom editor for it exists, @@ -1666,25 +1488,11 @@ bool IsMultiEditingSupported(Editor editor, Object target) return multiEditingSupported; } - internal bool EditorHasLargeHeader(int editorIndex, Editor[] trackerActiveEditors) + internal static bool EditorHasLargeHeader(int editorIndex, Editor[] trackerActiveEditors) { return trackerActiveEditors[editorIndex].firstInspectedEditor || trackerActiveEditors[editorIndex].HasLargeHeader(); } - private void HandleComponentScreenshot(Rect contentRect, Editor editor) - { - if (ScreenShots.s_TakeComponentScreenshot) - { - contentRect.yMin -= 16; - if (contentRect.Contains(Event.current.mousePosition)) - { - Rect globalComponentRect = GUIClip.Unclip(contentRect); - globalComponentRect.position = globalComponentRect.position + m_Parent.screenPosition.position; - ScreenShots.ScreenShotComponent(globalComponentRect, editor.target); - } - } - } - internal bool ShouldCullEditor(Editor[] editors, int editorIndex) { if (editors[editorIndex].hideInspector) @@ -1692,7 +1500,7 @@ internal bool ShouldCullEditor(Editor[] editors, int editorIndex) Object currentTarget = editors[editorIndex].target; - // Objects that should always be hidden + // Editors that should always be hidden if (currentTarget is ParticleSystemRenderer) return true; @@ -1703,7 +1511,7 @@ internal bool ShouldCullEditor(Editor[] editors, int editorIndex) // Let asset importers decide if the imported object should be shown or not if (m_InspectorMode == InspectorMode.Normal && editorIndex != 0) { - AssetImporterEditor importerEditor = editors[0] as AssetImporterEditor; + AssetImporterEditor importerEditor = GetAssetImporter(editors); if (importerEditor != null && !importerEditor.showImportedObject) return true; } @@ -1743,23 +1551,36 @@ void DrawSelectionPickerList() EditorGUIUtility.SetIconSize(oldSize); } + AssetImporterEditor GetAssetImporter(Editor[] editors) + { + if (editors == null || editors.Length == 0) + return null; + + return editors[0] as AssetImporterEditor; + } + void HandleLastInteractedEditor(Rect componentRect, Editor editor) { - if (editor != m_LastInteractedEditor && + if (editor != lastInteractedEditor && Event.current.type == EventType.MouseDown && componentRect.Contains(Event.current.mousePosition)) { // Don't use the event because the editor might want to use it. // But don't move the check down below the editor either, // because we want to set the last interacted editor simultaneously. - m_LastInteractedEditor = editor; + lastInteractedEditor = editor; Repaint(); } } private void AddComponentButton(Editor[] editors) { + // Don't show the Add Component button if we are not showing imported objects for Asset Importers + var assetImporter = GetAssetImporter(editors); + if (assetImporter != null && !assetImporter.showImportedObject) + return; + Editor editor = InspectorWindowUtils.GetFirstNonImportInspectorEditor(editors); - if (editor != null && editor.target != null && editor.target is GameObject && editor.IsEnabled() && !EditorUtility.IsPersistent(editor.target)) + if (editor != null && editor.target != null && editor.target is GameObject && editor.IsEnabled()) { EditorGUILayout.BeginHorizontal(GUIContent.none, GUIStyle.none, GUILayout.Height(kAddComponentButtonHeight)); { @@ -1942,5 +1763,69 @@ internal static void RemoveInspectorWindow(InspectorWindow window) { m_AllInspectors.Remove(window); } + + /* + * ProcessEditorElementsToRebuild is required as there are times when the ActiveEditorTracker + * is rebuilt even though the selection does not change and there are IMGUI controls outside + * the InspectorWindow that depend on currently valid control IDs + * An example is the Object Selector + * + * When a rebuild of the InspectorWindow is requested, we attempt to match up existing Editor references to current ones. + * We can't rely on the Editor instance ids those will have been recreated and our previously drawn ones will now be invalid + * Instead we can find matching Editor instances by comparing the target InstanceIDs. + */ + Dictionary ProcessEditorElementsToRebuild(Editor[] editors) + { + Dictionary editorToElementMap = new Dictionary(); + var currentElements = editorsElement.Children().OfType().ToList(); + if (editors.Length == 0) + { + return null; + } + + if (rootVisualElement.panel == null) + { + return null; + } + + var newEditorsIndex = 0; + var previousEditorsIndex = 0; + while (newEditorsIndex < editors.Length && previousEditorsIndex < currentElements.Count) + { + var ed = editors[newEditorsIndex]; + var currentEd = currentElements[previousEditorsIndex]; + + if (currentEd.editor == null) + { + ++previousEditorsIndex; + continue; + } + + if (ed.target != currentEd.editor.target) + { + // We won't have an EditorElement for editors that are normally culled so we should skip this + if (ShouldCullEditor(editors, newEditorsIndex)) + { + ++newEditorsIndex; + continue; + } + + return null; + } + + currentEd.Reinit(newEditorsIndex); + editorToElementMap[ed.target.GetInstanceID()] = currentEd; + ++newEditorsIndex; + ++previousEditorsIndex; + } + + // Remove any elements at the end of the InspectorWindow that don't have matching Editors + for (int j = previousEditorsIndex; j < currentElements.Count; ++j) + { + currentElements[j].RemoveFromHierarchy(); + } + + return editorToElementMap; + } } } diff --git a/Editor/Mono/Inspector/InspectorWindowUtils.cs b/Editor/Mono/Inspector/InspectorWindowUtils.cs index b264f5eaad..85eef32df4 100644 --- a/Editor/Mono/Inspector/InspectorWindowUtils.cs +++ b/Editor/Mono/Inspector/InspectorWindowUtils.cs @@ -126,7 +126,7 @@ public static void DrawAddedComponentBackground(Rect position, Object[] targets, Component comp = targets[0] as Component; if (comp != null && EditorGUIUtility.comparisonViewMode == EditorGUIUtility.ComparisonViewMode.None && - PrefabUtility.GetCorrespondingObjectFromSource(comp.gameObject) != null && + PrefabUtility.GetCorrespondingConnectedObjectFromSource(comp.gameObject) != null && PrefabUtility.GetCorrespondingObjectFromSource(comp) == null) { // Ensure colored margin here for component body doesn't overlap colored margin from InspectorTitlebar, diff --git a/Editor/Mono/Inspector/LightEditor.cs b/Editor/Mono/Inspector/LightEditor.cs index b664f7afb2..4ddb6d7064 100644 --- a/Editor/Mono/Inspector/LightEditor.cs +++ b/Editor/Mono/Inspector/LightEditor.cs @@ -40,6 +40,7 @@ public sealed class Settings public SerializedProperty flare { get; private set; } public SerializedProperty renderMode { get; private set; } public SerializedProperty cullingMask { get; private set; } + public SerializedProperty renderingLayerMask { get; private set; } public SerializedProperty lightmapping { get; private set; } public SerializedProperty areaSizeX { get; private set; } public SerializedProperty areaSizeY { get; private set; } @@ -97,6 +98,7 @@ private static class Styles public static readonly GUIContent Flare = EditorGUIUtility.TrTextContent("Flare", "Specifies the flare object to be used by the light to render lens flares in the scene."); public static readonly GUIContent RenderMode = EditorGUIUtility.TrTextContent("Render Mode", "Specifies the importance of the light which impacts lighting fidelity and performance. Options are Auto, Important, and Not Important. This only affects Forward Rendering."); public static readonly GUIContent CullingMask = EditorGUIUtility.TrTextContent("Culling Mask", "Specifies which layers will be affected or excluded from the light's effect on objects in the scene."); + public static readonly GUIContent RenderingLayerMask = EditorGUIUtility.TrTextContent("Rendering Layer Mask", "Mask that can be used with SRP when drawing shadows to filter renderers outside of the normal layering system."); public static readonly GUIContent AreaWidth = EditorGUIUtility.TrTextContent("Width", "Controls the width in units of the area light."); public static readonly GUIContent AreaHeight = EditorGUIUtility.TrTextContent("Height", "Controls the height in units of the area light."); @@ -187,6 +189,7 @@ public void OnEnable() flare = m_SerializedObject.FindProperty("m_Flare"); renderMode = m_SerializedObject.FindProperty("m_RenderMode"); cullingMask = m_SerializedObject.FindProperty("m_CullingMask"); + renderingLayerMask = m_SerializedObject.FindProperty("m_RenderingLayerMask"); lightmapping = m_SerializedObject.FindProperty("m_Lightmapping"); areaSizeX = m_SerializedObject.FindProperty("m_AreaSize.x"); areaSizeY = m_SerializedObject.FindProperty("m_AreaSize.y"); @@ -205,7 +208,9 @@ public void OnDestroy() static Texture2D CreateKelvinGradientTexture(string name, int width, int height, float minKelvin, float maxKelvin) { - var texture = new Texture2D(width, height, TextureFormat.ARGB32, false) + // The texture is draw with a simple internal-GUITexture shader that don't perform any gamma correction + // so we need to provide value for color temperature texture in gamma space and use a linear format for the texture + var texture = new Texture2D(width, height, TextureFormat.ARGB32, false, true) { name = name, hideFlags = HideFlags.HideAndDontSave @@ -468,6 +473,27 @@ public void DrawCullingMask() EditorGUILayout.PropertyField(cullingMask, Styles.CullingMask); } + public void DrawRenderingLayerMask() + { + RenderPipelineAsset srpAsset = GraphicsSettings.renderPipelineAsset; + bool usingSRP = srpAsset != null; + if (!usingSRP) + return; + + EditorGUI.showMixedValue = renderingLayerMask.hasMultipleDifferentValues; + + var mask = renderingLayerMask.intValue; + var layerNames = srpAsset.renderingLayerMaskNames; + if (layerNames == null) + layerNames = RendererEditorBase.defaultRenderingLayerNames; + + var rect = EditorGUILayout.GetControlRect(); + EditorGUI.BeginProperty(rect, Styles.RenderingLayerMask, renderingLayerMask); + EditorGUI.MaskField(rect, Styles.RenderingLayerMask, mask, layerNames); + EditorGUI.EndProperty(); + EditorGUI.showMixedValue = false; + } + public void ApplyModifiedProperties() { m_SerializedObject.ApplyModifiedProperties(); @@ -740,6 +766,7 @@ public override void OnInspectorGUI() settings.DrawFlare(); settings.DrawRenderMode(); settings.DrawCullingMask(); + settings.DrawRenderingLayerMask(); EditorGUILayout.Space(); if (SceneView.lastActiveSceneView != null && SceneView.lastActiveSceneView.sceneLighting == false) diff --git a/Editor/Mono/Inspector/LightProbeGroupInspector.cs b/Editor/Mono/Inspector/LightProbeGroupInspector.cs index 2f562e22d2..dd2c9268fe 100644 --- a/Editor/Mono/Inspector/LightProbeGroupInspector.cs +++ b/Editor/Mono/Inspector/LightProbeGroupInspector.cs @@ -24,6 +24,7 @@ internal class LightProbeGroupEditor : IEditablePoint private readonly LightProbeGroup m_Group; private bool m_ShouldRecalculateTetrahedra; + private bool m_SourcePositionsDirty; private Vector3 m_LastPosition = Vector3.zero; private Quaternion m_LastRotation = Quaternion.identity; private Vector3 m_LastScale = Vector3.one; @@ -34,7 +35,8 @@ internal class LightProbeGroupEditor : IEditablePoint public LightProbeGroupEditor(LightProbeGroup group, LightProbeGroupInspector inspector) { m_Group = group; - MarkTetrahedraDirty(); + m_ShouldRecalculateTetrahedra = false; + m_SourcePositionsDirty = false; m_SerializedSelectedProbes = ScriptableObject.CreateInstance(); m_SerializedSelectedProbes.hideFlags = HideFlags.HideAndDontSave; m_Inspector = inspector; @@ -52,7 +54,7 @@ public void AddProbe(Vector3 position) m_SourcePositions.Add(position); SelectProbe(m_SourcePositions.Count - 1); - MarkTetrahedraDirty(); + MarkSourcePositionsDirty(); } private void SelectProbe(int i) @@ -93,7 +95,7 @@ public void DuplicateSelectedProbes() m_SourcePositions.Add(position); } - MarkTetrahedraDirty(); + MarkSourcePositionsDirty(); } private void CopySelectedProbes() @@ -153,7 +155,7 @@ private bool PasteProbes() { SelectProbe(i); } - MarkTetrahedraDirty(); + MarkSourcePositionsDirty(); return true; } @@ -177,7 +179,7 @@ public void RemoveSelectedProbes() m_SourcePositions.RemoveAt(index); } DeselectProbes(); - MarkTetrahedraDirty(); + MarkSourcePositionsDirty(); } public void PullProbePositions() @@ -191,7 +193,12 @@ public void PullProbePositions() public void PushProbePositions() { - m_Group.probePositions = m_SourcePositions.ToArray(); + if (m_SourcePositionsDirty) + { + m_Group.probePositions = m_SourcePositions.ToArray(); + m_SourcePositionsDirty = false; + } + m_SerializedSelectedProbes.m_Selection = m_Selection; } @@ -301,7 +308,7 @@ public bool OnSceneGUI(Transform transform) || m_LastRotation != m_Group.transform.rotation || m_LastScale != m_Group.transform.localScale) { - MarkTetrahedraDirty(); + MarkSourcePositionsDirty(); } m_LastPosition = m_Group.transform.position; @@ -373,20 +380,21 @@ public bool OnSceneGUI(Transform transform) { Undo.RegisterCompleteObjectUndo(new Object[] { m_Group, m_SerializedSelectedProbes }, "Move Probes"); if (LightProbeVisualization.dynamicUpdateLightProbes) - MarkTetrahedraDirty(); + MarkSourcePositionsDirty(); } if (m_Editing && mouseUpEvent && !LightProbeVisualization.dynamicUpdateLightProbes) { - MarkTetrahedraDirty(); + MarkSourcePositionsDirty(); } return m_Editing; } - public void MarkTetrahedraDirty() + public void MarkSourcePositionsDirty() { m_ShouldRecalculateTetrahedra = true; + m_SourcePositionsDirty = true; } public Bounds selectedProbeBounds @@ -433,6 +441,7 @@ public void SetPosition(int idx, Vector3 position) return; m_SourcePositions[idx] = position; + MarkSourcePositionsDirty(); } private static readonly Color kCloudColor = new Color(200f / 255f, 200f / 255f, 20f / 255f, 0.85f); @@ -470,6 +479,8 @@ public void UpdateSelectedPosition(int idx, Vector3 position) return; m_SourcePositions[m_Selection[idx]] = position; + + MarkSourcePositionsDirty(); } public IEnumerable GetPositions() @@ -612,6 +623,9 @@ public void OnDisable() EndEditProbes(); Undo.undoRedoPerformed -= UndoRedoPerformed; SceneView.duringSceneGui -= OnSceneGUIDelegate; + EditMode.editModeStarted -= OnEditModeStarted; + EditMode.editModeEnded -= OnEditModeEnded; + if (target != null) { m_Editor.PushProbePositions(); @@ -624,7 +638,7 @@ private void UndoRedoPerformed() // Update the cached probe positions from the ones just restored in the LightProbeGroup m_Editor.PullProbePositions(); - m_Editor.MarkTetrahedraDirty(); + m_Editor.MarkSourcePositionsDirty(); } private bool m_EditingProbes; @@ -707,7 +721,7 @@ public override void OnInspectorGUI() if (EditorGUI.EndChangeCheck()) { - m_Editor.MarkTetrahedraDirty(); + m_Editor.MarkSourcePositionsDirty(); SceneView.RepaintAll(); } } diff --git a/Editor/Mono/Inspector/LightProbeProxyVolumeEditor.cs b/Editor/Mono/Inspector/LightProbeProxyVolumeEditor.cs index b849130b70..747aaa9f79 100644 --- a/Editor/Mono/Inspector/LightProbeProxyVolumeEditor.cs +++ b/Editor/Mono/Inspector/LightProbeProxyVolumeEditor.cs @@ -44,7 +44,7 @@ static Styles() } public static GUIStyle richTextMiniLabel = new GUIStyle(EditorStyles.miniLabel); - public static GUIContent volumeResolutionText = EditorGUIUtility.TrTextContent("Proxy Volume Resolution", "Specifies the resolution of the 3D grid of interpolated light probes. Higher resolution/density means better lighting but the CPU cost will increase."); + public static GUIContent volumeResolutionText = EditorGUIUtility.TrTextContent("Proxy Volume Resolution", "Specifies the resolution of the 3D grid of interpolated light probes. Higher resolution/density means better lighting, but the CPU cost will increase."); public static GUIContent resolutionXText = new GUIContent("X"); public static GUIContent resolutionYText = new GUIContent("Y"); public static GUIContent resolutionZText = new GUIContent("Z"); @@ -52,10 +52,10 @@ static Styles() public static GUIContent bbSettingsText = EditorGUIUtility.TrTextContent("Bounding Box Settings"); public static GUIContent originText = EditorGUIUtility.TrTextContent("Origin"); public static GUIContent bbModeText = EditorGUIUtility.TrTextContent("Bounding Box Mode", "The mode in which the bounding box is computed. A 3D grid of interpolated light probes will be generated inside this bounding box.\n\nAutomatic Local - the local-space bounding box of the Renderer is used.\n\nAutomatic Global - a bounding box is computed which encloses the current Renderer and all the Renderers down the hierarchy that have the Light Probes property set to Use Proxy Volume. The bounding box will be world-space aligned.\n\nCustom - a custom bounding box is used. The bounding box is specified in the local-space of the game object."); - public static GUIContent resModeText = EditorGUIUtility.TrTextContent("Resolution Mode", "The mode in which the resolution of the 3D grid of interpolated light probes is specified:\n\nAutomatic - the resolution on each axis is computed using a user-specified number of interpolated light probes per unit area(Density).\n\nCustom - the user can specify a different resolution on each axis."); + public static GUIContent resModeText = EditorGUIUtility.TrTextContent("Resolution Mode", "The mode in which the resolution of the 3D grid of interpolated light probes is specified:\n\nAutomatic - the resolution on each axis is computed using a user-specified number of interpolated light probes per unit area (Density).\n\nCustom - the user can specify a different resolution on each axis."); public static GUIContent probePositionText = EditorGUIUtility.TrTextContent("Probe Position Mode", "The mode in which the interpolated probe positions are generated.\n\nCellCorner - divide the volume in cells and generate interpolated probe positions in the corner/edge of the cells.\n\nCellCenter - divide the volume in cells and generate interpolated probe positions in the center of the cells."); public static GUIContent refreshModeText = EditorGUIUtility.TrTextContent("Refresh Mode"); - public static GUIContent qualityText = EditorGUIUtility.TrTextContent("Quality", "Affects the total number of evaluated Spherical Harmonics(SH) bands for Renderers that use a Light Probe Proxy Volume:\n\nLow Quality - uses only 2 bands(L0 and L1) sampled from a LPPV texture. This option might improve the performance by not breaking batching.\n\nNormal Quality - uses all the bands to evaluate the SH. L0 and L1 are sampled from a LPPV texture and L2 is constant per Renderer."); + public static GUIContent qualityText = EditorGUIUtility.TrTextContent("Quality", "Affects the total number of evaluated Spherical Harmonics(SH) bands for Renderers that use a Light Probe Proxy Volume:\n\nLow Quality - uses only 2 bands (L0 and L1) sampled from a LPPV texture. This option might improve the performance by not breaking batching.\n\nNormal Quality - uses all the bands to evaluate the SH. L0 and L1 are sampled from a LPPV texture and L2 is constant per Renderer."); public static GUIContent[] bbMode = (Enum.GetNames(typeof(LightProbeProxyVolume.BoundingBoxMode)).Select(x => ObjectNames.NicifyVariableName(x)).ToArray()).Select(x => new GUIContent(x)).ToArray(); public static GUIContent[] resMode = (Enum.GetNames(typeof(LightProbeProxyVolume.ResolutionMode)).Select(x => ObjectNames.NicifyVariableName(x)).ToArray()).Select(x => new GUIContent(x)).ToArray(); public static GUIContent[] probePositionMode = (Enum.GetNames(typeof(LightProbeProxyVolume.ProbePositionMode)).Select(x => ObjectNames.NicifyVariableName(x)).ToArray()).Select(x => new GUIContent(x)).ToArray(); diff --git a/Editor/Mono/Inspector/LightingSettingsInspector.cs b/Editor/Mono/Inspector/LightingSettingsInspector.cs index b1201cff35..e54e2683b2 100644 --- a/Editor/Mono/Inspector/LightingSettingsInspector.cs +++ b/Editor/Mono/Inspector/LightingSettingsInspector.cs @@ -15,7 +15,7 @@ internal class LightingSettingsInspector { static class Styles { - public static readonly GUIContent OptimizeRealtimeUVs = EditorGUIUtility.TrTextContent("Optimize", "Specifies whether the authored mesh UVs get optimized for Realtime Global Illumination or not. When enabled, the authored UVs can get merged, scaled, and packed for optimisation purposes. When disabled, the authored UVs will get scaled and packed, but not merged."); + public static readonly GUIContent OptimizeRealtimeUVs = EditorGUIUtility.TrTextContent("Optimize", "Specifies whether the authored mesh UVs get optimized for Realtime Global Illumination or not. When enabled, the authored UVs can get merged, scaled, and packed for optimization purposes. When disabled, the authored UVs will get scaled and packed, but not merged."); public static readonly GUIContent IgnoreNormalsForChartDetection = EditorGUIUtility.TrTextContent("Ignore Normals", "When enabled, prevents the UV charts from being split during the precompute process for Realtime Global Illumination lighting."); public static readonly int[] MinimumChartSizeValues = { 2, 4 }; public static readonly GUIContent[] MinimumChartSizeStrings = @@ -27,7 +27,7 @@ static class Styles public static readonly GUIContent MinimumChartSize = EditorGUIUtility.TrTextContent("Min Chart Size", "Specifies the minimum texel size used for a UV chart. If stitching is required, a value of 4 will create a chart of 4x4 texels to store lighting and directionality. If stitching is not required, a value of 2 will reduce the texel density and provide better lighting build times and run time performance."); public static readonly GUIContent ImportantGI = EditorGUIUtility.TrTextContent("Prioritize Illumination", "When enabled, the object will be marked as a priority object and always included in lighting calculations. Useful for objects that will be strongly emissive to make sure that other objects will be illuminated by this object."); public static readonly GUIContent StitchLightmapSeams = EditorGUIUtility.TrTextContent("Stitch Seams", "When enabled, seams in baked lightmaps will get smoothed."); - public static readonly GUIContent AutoUVMaxDistance = EditorGUIUtility.TrTextContent("Max Distance", "Specifies the maximum worldspace distance to be used for UV chart simplification. If charts are within this distance they will be simplified for optimization purposes."); + public static readonly GUIContent AutoUVMaxDistance = EditorGUIUtility.TrTextContent("Max Distance", "Specifies the maximum worldspace distance to be used for UV chart simplification. If charts are within this distance, they will be simplified for optimization purposes."); public static readonly GUIContent AutoUVMaxAngle = EditorGUIUtility.TrTextContent("Max Angle", "Specifies the maximum angle in degrees between faces sharing a UV edge. If the angle between the faces is below this value, the UV charts will be simplified."); public static readonly GUIContent LightmapParameters = EditorGUIUtility.TrTextContent("Lightmap Parameters", "Allows the adjustment of advanced parameters that affect the process of generating a lightmap for an object using global illumination."); public static readonly GUIContent AtlasTilingX = EditorGUIUtility.TrTextContent("Tiling X"); diff --git a/Editor/Mono/Inspector/LineRendererCurveEditor.cs b/Editor/Mono/Inspector/LineRendererCurveEditor.cs index e99a67f068..dbd876d242 100644 --- a/Editor/Mono/Inspector/LineRendererCurveEditor.cs +++ b/Editor/Mono/Inspector/LineRendererCurveEditor.cs @@ -110,10 +110,24 @@ public void CheckCurveChangedExternally() } else if (cw != null) { - if (cw.curve.length == 0) - m_Refresh = true; - else if (propCurve.length >= 1 && propCurve.keys[0].value != cw.curve.keys[0].value) + if (cw.curve.length == 0 || cw.curve.length != propCurve.length) + { m_Refresh = true; + } + else + { + var curveKeys = cw.curve.keys; + var propKeys = propCurve.keys; + + for (int i = 0; i < curveKeys.Length; i++) + { + if (!propKeys[i].Equals(curveKeys[i])) + { + m_Refresh = true; + break; + } + } + } } } else if (cw != null) diff --git a/Editor/Mono/Inspector/LineRendererEditor.cs b/Editor/Mono/Inspector/LineRendererEditor.cs index 841b5c6735..2fc2840021 100644 --- a/Editor/Mono/Inspector/LineRendererEditor.cs +++ b/Editor/Mono/Inspector/LineRendererEditor.cs @@ -26,7 +26,7 @@ private class Styles public readonly GUIContent normalOffset = EditorGUIUtility.TrTextContent("Offset", "The offset applied to created points either from the scene camera or raycast normal, when using physics."); public readonly GUIContent numCapVertices = EditorGUIUtility.TrTextContent("End Cap Vertices", "How many vertices to add at each end."); public readonly GUIContent numCornerVertices = EditorGUIUtility.TrTextContent("Corner Vertices", "How many vertices to add for each corner."); - public readonly GUIContent pointSeparation = EditorGUIUtility.TrTextContent("Min Vertex Distance", "When dragging the mouse a new point will be created after the distance has been exceeded."); + public readonly GUIContent pointSeparation = EditorGUIUtility.TrTextContent("Min Vertex Distance", "When dragging the mouse, a new point will be created after the distance has been exceeded."); public readonly GUIContent positions = EditorGUIUtility.TrTextContent("Positions"); public readonly GUIContent propertyMenuContent = EditorGUIUtility.TrTextContent("Delete Selected Array Elements"); public readonly GUIContent showWireframe = EditorGUIUtility.TrTextContent("Show Wireframe", "Show the wireframe visualizing the line."); @@ -483,6 +483,11 @@ private void InternalOnSceneView() { case EditMode.SceneViewEditMode.LineRendererEdit: m_PointEditor.EditSceneGUI(); + + // We need to wait for m_Positions to be updated next frame or we risk calling SetSelection with invalid indexes. + if (m_PointEditor.Count != m_Positions.arraySize) + break; + if (m_Positions.arraySize != m_PositionsView.GetRows().Count) { m_PositionsView.Reload(); diff --git a/Editor/Mono/Inspector/MaterialEditor.cs b/Editor/Mono/Inspector/MaterialEditor.cs index 7b8f0de03f..bc0f0bf64f 100644 --- a/Editor/Mono/Inspector/MaterialEditor.cs +++ b/Editor/Mono/Inspector/MaterialEditor.cs @@ -6,8 +6,10 @@ using System.Collections.Generic; using System.Linq; using UnityEditor.IMGUI.Controls; +using UnityEditor.UIElements; using UnityEngine; using UnityEditorInternal; +using UnityEngine.UIElements; using Object = UnityEngine.Object; namespace UnityEditor @@ -420,7 +422,7 @@ public ShaderDropdownItem(string prefix, string fullName, string shaderName) { m_FullName = fullName; m_Prefix = prefix; - id = (prefix + fullName).GetHashCode(); + id = (prefix + fullName + shaderName).GetHashCode(); } } @@ -1545,21 +1547,31 @@ public bool DidModifyAnimationModeMaterialProperty(MaterialProperty property, in static Renderer[] GetAssociatedRenderersFromInspector() { - List renderers = new List(); - if (InspectorWindow.s_CurrentInspectorWindow != null) + var imguicontainer = UIElementsUtility.GetCurrentIMGUIContainer(); + if (imguicontainer != null) { - Editor[] editors = InspectorWindow.s_CurrentInspectorWindow.tracker.activeEditors; - foreach (var editor in editors) + var editorElement = imguicontainer.GetFirstAncestorOfType(); + if (editorElement != null) { - foreach (Object target in editor.targets) - { - var renderer = target as Renderer; - if (renderer) - renderers.Add(renderer); - } + return GetAssociatedRenderersFromEditors(editorElement.m_Editors); } } + return new Renderer[0]; + } + + internal static Renderer[] GetAssociatedRenderersFromEditors(IEnumerable editors) + { + List renderers = new List(); + foreach (var editor in editors) + { + foreach (Object target in editor.targets) + { + var renderer = target as Renderer; + if (renderer) + renderers.Add(renderer); + } + } return renderers.ToArray(); } diff --git a/Editor/Mono/Inspector/MinMaxCurvePropertyDrawer.cs b/Editor/Mono/Inspector/MinMaxCurvePropertyDrawer.cs index 2cf6d612fc..876d18461b 100644 --- a/Editor/Mono/Inspector/MinMaxCurvePropertyDrawer.cs +++ b/Editor/Mono/Inspector/MinMaxCurvePropertyDrawer.cs @@ -22,6 +22,7 @@ class PropertyData } internal bool isNativeProperty { get; set; } + internal string xAxisLabel { get; set; } = "time"; // Its possible that the PropertyDrawer may be used to draw more than one MinMaxCurve property(arrays, lists) Dictionary m_PropertyDataPerPropertyPath = new Dictionary(); @@ -125,11 +126,11 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten break; case MinMaxCurveState.k_Curve: - DoMinMaxCurvesField(fieldRect, m_Property.curveMax.GetHashCode(), m_Property.curveMax, null, m_Property.curveMultiplier, s_Styles.curveColor, s_Styles.curveBackgroundColor); + DoMinMaxCurvesField(fieldRect, m_Property.curveMax.GetHashCode(), m_Property.curveMax, null, m_Property.curveMultiplier, s_Styles.curveColor, s_Styles.curveBackgroundColor, xAxisLabel); break; case MinMaxCurveState.k_TwoCurves: - DoMinMaxCurvesField(fieldRect, m_Property.curveMin.GetHashCode(), m_Property.curveMax, m_Property.curveMin, m_Property.curveMultiplier, s_Styles.curveColor, s_Styles.curveBackgroundColor); + DoMinMaxCurvesField(fieldRect, m_Property.curveMin.GetHashCode(), m_Property.curveMax, m_Property.curveMin, m_Property.curveMultiplier, s_Styles.curveColor, s_Styles.curveBackgroundColor, xAxisLabel); break; case MinMaxCurveState.k_TwoScalars: @@ -148,7 +149,7 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten } } - static void DoMinMaxCurvesField(Rect position, int id, SerializedProperty propertyMax, SerializedProperty propertyMin, SerializedProperty scalar, Color color, Color backgroundColor) + static void DoMinMaxCurvesField(Rect position, int id, SerializedProperty propertyMax, SerializedProperty propertyMin, SerializedProperty scalar, Color color, Color backgroundColor, string xLabel) { var evt = Event.current; @@ -159,6 +160,7 @@ static void DoMinMaxCurvesField(Rect position, int id, SerializedProperty proper s_CurveId = id; if (MinMaxCurveEditorWindow.visible) { + MinMaxCurveEditorWindow.xAxisLabel = xLabel; MinMaxCurveEditorWindow.SetCurves(propertyMax, propertyMin, scalar, color); MinMaxCurveEditorWindow.ShowPopup(GUIView.current); } @@ -167,6 +169,7 @@ static void DoMinMaxCurvesField(Rect position, int id, SerializedProperty proper { if (MinMaxCurveEditorWindow.visible && Event.current.type == EventType.Repaint) { + MinMaxCurveEditorWindow.xAxisLabel = xLabel; MinMaxCurveEditorWindow.SetCurves(propertyMax, propertyMin, scalar, color); MinMaxCurveEditorWindow.instance.Repaint(); } @@ -180,6 +183,7 @@ static void DoMinMaxCurvesField(Rect position, int id, SerializedProperty proper { s_CurveId = id; GUIUtility.keyboardControl = id; + MinMaxCurveEditorWindow.xAxisLabel = xLabel; MinMaxCurveEditorWindow.SetCurves(propertyMax, propertyMin, scalar, color); MinMaxCurveEditorWindow.ShowPopup(GUIView.current); evt.Use(); @@ -217,6 +221,7 @@ static void DoMinMaxCurvesField(Rect position, int id, SerializedProperty proper if (evt.MainActionKeyForControl(id)) { s_CurveId = id; + MinMaxCurveEditorWindow.xAxisLabel = xLabel; MinMaxCurveEditorWindow.SetCurves(propertyMax, propertyMin, scalar, color); MinMaxCurveEditorWindow.ShowPopup(GUIView.current); evt.Use(); diff --git a/Editor/Mono/Inspector/ParticleSystemForceFieldInspector.cs b/Editor/Mono/Inspector/ParticleSystemForceFieldInspector.cs index 5a696abe39..94530057fd 100644 --- a/Editor/Mono/Inspector/ParticleSystemForceFieldInspector.cs +++ b/Editor/Mono/Inspector/ParticleSystemForceFieldInspector.cs @@ -35,6 +35,8 @@ internal class ParticleSystemForceFieldInspector : Editor private static PropertyInfo s_GravityFocusProperty = typeof(ParticleSystemForceField).GetProperty("gravityFocus"); private static PropertyInfo s_LengthProperty = typeof(ParticleSystemForceField).GetProperty("length"); + private static readonly string s_UndoString = L10n.Tr("Modify {0}"); + private SerializedProperty m_Shape; private SerializedProperty m_StartRange; private SerializedProperty m_EndRange; @@ -122,15 +124,15 @@ void OnEnable() m_VectorFieldSpeed = serializedObject.FindProperty("m_Parameters.m_VectorFieldSpeedCurve"); m_VectorFieldAttraction = serializedObject.FindProperty("m_Parameters.m_VectorFieldAttractionCurve"); - m_DirectionDrawerX = new MinMaxCurvePropertyDrawer() { isNativeProperty = true }; - m_DirectionDrawerY = new MinMaxCurvePropertyDrawer() { isNativeProperty = true }; - m_DirectionDrawerZ = new MinMaxCurvePropertyDrawer() { isNativeProperty = true }; - m_GravityDrawer = new MinMaxCurvePropertyDrawer() { isNativeProperty = true }; - m_RotationSpeedDrawer = new MinMaxCurvePropertyDrawer() { isNativeProperty = true }; - m_RotationAttractionDrawer = new MinMaxCurvePropertyDrawer() { isNativeProperty = true }; - m_DragDrawer = new MinMaxCurvePropertyDrawer() { isNativeProperty = true }; - m_VectorFieldSpeedDrawer = new MinMaxCurvePropertyDrawer() { isNativeProperty = true }; - m_VectorFieldAttractionDrawer = new MinMaxCurvePropertyDrawer() { isNativeProperty = true }; + m_DirectionDrawerX = new MinMaxCurvePropertyDrawer() { isNativeProperty = true, xAxisLabel = "distance" }; + m_DirectionDrawerY = new MinMaxCurvePropertyDrawer() { isNativeProperty = true, xAxisLabel = "distance" }; + m_DirectionDrawerZ = new MinMaxCurvePropertyDrawer() { isNativeProperty = true, xAxisLabel = "distance" }; + m_GravityDrawer = new MinMaxCurvePropertyDrawer() { isNativeProperty = true, xAxisLabel = "distance" }; + m_RotationSpeedDrawer = new MinMaxCurvePropertyDrawer() { isNativeProperty = true, xAxisLabel = "distance" }; + m_RotationAttractionDrawer = new MinMaxCurvePropertyDrawer() { isNativeProperty = true, xAxisLabel = "distance" }; + m_DragDrawer = new MinMaxCurvePropertyDrawer() { isNativeProperty = true, xAxisLabel = "distance" }; + m_VectorFieldSpeedDrawer = new MinMaxCurvePropertyDrawer() { isNativeProperty = true, xAxisLabel = "distance" }; + m_VectorFieldAttractionDrawer = new MinMaxCurvePropertyDrawer() { isNativeProperty = true, xAxisLabel = "distance" }; } static void DrawMinMaxCurveField(SerializedProperty property, MinMaxCurvePropertyDrawer drawer, GUIContent label) @@ -273,7 +275,7 @@ private static void DrawSphere(PropertyInfo radiusProp, ParticleSystemForceField s_SphereBoundsHandle.DrawHandle(); if (EditorGUI.EndChangeCheck()) { - Undo.RecordObject(target, string.Format("Modify {0}", ObjectNames.NicifyVariableName(target.GetType().Name))); + Undo.RecordObject(target, string.Format(s_UndoString, ObjectNames.NicifyVariableName(target.GetType().Name))); radiusProp.SetValue(target, s_SphereBoundsHandle.radius / multiplyByRadius, null); } } @@ -286,7 +288,7 @@ private static void DrawHemisphere(PropertyInfo radiusProp, ParticleSystemForceF float newRadius = Handles.DoSimpleRadiusHandle(Quaternion.Euler(-90, 0, 0), Vector3.zero, oldRadius, true); if (EditorGUI.EndChangeCheck()) { - Undo.RecordObject(target, string.Format("Modify {0}", ObjectNames.NicifyVariableName(target.GetType().Name))); + Undo.RecordObject(target, string.Format(s_UndoString, ObjectNames.NicifyVariableName(target.GetType().Name))); radiusProp.SetValue(target, newRadius / multiplyByRadius, null); } } @@ -306,7 +308,7 @@ private static void DrawCylinder(PropertyInfo radiusProp, PropertyInfo lengthPro s_SphereBoundsHandle.DrawHandle(); if (EditorGUI.EndChangeCheck()) { - Undo.RecordObject(target, string.Format("Modify {0}", ObjectNames.NicifyVariableName(target.GetType().Name))); + Undo.RecordObject(target, string.Format(s_UndoString, ObjectNames.NicifyVariableName(target.GetType().Name))); radiusProp.SetValue(target, s_SphereBoundsHandle.radius / multiplyByRadius, null); } } @@ -317,7 +319,7 @@ private static void DrawCylinder(PropertyInfo radiusProp, PropertyInfo lengthPro lengthHalf = Handles.SizeSlider(Vector3.zero, -Vector3.up, lengthHalf); if (EditorGUI.EndChangeCheck()) { - Undo.RecordObject(target, string.Format("Modify {0}", ObjectNames.NicifyVariableName(target.GetType().Name))); + Undo.RecordObject(target, string.Format(s_UndoString, ObjectNames.NicifyVariableName(target.GetType().Name))); lengthProp.SetValue(target, Mathf.Max(0.0f, lengthHalf * 2.0f), null); } @@ -339,7 +341,7 @@ private static void DrawBox(PropertyInfo extentProp, ParticleSystemForceField ta s_BoxBoundsHandle.DrawHandle(); if (EditorGUI.EndChangeCheck()) { - Undo.RecordObject(target, string.Format("Modify {0}", ObjectNames.NicifyVariableName(target.GetType().Name))); + Undo.RecordObject(target, string.Format(s_UndoString, ObjectNames.NicifyVariableName(target.GetType().Name))); extentProp.SetValue(target, s_BoxBoundsHandle.radius / multiplyByRadius, null); } } diff --git a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs index 2b52f10cdf..b305c532a7 100644 --- a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs +++ b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs @@ -48,7 +48,7 @@ static Styles() class SettingsContent { - public static readonly GUIContent colorSpaceAndroidWarning = EditorGUIUtility.TrTextContent("Linear colorspace requires OpenGL ES 3.0 or Vulkan, uncheck 'Automatic Graphics API' to remove OpenGL ES 2 API, Blit Type must be Always Blit or Auto and 'Minimum API Level' must be at least Android 4.3"); + public static readonly GUIContent colorSpaceAndroidWarning = EditorGUIUtility.TrTextContent("Linear colorspace requires OpenGL ES 3.0 or Vulkan, uncheck 'Automatic Graphics API' to remove OpenGL ES 2 API, Blit Type for non-SRP projects must be Always Blit or Auto and 'Minimum API Level' must be at least Android 4.3"); public static readonly GUIContent colorSpaceWebGLWarning = EditorGUIUtility.TrTextContent("Linear colorspace requires WebGL 2.0, uncheck 'Automatic Graphics API' to remove WebGL 1.0 API. WARNING: If DXT sRGB is not supported by the browser, texture will be decompressed"); public static readonly GUIContent colorSpaceIOSWarning = EditorGUIUtility.TrTextContent("Linear colorspace requires Metal API only. Uncheck 'Automatic Graphics API' and remove OpenGL ES 2/3 APIs."); public static readonly GUIContent recordingInfo = EditorGUIUtility.TrTextContent("Reordering the list will switch editor to the first available platform"); @@ -60,7 +60,7 @@ class SettingsContent public static readonly GUIContent cursorHotspot = EditorGUIUtility.TrTextContent("Cursor Hotspot"); public static readonly GUIContent defaultCursor = EditorGUIUtility.TrTextContent("Default Cursor"); public static readonly GUIContent defaultIcon = EditorGUIUtility.TrTextContent("Default Icon"); - public static readonly GUIContent vertexChannelCompressionMask = EditorGUIUtility.TrTextContent("Vertex Compression*", "Select which vertex channels should be compressed. Compression can save memory and bandwidth but precision will be lower."); + public static readonly GUIContent vertexChannelCompressionMask = EditorGUIUtility.TrTextContent("Vertex Compression*", "Select which vertex channels should be compressed. Compression can save memory and bandwidth, but precision will be lower."); public static readonly GUIContent iconTitle = EditorGUIUtility.TrTextContent("Icon"); public static readonly GUIContent resolutionPresentationTitle = EditorGUIUtility.TrTextContent("Resolution and Presentation"); @@ -114,8 +114,12 @@ class SettingsContent public static readonly GUIContent fullscreenWindow = EditorGUIUtility.TrTextContent("Fullscreen Window"); public static readonly GUIContent maximizedWindow = EditorGUIUtility.TrTextContent("Maximized Window"); public static readonly GUIContent windowed = EditorGUIUtility.TrTextContent("Windowed"); + public static readonly GUIContent displayResolutionDialogEnabledLabel = EditorGUIUtility.TrTextContent("Enabled (Deprecated)"); + public static readonly GUIContent displayResolutionDialogHiddenLabel = EditorGUIUtility.TrTextContent("Hidden by Default (Deprecated)"); + public static readonly GUIContent displayResolutionDialogDeprecationWarning = EditorGUIUtility.TrTextContent("The Display Resolution Dialog has been deprecated and will be removed in a future version."); public static readonly GUIContent visibleInBackground = EditorGUIUtility.TrTextContent("Visible In Background"); public static readonly GUIContent allowFullscreenSwitch = EditorGUIUtility.TrTextContent("Allow Fullscreen Switch"); + public static readonly GUIContent useFlipModelSwapChain = EditorGUIUtility.TrTextContent("Use DXGI Flip Model Swapchain for D3D11", "Flip model ensures the best performance. Disable this to fallback to Windows 7-style BltBlt model. This setting affects only D3D11 graphics API."); public static readonly GUIContent use32BitDisplayBuffer = EditorGUIUtility.TrTextContent("Use 32-bit Display Buffer*", "If set Display Buffer will be created to hold 32-bit color values. Use it only if you see banding, as it has performance implications."); public static readonly GUIContent disableDepthAndStencilBuffers = EditorGUIUtility.TrTextContent("Disable Depth and Stencil*"); public static readonly GUIContent preserveFramebufferAlpha = EditorGUIUtility.TrTextContent("Render Over Native UI*", "Enable this option ONLY if you want Unity to render on top of the native Android or iOS UI."); @@ -141,7 +145,7 @@ class SettingsContent public static readonly GUIContent graphicsJobsMode = EditorGUIUtility.TrTextContent("Graphics Jobs Mode*"); public static readonly GUIContent applicationBuildNumber = EditorGUIUtility.TrTextContent("Build"); public static readonly GUIContent appleDeveloperTeamID = EditorGUIUtility.TrTextContent("iOS Developer Team ID", "Developers can retrieve their Team ID by visiting the Apple Developer site under Account > Membership."); - public static readonly GUIContent useOnDemandResources = EditorGUIUtility.TrTextContent("Use on demand resources*"); + public static readonly GUIContent useOnDemandResources = EditorGUIUtility.TrTextContent("Use on-demand resources*"); public static readonly GUIContent gcIncremental = EditorGUIUtility.TrTextContent("Use incremental GC (Experimental)", "With incremental Garbage Collection, the Garbage Collector will try to time-slice the collection task into multiple steps, to avoid long GC times preventing content from running smoothly."); public static readonly GUIContent accelerometerFrequency = EditorGUIUtility.TrTextContent("Accelerometer Frequency*"); public static readonly GUIContent cameraUsageDescription = EditorGUIUtility.TrTextContent("Camera Usage Description*", "String shown to the user when requesting permission to use the device camera. Written to the NSCameraUsageDescription field in Xcode project's info.plist file"); @@ -153,6 +157,7 @@ class SettingsContent public static readonly GUIContent UIRequiresPersistentWiFi = EditorGUIUtility.TrTextContent("Requires Persistent WiFi*"); public static readonly GUIContent iOSAllowHTTPDownload = EditorGUIUtility.TrTextContent("Allow downloads over HTTP (nonsecure)*"); public static readonly GUIContent iOSURLSchemes = EditorGUIUtility.TrTextContent("Supported URL schemes*"); + public static readonly GUIContent iOSExternalAudioInputNotSupported = EditorGUIUtility.TrTextContent("Audio input from Bluetooth microphones is not supported when Mute Other Audio Sources is off."); public static readonly GUIContent aotOptions = EditorGUIUtility.TrTextContent("AOT Compilation Options*"); public static readonly GUIContent require31 = EditorGUIUtility.TrTextContent("Require ES3.1"); public static readonly GUIContent requireAEP = EditorGUIUtility.TrTextContent("Require ES3.1+AEP"); @@ -189,8 +194,8 @@ class SettingsContent public static readonly GUIContent[] activeInputHandlingOptions = new GUIContent[] { EditorGUIUtility.TrTextContent("Input Manager"), EditorGUIUtility.TrTextContent("Input System (Preview)"), EditorGUIUtility.TrTextContent("Both") }; public static readonly GUIContent lightmapEncodingLabel = EditorGUIUtility.TrTextContent("Lightmap Encoding", "Affects the encoding scheme and compression format of the lightmaps."); public static readonly GUIContent[] lightmapEncodingNames = { EditorGUIUtility.TrTextContent("Low Quality"), EditorGUIUtility.TrTextContent("Normal Quality"), EditorGUIUtility.TrTextContent("High Quality")}; - public static readonly GUIContent lightmapStreamingEnabled = EditorGUIUtility.TrTextContent("Lightmap Streaming Enabled", "Only load larger lightmap mip maps as needed to render the current game cameras. Requires texture streaming to be enabled in quality settings. This value is applied to the light map textures as they are generated."); - public static readonly GUIContent lightmapStreamingPriority = EditorGUIUtility.TrTextContent("Streaming Priority", "Lightmap mip map streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127. This value is applied to the light map textures as they are generated."); + public static readonly GUIContent lightmapStreamingEnabled = EditorGUIUtility.TrTextContent("Lightmap Streaming Enabled", "Only load larger lightmap mipmaps as needed to render the current game cameras. Requires texture streaming to be enabled in quality settings. This value is applied to the light map textures as they are generated."); + public static readonly GUIContent lightmapStreamingPriority = EditorGUIUtility.TrTextContent("Streaming Priority", "Lightmap mipmap streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127. This value is applied to the light map textures as they are generated."); public static readonly GUIContent lightmapQualityAndroidWarning = EditorGUIUtility.TrTextContent("The selected Lightmap Encoding requires OpenGL ES 3.0 or Vulkan. Uncheck 'Automatic Graphics API' and remove OpenGL ES 2 API. Additionally, 'Minimum API Level' must be at least Android 4.3"); public static readonly GUIContent lightmapQualityIOSWarning = EditorGUIUtility.TrTextContent("The selected Lightmap Encoding requires Metal API only. Uncheck 'Automatic Graphics API' and remove OpenGL ES APIs."); public static readonly GUIContent monoNotSupportediOS11WarningGUIContent = EditorGUIUtility.TrTextContent("Mono is not supported on iOS11 and above."); @@ -322,6 +327,7 @@ PlayerSettingsSplashScreenEditor splashScreenEditor SerializedProperty m_VisibleInBackground; SerializedProperty m_AllowFullscreenSwitch; SerializedProperty m_ForceSingleInstance; + SerializedProperty m_UseFlipModelSwapchain; SerializedProperty m_RunInBackground; SerializedProperty m_CaptureSingleScreen; @@ -481,6 +487,7 @@ void OnEnable() m_SkinOnGPU = FindPropertyAssert("gpuSkinning"); m_GraphicsJobs = FindPropertyAssert("graphicsJobs"); m_ForceSingleInstance = FindPropertyAssert("forceSingleInstance"); + m_UseFlipModelSwapchain = FindPropertyAssert("useFlipModelSwapchain"); m_RequireES31 = FindPropertyAssert("openGLRequireES31"); m_RequireES31AEP = FindPropertyAssert("openGLRequireES31AEP"); @@ -498,10 +505,8 @@ void OnEnable() } for (int i = 0; i < m_SectionAnimators.Length; i++) - m_SectionAnimators[i] = new AnimBool(m_SelectedSection.value == i, Repaint); - - m_ShowDefaultIsNativeResolution.valueChanged.AddListener(Repaint); - m_ShowResolution.valueChanged.AddListener(Repaint); + m_SectionAnimators[i] = new AnimBool(m_SelectedSection.value == i); + SetValueChangeListeners(Repaint); m_VRSettings = new VR.PlayerSettingsEditorVR(this); @@ -512,13 +517,19 @@ void OnEnable() s_GraphicsDeviceLists.Clear(); } - public void SetSectionOpenListener(UnityAction action) + public void SetValueChangeListeners(UnityAction action) { for (int i = 0; i < m_SectionAnimators.Length; i++) { m_SectionAnimators[i].valueChanged.RemoveAllListeners(); m_SectionAnimators[i].valueChanged.AddListener(action); } + + m_ShowDefaultIsNativeResolution.valueChanged.RemoveAllListeners(); + m_ShowDefaultIsNativeResolution.valueChanged.AddListener(action); + + m_ShowResolution.valueChanged.RemoveAllListeners(); + m_ShowResolution.valueChanged.AddListener(action); } public override bool UseDefaultMargins() @@ -934,6 +945,12 @@ public void ResolutionSectionGUI(BuildTargetGroup targetGroup, ISettingEditorExt GUILayout.Label(SettingsContent.standalonePlayerOptionsTitle, EditorStyles.boldLabel); EditorGUILayout.PropertyField(m_CaptureSingleScreen); EditorGUILayout.PropertyField(m_DisplayResolutionDialog); + + if (m_DisplayResolutionDialog.intValue > 0) + { + EditorGUILayout.HelpBox(SettingsContent.displayResolutionDialogDeprecationWarning.text, MessageType.Warning, true); + } + EditorGUILayout.PropertyField(m_UsePlayerLog); EditorGUILayout.PropertyField(m_ResizableWindow); @@ -942,6 +959,7 @@ public void ResolutionSectionGUI(BuildTargetGroup targetGroup, ISettingEditorExt EditorGUILayout.PropertyField(m_AllowFullscreenSwitch, SettingsContent.allowFullscreenSwitch); EditorGUILayout.PropertyField(m_ForceSingleInstance); + EditorGUILayout.PropertyField(m_UseFlipModelSwapchain, SettingsContent.useFlipModelSwapChain); EditorGUILayout.PropertyField(m_SupportedAspectRatios, true); EditorGUILayout.Space(); @@ -1056,22 +1074,21 @@ private struct ChangeGraphicsApiAction } private ChangeGraphicsApiAction CheckApplyGraphicsAPIList(BuildTarget target, bool firstEntryChanged) { - bool doChange = true, doReload = false; + bool doRestart = false; // If we're changing the first API for relevant editor, this will cause editor to switch: ask for scene save & confirmation if (firstEntryChanged && WillEditorUseFirstGraphicsAPI(target)) { - doChange = false; if (EditorUtility.DisplayDialog("Changing editor graphics device", - "Changing active graphics API requires reloading all graphics objects, it might take a while", - "Apply", "Cancel")) + "You've changed the active graphics API. This requires a restart of the Editor.", + "Restart Editor", "Not now")) { if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) - doChange = doReload = true; + doRestart = true; } else - doChange = doReload = false; + doRestart = false; } - return new ChangeGraphicsApiAction(doChange, doReload); + return new ChangeGraphicsApiAction(true, doRestart); } private void ApplyChangeGraphicsApiAction(BuildTarget target, GraphicsDeviceType[] apis, ChangeGraphicsApiAction action) @@ -1081,7 +1098,7 @@ private void ApplyChangeGraphicsApiAction(BuildTarget target, GraphicsDeviceType if (action.reloadGfx) { - ShaderUtil.RecreateGfxDevice(); + EditorApplication.RequestCloseAndRelaunchWithCurrentArguments(); GUIUtility.ExitGUI(); } } @@ -1474,33 +1491,30 @@ private void OtherSectionRenderingGUI(BuildPlatform platform, BuildTargetGroup t // Display a warning for platforms that some devices don't support linear rendering if the settings are not fine for linear colorspace if (PlayerSettings.colorSpace == ColorSpace.Linear) { - bool hasMinGraphicsAPI = false; + bool showWarning = false; + GUIContent warningMessage = null; var apis = PlayerSettings.GetGraphicsAPIs(platform.defaultTarget); if (targetGroup == BuildTargetGroup.Android) { - hasMinGraphicsAPI = (apis.Contains(GraphicsDeviceType.Vulkan) || apis.Contains(GraphicsDeviceType.OpenGLES3)) && !apis.Contains(GraphicsDeviceType.OpenGLES2); - - var hasBlitDisabled = PlayerSettings.Android.blitType == AndroidBlitType.Never; - if (hasBlitDisabled || !hasMinGraphicsAPI || (int)PlayerSettings.Android.minSdkVersion < 18) - EditorGUILayout.HelpBox(SettingsContent.colorSpaceAndroidWarning.text, MessageType.Warning); + // SRP should handle blits internally + bool hasBlitDisabled = (PlayerSettings.Android.blitType == AndroidBlitType.Never) && (GraphicsSettings.renderPipelineAsset == null); + showWarning = hasBlitDisabled || apis.Contains(GraphicsDeviceType.OpenGLES2) || (int)PlayerSettings.Android.minSdkVersion < 18; + warningMessage = SettingsContent.colorSpaceAndroidWarning; } else if (targetGroup == BuildTargetGroup.iOS || platform.targetGroup == BuildTargetGroup.tvOS) { - hasMinGraphicsAPI = !apis.Contains(GraphicsDeviceType.OpenGLES3) && !apis.Contains(GraphicsDeviceType.OpenGLES2); - - if (!hasMinGraphicsAPI) - { - EditorGUILayout.HelpBox(SettingsContent.colorSpaceIOSWarning.text, MessageType.Warning); - } + showWarning = apis.Contains(GraphicsDeviceType.OpenGLES3) || apis.Contains(GraphicsDeviceType.OpenGLES2); + warningMessage = SettingsContent.colorSpaceIOSWarning; } - else if ((targetGroup == BuildTargetGroup.WebGL) && !hasMinGraphicsAPI) + else if ((targetGroup == BuildTargetGroup.WebGL)) { - // must have OpenGLES3-only - hasMinGraphicsAPI = apis.Contains(GraphicsDeviceType.OpenGLES3) && !apis.Contains(GraphicsDeviceType.OpenGLES2); - if (!hasMinGraphicsAPI) - EditorGUILayout.HelpBox(SettingsContent.colorSpaceWebGLWarning.text, MessageType.Error); + showWarning = apis.Contains(GraphicsDeviceType.OpenGLES2); + warningMessage = SettingsContent.colorSpaceWebGLWarning; } + + if (showWarning) + EditorGUILayout.HelpBox(warningMessage.text, MessageType.Warning); } // Graphics APIs @@ -1938,6 +1952,8 @@ private void OtherSectionConfigurationGUI(BuildPlatform platform, BuildTargetGro { PlayerSettings.scriptingRuntimeVersion = currentScriptingRuntimeVersions; } + + GUIUtility.ExitGUI(); } } @@ -2051,6 +2067,9 @@ private void OtherSectionConfigurationGUI(BuildPlatform platform, BuildTargetGro if (targetGroup == BuildTargetGroup.iOS || targetGroup == BuildTargetGroup.tvOS || targetGroup == BuildTargetGroup.Android) { EditorGUILayout.PropertyField(m_MuteOtherAudioSources, SettingsContent.muteOtherAudioSources); + + if (m_MuteOtherAudioSources.boolValue == false && targetGroup == BuildTargetGroup.iOS) + EditorGUILayout.HelpBox(SettingsContent.iOSExternalAudioInputNotSupported.text, MessageType.Warning); } // TVOS TODO: check what should stay or go @@ -2582,7 +2601,7 @@ internal static SettingsProvider CreateProjectSettingsProvider() SettingsProvider.GetSearchKeywordsFromGUIContentProperties()); provider.activateHandler = (searchContext, rootElement) => { - (provider.settingsEditor as PlayerSettingsEditor)?.SetSectionOpenListener(provider.Repaint); + (provider.settingsEditor as PlayerSettingsEditor)?.SetValueChangeListeners(provider.Repaint); }; return provider; } diff --git a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs index bf2cc635cb..49415848cd 100644 --- a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs +++ b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsSplashScreenEditor.cs @@ -58,11 +58,12 @@ class Texts { public GUIContent animate = EditorGUIUtility.TrTextContent("Animation"); public GUIContent backgroundColor = EditorGUIUtility.TrTextContent("Background Color", "Background color when no background image is used."); - public GUIContent backgroundImage = EditorGUIUtility.TrTextContent("Background Image", "Image to be used in landscape and portrait(when portrait image is not set)."); + public GUIContent backgroundImage = EditorGUIUtility.TrTextContent("Background Image", "Image to be used in landscape and portrait (when portrait image is not set)."); public GUIContent backgroundPortraitImage = EditorGUIUtility.TrTextContent("Alternate Portrait Image*", "Optional image to be used in portrait mode."); public GUIContent backgroundTitle = EditorGUIUtility.TrTextContent("Background*"); public GUIContent backgroundZoom = EditorGUIUtility.TrTextContent("Background Zoom"); public GUIContent configDialogBanner = EditorGUIUtility.TrTextContent("Application Config Dialog Banner"); + public GUIContent configDialogBannerDeprecationWarning = EditorGUIUtility.TrTextContent("Application Config Dialog Banner is deprecated and will be removed in future versions."); public GUIContent drawMode = EditorGUIUtility.TrTextContent("Draw Mode"); public GUIContent logoDuration = EditorGUIUtility.TrTextContent("Logo Duration", "The time the logo will be shown for."); public GUIContent logosTitle = EditorGUIUtility.TrTextContent("Logos*"); @@ -282,6 +283,11 @@ public void SplashSectionGUI(BuildPlatform platform, BuildTargetGroup targetGrou if (targetGroup == BuildTargetGroup.Standalone) { ObjectReferencePropertyField(m_ResolutionDialogBanner, k_Texts.configDialogBanner); + if (m_ResolutionDialogBanner.objectReferenceValue != null) + { + EditorGUILayout.HelpBox(k_Texts.configDialogBannerDeprecationWarning.text, MessageType.Warning, true); + } + EditorGUILayout.Space(); } diff --git a/Editor/Mono/Inspector/PreviewRenderUtility.cs b/Editor/Mono/Inspector/PreviewRenderUtility.cs index 9545751984..635eb4656f 100644 --- a/Editor/Mono/Inspector/PreviewRenderUtility.cs +++ b/Editor/Mono/Inspector/PreviewRenderUtility.cs @@ -221,7 +221,7 @@ public void BeginPreview(Rect r, GUIStyle previewBackground) { Texture defaultEnvTexture = ReflectionProbe.defaultTexture; - if (Unsupported.SetOverrideRenderSettings(previewScene.scene)) + if (Unsupported.SetOverrideLightingSettings(previewScene.scene)) { RenderSettings.ambientMode = AmbientMode.Flat; RenderSettings.ambientLight = ambientColor; @@ -260,7 +260,7 @@ public void BeginStaticPreview(Rect r) { var oldProbe = RenderSettings.ambientProbe; Texture defaultEnvTexture = ReflectionProbe.defaultTexture; - if (Unsupported.SetOverrideRenderSettings(previewScene.scene)) + if (Unsupported.SetOverrideLightingSettings(previewScene.scene)) { // Most preview windows just want the light probe from the main scene so by default we copy it here. It can then be overridden if user wants. RenderSettings.ambientProbe = oldProbe; @@ -338,7 +338,7 @@ public void BeginPreviewHDR(Rect r, GUIStyle previewBackground) public Texture EndPreview() { - Unsupported.RestoreOverrideRenderSettings(); + Unsupported.RestoreOverrideLightingSettings(); m_SavedState.Restore(); FinishFrame(); @@ -347,7 +347,7 @@ public Texture EndPreview() private void FinishFrame() { - Unsupported.RestoreOverrideRenderSettings(); + Unsupported.RestoreOverrideLightingSettings(); foreach (var light in lights) light.enabled = false; } @@ -366,7 +366,7 @@ internal static void DrawPreview(Rect r, Texture texture) public Texture2D EndStaticPreview() { if (!EditorApplication.isUpdating) - Unsupported.RestoreOverrideRenderSettings(); + Unsupported.RestoreOverrideLightingSettings(); var tmp = RenderTexture.GetTemporary((int)m_TargetRect.width, (int)m_TargetRect.height, 0, GraphicsFormat.R8G8B8A8_UNorm); diff --git a/Editor/Mono/Inspector/PreviewWindow.cs b/Editor/Mono/Inspector/PreviewWindow.cs index 15ffde94ae..0de18d2244 100644 --- a/Editor/Mono/Inspector/PreviewWindow.cs +++ b/Editor/Mono/Inspector/PreviewWindow.cs @@ -3,7 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEngine; -using UnityEngine.Experimental.UIElements; +using UnityEngine.UIElements; namespace UnityEditor { @@ -14,7 +14,7 @@ internal class PreviewWindow : InspectorWindow VisualElement m_previewElement; - VisualElement previewElement => m_previewElement ?? (m_previewElement = rootVisualContainer.Q("preview")); + VisualElement previewElement => m_previewElement ?? (m_previewElement = rootVisualElement.Q(className: "unity-inspector-preview")); public void SetParentInspector(InspectorWindow inspector) { @@ -31,11 +31,11 @@ protected override void OnEnable() AddInspectorWindow(this); var tpl = EditorGUIUtility.Load("UXML/InspectorWindow/PreviewWindow.uxml") as VisualTreeAsset; - var container = tpl.CloneTree(null); - container.AddToClassList("mainContainer"); - rootVisualContainer.shadow.Add(container); + var container = tpl.CloneTree(); + container.AddToClassList(s_MainContainerClassName); + rootVisualElement.hierarchy.Add(container); - rootVisualContainer.AddStyleSheetPath("StyleSheets/InspectorWindow/PreviewWindow.uss"); + rootVisualElement.AddStyleSheetPath("StyleSheets/InspectorWindow/PreviewWindow.uss"); RebuildContentsContainers(); } diff --git a/Editor/Mono/Inspector/QualitySettingsEditor.cs b/Editor/Mono/Inspector/QualitySettingsEditor.cs index 507fe01fe7..ceda524753 100644 --- a/Editor/Mono/Inspector/QualitySettingsEditor.cs +++ b/Editor/Mono/Inspector/QualitySettingsEditor.cs @@ -21,7 +21,7 @@ private class Content public static readonly GUIContent kStreamingMipmapsActive = EditorGUIUtility.TrTextContent("Texture Streaming", "Enable to use texture mipmap streaming."); public static readonly GUIContent kStreamingMipmapsMemoryBudget = EditorGUIUtility.TrTextContent("Memory Budget", "Texture Streaming Budget in MB."); public static readonly GUIContent kStreamingMipmapsRenderersPerFrame = EditorGUIUtility.TrTextContent("Renderers Per Frame", "Number of renderers to process each frame. A lower number will decrease the CPU load at the cost of delaying the mipmap loading."); - public static readonly GUIContent kStreamingMipmapsAddAllCameras = EditorGUIUtility.TrTextContent("Add All Cameras", "Adds all cameras to texture streaming system even if it lacks a StreamingController component. If a camera has the StreamingController component that will control whether its processed or not."); + public static readonly GUIContent kStreamingMipmapsAddAllCameras = EditorGUIUtility.TrTextContent("Add All Cameras", "Adds all cameras to texture streaming system even if it lacks a StreamingController component. If a camera has the StreamingController component, that will control whether it is processed or not."); public static readonly GUIContent kStreamingMipmapsMaxLevelReduction = EditorGUIUtility.TrTextContent("Max Level Reduction", "This is the maximum number of mipmap levels a texture should drop."); public static readonly GUIContent kStreamingMipmapsMaxFileIORequests = EditorGUIUtility.TrTextContent("Max IO Requests", "Maximum number of texture file IO calls active from the texture streaming system at any time."); @@ -524,7 +524,13 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(pixelLightCountProperty); // still valid with SRP + EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(textureQualityProperty); + if (EditorGUI.EndChangeCheck() && usingSRP) + { + RenderPipelineManager.CleanupRenderPipeline(); + } + EditorGUILayout.PropertyField(anisotropicTexturesProperty); if (!usingSRP) @@ -556,27 +562,31 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(streamingMipmapsMaxFileIORequestsProperty, Content.kStreamingMipmapsMaxFileIORequests); EditorGUI.indentLevel--; } + bool shadowMaskSupported = SupportedRenderingFeatures.IsMixedLightingModeSupported(MixedLightingMode.Shadowmask); + if (!usingSRP || shadowMaskSupported) + { + GUILayout.Space(10); - GUILayout.Space(10); + GUILayout.Label(EditorGUIUtility.TempContent("Shadows"), EditorStyles.boldLabel); - GUILayout.Label(EditorGUIUtility.TempContent("Shadows"), EditorStyles.boldLabel); - if (SupportedRenderingFeatures.IsMixedLightingModeSupported(MixedLightingMode.Shadowmask)) - EditorGUILayout.PropertyField(shadowMaskUsageProperty); + if (shadowMaskSupported) + EditorGUILayout.PropertyField(shadowMaskUsageProperty); - if (!usingSRP) - { - EditorGUILayout.PropertyField(shadowsProperty); - EditorGUILayout.PropertyField(shadowResolutionProperty); - EditorGUILayout.PropertyField(shadowProjectionProperty); - EditorGUILayout.PropertyField(shadowDistanceProperty); - EditorGUILayout.PropertyField(shadowNearPlaneOffsetProperty); - EditorGUILayout.PropertyField(shadowCascadesProperty); - - if (shadowCascadesProperty.intValue == 2) - DrawCascadeSplitGUI(ref shadowCascade2SplitProperty); - else if (shadowCascadesProperty.intValue == 4) - DrawCascadeSplitGUI(ref shadowCascade4SplitProperty); + if (!usingSRP) + { + EditorGUILayout.PropertyField(shadowsProperty); + EditorGUILayout.PropertyField(shadowResolutionProperty); + EditorGUILayout.PropertyField(shadowProjectionProperty); + EditorGUILayout.PropertyField(shadowDistanceProperty); + EditorGUILayout.PropertyField(shadowNearPlaneOffsetProperty); + EditorGUILayout.PropertyField(shadowCascadesProperty); + + if (shadowCascadesProperty.intValue == 2) + DrawCascadeSplitGUI(ref shadowCascade2SplitProperty); + else if (shadowCascadesProperty.intValue == 4) + DrawCascadeSplitGUI(ref shadowCascade4SplitProperty); + } } GUILayout.Space(10); diff --git a/Editor/Mono/Inspector/RectTransformEditor.cs b/Editor/Mono/Inspector/RectTransformEditor.cs index 95cb889406..dc117a14cb 100644 --- a/Editor/Mono/Inspector/RectTransformEditor.cs +++ b/Editor/Mono/Inspector/RectTransformEditor.cs @@ -41,7 +41,7 @@ class Styles public GUIContent anchorsContent = EditorGUIUtility.TrTextContent("Anchors"); public GUIContent anchorMinContent = EditorGUIUtility.TrTextContent("Min", "The normalized position in the parent rectangle that the lower left corner is anchored to."); public GUIContent anchorMaxContent = EditorGUIUtility.TrTextContent("Max", "The normalized position in the parent rectangle that the upper right corner is anchored to."); - public GUIContent pivotContent = EditorGUIUtility.TrTextContent("Pivot", "The pivot point specified in normalized values between 0 and 1. The pivot point is the origin of this rectangle. Rotation and scaling is around this point."); + public GUIContent pivotContent = EditorGUIUtility.TrTextContent("Pivot", "The pivot point specified in normalized values between 0 and 1. The pivot point is the origin of this rectangle. Rotation and scaling are around this point."); public GUIContent transformScaleContent = EditorGUIUtility.TrTextContent("Scale", "The local scaling of this Game Object relative to the parent. This scales everything including image borders and text."); public GUIContent rawEditContent; public GUIContent blueprintContent; diff --git a/Editor/Mono/Inspector/ReflectionProbeEditor.cs b/Editor/Mono/Inspector/ReflectionProbeEditor.cs index c9563ffd04..a36d13a86d 100644 --- a/Editor/Mono/Inspector/ReflectionProbeEditor.cs +++ b/Editor/Mono/Inspector/ReflectionProbeEditor.cs @@ -108,7 +108,7 @@ static Styles() public static GUIContent timeSlicing = EditorGUIUtility.TrTextContent("Time Slicing", "If enabled this probe will update over several frames, to help reduce the impact on the frame rate"); public static GUIContent refreshMode = EditorGUIUtility.TrTextContent("Refresh Mode", "Controls how this probe refreshes in the Player"); - public static GUIContent typeText = EditorGUIUtility.TrTextContent("Type", "'Baked Cubemap' uses the 'Auto Baking' mode from the Lighting window. If it is enabled then baking is automatic otherwise manual bake is needed (use the bake button below). \n'Custom' can be used if a custom cubemap is wanted. \n'Realtime' can be used to dynamically re-render the cubemap during runtime (via scripting)."); + public static GUIContent typeText = EditorGUIUtility.TrTextContent("Type", "'Baked Cubemap' uses the 'Auto Baking' mode from the Lighting window. If it is enabled, then baking is automatic otherwise manual bake is needed (use the bake button below). \n'Custom' can be used if a custom cubemap is wanted. \n'Realtime' can be used to dynamically re-render the cubemap during runtime (via scripting)."); public static GUIContent[] reflectionProbeMode = { EditorGUIUtility.TrTextContent("Baked"), EditorGUIUtility.TrTextContent("Custom"), EditorGUIUtility.TrTextContent("Realtime") }; public static int[] reflectionProbeModeValues = { (int)ReflectionProbeMode.Baked, (int)ReflectionProbeMode.Custom, (int)ReflectionProbeMode.Realtime }; diff --git a/Editor/Mono/Inspector/RenderTextureEditor.cs b/Editor/Mono/Inspector/RenderTextureEditor.cs index b20805e217..66b84d5869 100644 --- a/Editor/Mono/Inspector/RenderTextureEditor.cs +++ b/Editor/Mono/Inspector/RenderTextureEditor.cs @@ -4,7 +4,7 @@ using UnityEngine; using System; - +using UnityEngine.Experimental.Rendering; namespace UnityEditor { @@ -16,13 +16,14 @@ private class Styles { public readonly GUIContent size = EditorGUIUtility.TrTextContent("Size", "Size of the render texture in pixels."); public readonly GUIContent cross = EditorGUIUtility.TextContent("x"); - public readonly GUIContent antiAliasing = EditorGUIUtility.TrTextContent("Anti-Aliasing", "Number of anti-aliasing samples."); + public readonly GUIContent antiAliasing = EditorGUIUtility.TrTextContent("Anti-aliasing", "Number of anti-aliasing samples."); public readonly GUIContent colorFormat = EditorGUIUtility.TrTextContent("Color Format", "Format of the color buffer."); public readonly GUIContent depthBuffer = EditorGUIUtility.TrTextContent("Depth Buffer", "Format of the depth buffer."); + public readonly GUIContent enableCompatibleFormat = EditorGUIUtility.TrTextContent("Enable Compatible Color Format", "Lets the color format be changed to compatible and supported formats for the target platform automatically, if the target platform doesn't support the input format."); public readonly GUIContent dimension = EditorGUIUtility.TrTextContent("Dimension", "Is the texture 2D, Cube or 3D?"); public readonly GUIContent enableMipmaps = EditorGUIUtility.TrTextContent("Enable Mip Maps", "This render texture will have Mip Maps."); public readonly GUIContent bindMS = EditorGUIUtility.TrTextContent("Bind multisampled", "If enabled, the texture will not go through an AA resolve if bound to a shader."); - public readonly GUIContent autoGeneratesMipmaps = EditorGUIUtility.TrTextContent("Auto generate Mip Maps", "This render texture automatically generate its Mip Maps."); + public readonly GUIContent autoGeneratesMipmaps = EditorGUIUtility.TrTextContent("Auto generate Mip Maps", "This render texture automatically generates its Mip Maps."); public readonly GUIContent sRGBTexture = EditorGUIUtility.TrTextContent("sRGB (Color RenderTexture)", "RenderTexture content is stored in gamma space. Non-HDR color textures should enable this flag."); public readonly GUIContent useDynamicScale = EditorGUIUtility.TrTextContent("Dynamic Scaling", "Allow the texture to be automatically resized by ScalableBufferManager, to support dynamic resolution."); @@ -58,6 +59,7 @@ protected enum GUIElements SerializedProperty m_Depth; SerializedProperty m_ColorFormat; SerializedProperty m_DepthFormat; + SerializedProperty m_EnableCompatibleFormat; SerializedProperty m_AntiAliasing; SerializedProperty m_EnableMipmaps; SerializedProperty m_AutoGeneratesMipmaps; @@ -74,6 +76,7 @@ protected override void OnEnable() m_AntiAliasing = serializedObject.FindProperty("m_AntiAliasing"); m_ColorFormat = serializedObject.FindProperty("m_ColorFormat"); m_DepthFormat = serializedObject.FindProperty("m_DepthFormat"); + m_EnableCompatibleFormat = serializedObject.FindProperty("m_EnableCompatibleFormat"); m_EnableMipmaps = serializedObject.FindProperty("m_MipMap"); m_AutoGeneratesMipmaps = serializedObject.FindProperty("m_GenerateMips"); m_Dimension = serializedObject.FindProperty("m_Dimension"); @@ -81,17 +84,6 @@ protected override void OnEnable() m_UseDynamicScale = serializedObject.FindProperty("m_UseDynamicScale"); } - public static bool IsHDRFormat(RenderTextureFormat format) - { - return format == RenderTextureFormat.ARGBHalf || - format == RenderTextureFormat.RGB111110Float || - format == RenderTextureFormat.RGFloat || - format == RenderTextureFormat.ARGBFloat || - format == RenderTextureFormat.RFloat || - format == RenderTextureFormat.RGHalf || - format == RenderTextureFormat.RHalf; - } - protected void OnRenderTextureGUI(GUIElements guiElements) { GUI.changed = false; @@ -115,16 +107,33 @@ protected void OnRenderTextureGUI(GUIElements guiElements) if ((guiElements & GUIElements.RenderTargetAAGUI) != 0) EditorGUILayout.IntPopup(m_AntiAliasing, styles.renderTextureAntiAliasing, styles.renderTextureAntiAliasingValues, styles.antiAliasing); + + GraphicsFormat format = (GraphicsFormat)m_ColorFormat.intValue; + GraphicsFormat compatibleFormat = SystemInfo.GetCompatibleFormat(format, FormatUsage.Render); + + using (new EditorGUI.DisabledScope(compatibleFormat == GraphicsFormat.None)) + EditorGUILayout.PropertyField(m_EnableCompatibleFormat, styles.enableCompatibleFormat); + EditorGUILayout.PropertyField(m_ColorFormat, styles.colorFormat); - if ((guiElements & GUIElements.RenderTargetDepthGUI) != 0) - EditorGUILayout.PropertyField(m_DepthFormat, styles.depthBuffer); - bool isHDRRenderTexture = IsHDRFormat((RenderTextureFormat)m_ColorFormat.intValue); - using (new EditorGUI.DisabledScope(isHDRRenderTexture)) + if (compatibleFormat != format) { - EditorGUILayout.PropertyField(m_sRGB, styles.sRGBTexture); + string text = string.Format("Format {0} is not supported on this platform. ", format.ToString()); + if (compatibleFormat != GraphicsFormat.None) + { + if (m_EnableCompatibleFormat.boolValue) + text += string.Format("Using {0} as a compatible format.", compatibleFormat.ToString()); + else + text += string.Format("You may enable Compatible Color Format to fallback automatically to a platform specific comptible format, {0} on this device.", compatibleFormat.ToString()); + } + EditorGUILayout.HelpBox(text, m_EnableCompatibleFormat.boolValue && compatibleFormat != GraphicsFormat.None ? MessageType.Warning : MessageType.Error); } + if ((guiElements & GUIElements.RenderTargetDepthGUI) != 0) + EditorGUILayout.PropertyField(m_DepthFormat, styles.depthBuffer); + + m_sRGB.boolValue = GraphicsFormatUtility.IsSRGBFormat(format); + using (new EditorGUI.DisabledScope(isTexture3D)) { EditorGUILayout.PropertyField(m_EnableMipmaps, styles.enableMipmaps); @@ -178,7 +187,7 @@ public override void OnInspectorGUI() private bool RenderTextureHasDepth() { - if (TextureUtil.IsDepthRTFormat((RenderTextureFormat)m_ColorFormat.enumValueIndex)) + if (GraphicsFormatUtility.IsDepthFormat((GraphicsFormat)m_ColorFormat.enumValueIndex)) return true; return m_DepthFormat.enumValueIndex != 0; @@ -197,12 +206,12 @@ override public string GetInfoString() if (QualitySettings.desiredColorSpace == ColorSpace.Linear) { - bool formatIsHDR = IsHDRFormat(t.format); + bool formatIsHDR = GraphicsFormatUtility.IsIEEE754Format(t.graphicsFormat); bool sRGB = t.sRGB && !formatIsHDR; info += " " + (sRGB ? "sRGB" : "Linear"); } - info += " " + t.format; + info += " " + t.graphicsFormat; info += " " + EditorUtility.FormatBytes(TextureUtil.GetRuntimeMemorySizeLong(t)); return info; diff --git a/Editor/Mono/Inspector/RendererEditorBase.cs b/Editor/Mono/Inspector/RendererEditorBase.cs index 24cefa167b..7009bb6315 100644 --- a/Editor/Mono/Inspector/RendererEditorBase.cs +++ b/Editor/Mono/Inspector/RendererEditorBase.cs @@ -305,7 +305,7 @@ internal static string[] GetFieldsStringArray() } private static string[] m_DefaultRenderingLayerNames; - private static string[] defaultRenderingLayerNames + internal static string[] defaultRenderingLayerNames { get { @@ -328,7 +328,7 @@ private static string[] defaultRenderingLayerNames private SerializedProperty m_RendererPriority; static GUIContent m_RenderingLayerMaskStyle = EditorGUIUtility.TrTextContent("Rendering Layer Mask", "Mask that can be used with SRP DrawRenderers command to filter renderers outside of the normal layering system."); - static GUIContent m_RendererPriorityStyle = EditorGUIUtility.TrTextContent("Transparency Priority", "Priority used for sorting objects on top of material render queue."); + static GUIContent m_RendererPriorityStyle = EditorGUIUtility.TrTextContent("Priority", "Sets the priority value that the render pipeline uses to calculate the rendering order."); protected Probes m_Probes; diff --git a/Editor/Mono/Inspector/ScriptBindings/Editor.bindings.cs b/Editor/Mono/Inspector/ScriptBindings/Editor.bindings.cs index e1593136da..5a1d308fbe 100644 --- a/Editor/Mono/Inspector/ScriptBindings/Editor.bindings.cs +++ b/Editor/Mono/Inspector/ScriptBindings/Editor.bindings.cs @@ -20,6 +20,6 @@ namespace UnityEditor public partial class Editor { // Make a custom editor for /targetObject/ or /objects/. - extern public static Editor CreateEditorWithContext(Object[] targetObjects, Object context, [uei.DefaultValue("null")] Type editorType); + extern static Editor CreateEditorWithContextInternal(Object[] targetObjects, Object context, Type editorType); } } diff --git a/Editor/Mono/Inspector/ScriptExecutionOrderInspector.cs b/Editor/Mono/Inspector/ScriptExecutionOrderInspector.cs index 8a9692060e..fee0b38a94 100644 --- a/Editor/Mono/Inspector/ScriptExecutionOrderInspector.cs +++ b/Editor/Mono/Inspector/ScriptExecutionOrderInspector.cs @@ -134,6 +134,7 @@ public void OnEnable() if (!m_Instances.Contains(this)) m_Instances.Add(this); + EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; EditorApplication.playModeStateChanged += OnPlayModeStateChanged; } @@ -273,9 +274,22 @@ private void Apply() if (Provider.enabled) { - var task = Provider.Checkout(changedScripts.ToArray(), CheckoutMode.Meta); - task.Wait(); - editable = task.success; + var needToCheckout = new AssetList(); + foreach (var s in changedScripts) + { + var asset = Provider.GetAssetByPath(AssetDatabase.GetAssetPath(s)); + if (asset == null) // script might be outside of the project (e.g. in a package) + continue; + if (AssetDatabase.IsMetaFileOpenForEdit(s, StatusQueryOptions.UseCachedIfPossible)) + continue; // might not need a checkout (not connected, etc.) + needToCheckout.Add(asset); + } + if (needToCheckout.Any()) + { + var task = Provider.Checkout(needToCheckout, CheckoutMode.Meta); + task.Wait(); + editable = task.success; + } } if (editable) diff --git a/Editor/Mono/Inspector/ShaderInspector.cs b/Editor/Mono/Inspector/ShaderInspector.cs index ff54acee0e..4052cf80d6 100644 --- a/Editor/Mono/Inspector/ShaderInspector.cs +++ b/Editor/Mono/Inspector/ShaderInspector.cs @@ -36,6 +36,9 @@ internal class ShaderInspector : Editor private const float kSpace = 5f; + const float kValueFieldWidth = 200.0f; + const float kArrayValuePopupBtnWidth = 25.0f; + internal class Styles { public static Texture2D errorIcon = EditorGUIUtility.LoadIcon("console.erroricon.sml"); @@ -50,6 +53,8 @@ internal class Styles public static GUIContent no = EditorGUIUtility.TrTextContent("no"); public static GUIContent builtinShader = EditorGUIUtility.TrTextContent("Built-in shader"); + + public static readonly GUIContent arrayValuePopupButton = EditorGUIUtility.TrTextContent("..."); } static readonly int kErrorViewHash = "ShaderErrorView".GetHashCode(); @@ -106,6 +111,7 @@ public override void OnInspectorGUI() break; } EditorGUILayout.LabelField("Disable batching", disableBatchingString); + ShowKeywords(s); // If any SRP is active, then display the SRP Batcher compatibility status if (RenderPipelineManager.currentPipeline != null) @@ -125,6 +131,27 @@ public override void OnInspectorGUI() } } + private void ShowKeywords(Shader s) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.PrefixLabel("Keywords", EditorStyles.miniButton); + + Rect buttonRect = GUILayoutUtility.GetRect(Styles.arrayValuePopupButton, GUI.skin.button, GUILayout.MinWidth(kValueFieldWidth)); + buttonRect.width = kArrayValuePopupBtnWidth; + if (GUI.Button(buttonRect, Styles.arrayValuePopupButton, EditorStyles.miniButton)) + { + var globalKeywords = ShaderUtil.GetShaderGlobalKeywords(s); + var localKeywords = ShaderUtil.GetShaderLocalKeywords(s); + + PopupWindowWithoutFocus.Show( + buttonRect, + new KeywordsPopup(globalKeywords, localKeywords, 150.0f), + new[] { PopupLocation.Left, PopupLocation.Below, PopupLocation.Right }); + } + + EditorGUILayout.EndHorizontal(); + } + private void ShowShaderCodeArea(Shader s) { ShowSurfaceShaderButton(s); @@ -385,6 +412,60 @@ private static void ShowFixedFunctionShaderButton(Shader s) } } + internal class KeywordsPopup : PopupWindowContent + { + private Vector2 m_ScrollPos = Vector2.zero; + private string[] m_GlobalKeywords; + private string[] m_LocalKeywords; + private bool m_GlobalKeywordsExpended; + private bool m_LocalKeywordsExpended; + private float m_WindowWidth; + + private static readonly GUIStyle m_Style = EditorStyles.miniLabel; + + public KeywordsPopup(string[] globalKeywords, string[] localKeywords, float windowWidth) + { + m_GlobalKeywords = globalKeywords; + m_LocalKeywords = localKeywords; + m_GlobalKeywordsExpended = true; + m_LocalKeywordsExpended = true; + m_WindowWidth = windowWidth; + } + + public override Vector2 GetWindowSize() + { + var numValues = m_GlobalKeywords.Length + m_LocalKeywords.Length + 2; + var lineHeight = m_Style.lineHeight + m_Style.padding.vertical + m_Style.margin.top; + return new Vector2(m_WindowWidth, Math.Min(lineHeight * numValues, 250.0f)); + } + + public override void OnGUI(Rect rect) + { + m_ScrollPos = EditorGUILayout.BeginScrollView(m_ScrollPos); + + m_GlobalKeywordsExpended = KeywordsFoldout(m_GlobalKeywordsExpended, "Global Keywords", m_GlobalKeywords); + m_LocalKeywordsExpended = KeywordsFoldout(m_LocalKeywordsExpended, "Local Keywords", m_LocalKeywords); + + EditorGUILayout.EndScrollView(); + } + + private bool KeywordsFoldout(bool expended, string name, string[] values) + { + expended = EditorGUILayout.Foldout(expended, name, true, m_Style); + + if (expended) + { + EditorGUI.indentLevel++; + for (int i = 0; i < values.Length; ++i) + { + EditorGUILayout.LabelField(values[i], m_Style); + } + EditorGUI.indentLevel--; + } + + return expended; + } + } // Popup window to select which platforms to compile a shader for. internal class ShaderInspectorPlatformsPopup : PopupWindowContent diff --git a/Editor/Mono/Inspector/ShaderVariantCollectionInspector.cs b/Editor/Mono/Inspector/ShaderVariantCollectionInspector.cs index 667c956664..1e03433cc8 100644 --- a/Editor/Mono/Inspector/ShaderVariantCollectionInspector.cs +++ b/Editor/Mono/Inspector/ShaderVariantCollectionInspector.cs @@ -38,20 +38,6 @@ void DisplayAddVariantsWindow(Shader shader, ShaderVariantCollection collection) var data = new AddShaderVariantWindow.PopupData(); data.shader = shader; data.collection = collection; - string[] keywordStrings; - ShaderUtil.GetShaderVariantEntries(shader, collection, out data.types, out keywordStrings); - if (keywordStrings.Length == 0) - { - // nothing available to add - EditorApplication.Beep(); - return; - } - - data.keywords = new string[keywordStrings.Length][]; - for (var i = 0; i < keywordStrings.Length; ++i) - { - data.keywords[i] = keywordStrings[i].Split(' '); - } AddShaderVariantWindow.ShowAddVariantWindow(data); GUIUtility.ExitGUI(); } @@ -156,10 +142,6 @@ internal class PopupData { public Shader shader; public ShaderVariantCollection collection; - // list of all shader variants that are in the shader but not in collection yet - // (for each: pass type and shader keywords) - public int[] types; - public string[][] keywords; } class Styles @@ -183,10 +165,15 @@ class Styles PopupData m_Data; List m_SelectedKeywords; - List m_AvailableKeywords; // Other keywords still available in the currently filtered variants for further narrowing down - List m_FilteredVariants; // Indices of variants that pass the keyword filter + List m_AvailableKeywords; List m_SelectedVariants; // Indices of variants currently selected for adding + int[] m_FilteredVariantTypes; + string[][] m_FilteredVariantKeywords; + + int m_MaxVisibleVariants; + int m_NumFilteredVariants; + public AddShaderVariantWindow() { position = new Rect(100, 100, kMinWindowWidth * 1.5f, kMinWindowHeight * 1.5f); @@ -200,8 +187,6 @@ private void Initialize(PopupData data) m_SelectedKeywords = new List(); m_AvailableKeywords = new List(); m_SelectedVariants = new List(); - m_AvailableKeywords.Sort(); - m_FilteredVariants = new List(); ApplyKeywordFilter(); } @@ -214,34 +199,27 @@ public static void ShowAddVariantWindow(PopupData data) void ApplyKeywordFilter() { - m_FilteredVariants.Clear(); - m_AvailableKeywords.Clear(); - - // Go over all variants and see which ones pass the selected keywords filter - for (var i = 0; i < m_Data.keywords.Length; ++i) + m_MaxVisibleVariants = (int)(CalcVerticalSpaceForVariants() / EditorGUI.kSingleLineHeight); + string[] keywordLists, remainingKeywords; + m_FilteredVariantTypes = new int[m_MaxVisibleVariants]; + + ShaderUtil.GetShaderVariantEntriesFiltered(m_Data.shader, + m_MaxVisibleVariants + 1, // query one more to know if we're truncating + m_SelectedKeywords.ToArray(), + m_Data.collection, + out m_FilteredVariantTypes, + out keywordLists, + out remainingKeywords); + + m_NumFilteredVariants = m_FilteredVariantTypes.Length; + m_FilteredVariantKeywords = new string[m_NumFilteredVariants][]; + for (var i = 0; i < m_NumFilteredVariants; ++i) { - bool containsAll = true; - for (var j = 0; j < m_SelectedKeywords.Count; ++j) - { - if (!m_Data.keywords[i].Contains(m_SelectedKeywords[j])) - { - containsAll = false; - break; - } - } - if (containsAll) - { - // Contains all keywords -> passed the filter - m_FilteredVariants.Add(i); - // Add keywords in this variant that aren't selected yet into "available" set - foreach (var k in m_Data.keywords[i]) - { - if (!m_AvailableKeywords.Contains(k) && !m_SelectedKeywords.Contains(k)) - m_AvailableKeywords.Add(k); - } - } + m_FilteredVariantKeywords[i] = keywordLists[i].Split(' '); } + m_AvailableKeywords.Clear(); + m_AvailableKeywords.InsertRange(0, remainingKeywords); m_AvailableKeywords.Sort(); } @@ -292,7 +270,7 @@ float CalcVerticalSpaceForVariants() void DrawKeywordsList(ref Rect rect, List keywords, bool clickingAddsToSelected) { rect.height = CalcVerticalSpaceForKeywords(); - var displayKeywords = keywords.Select(k => string.IsNullOrEmpty(k) ? "" : k.ToLowerInvariant()).ToList(); + var displayKeywords = keywords.Select(k => k.ToLowerInvariant()).ToList(); GUI.BeginGroup(rect); Rect indentRect = new Rect(4, 0, rect.width, rect.height); @@ -303,11 +281,16 @@ void DrawKeywordsList(ref Rect rect, List keywords, bool clickingAddsToS { if (clickingAddsToSelected) { - m_SelectedKeywords.Add(keywords[i]); - m_SelectedKeywords.Sort(); + if (!m_SelectedKeywords.Contains(keywords[i])) + { + m_SelectedKeywords.Add(keywords[i]); + m_SelectedKeywords.Sort(); + m_AvailableKeywords.Remove(keywords[i]); + } } else { + m_AvailableKeywords.Add(keywords[i]); m_SelectedKeywords.Remove(keywords[i]); } ApplyKeywordFilter(); @@ -347,30 +330,33 @@ private void Draw(Rect windowRect) DrawSectionHeader(ref rect, "Shader variants with these keywords (click to select):", true); - if (m_FilteredVariants.Count > 0) + if (m_NumFilteredVariants > 0) { int maxFilteredLength = (int)(CalcVerticalSpaceForVariants() / EditorGUI.kSingleLineHeight); + if (maxFilteredLength > m_MaxVisibleVariants) // Query data again if we have bigger window than at last query + ApplyKeywordFilter(); + // Display first N variants (don't want to display thousands of them if filter is not narrow) - for (var i = 0; i < Mathf.Min(m_FilteredVariants.Count, maxFilteredLength); ++i) + for (var i = 0; i < Mathf.Min(m_NumFilteredVariants, maxFilteredLength); ++i) { - var index = m_FilteredVariants[i]; - var passType = (UnityEngine.Rendering.PassType)m_Data.types[index]; - var wasSelected = m_SelectedVariants.Contains(index); - var displayString = passType.ToString() + " " + string.Join(" ", m_Data.keywords[index]).ToLowerInvariant(); + var passType = (UnityEngine.Rendering.PassType)m_FilteredVariantTypes[i]; + var wasSelected = m_SelectedVariants.Contains(i); + var keywordString = string.IsNullOrEmpty(m_FilteredVariantKeywords[i][0]) ? "" : string.Join(" ", m_FilteredVariantKeywords[i]); + var displayString = passType.ToString() + " " + keywordString.ToLowerInvariant(); var isSelected = GUI.Toggle(rect, wasSelected, displayString, Styles.sMenuItem); rect.y += rect.height; if (isSelected && !wasSelected) - m_SelectedVariants.Add(index); + m_SelectedVariants.Add(i); else if (!isSelected && wasSelected) - m_SelectedVariants.Remove(index); + m_SelectedVariants.Remove(i); } // show how many variants we skipped due to filter not being narrow enough - if (m_FilteredVariants.Count > maxFilteredLength) + if (m_NumFilteredVariants > maxFilteredLength) { - GUI.Label(rect, string.Format("[{0} more variants skipped]", m_FilteredVariants.Count - maxFilteredLength), EditorStyles.miniLabel); + GUI.Label(rect, "List of variants was cropped. Pick further keywords to narrow the selection.", EditorStyles.miniLabel); rect.y += rect.height; } } @@ -393,7 +379,7 @@ private void Draw(Rect windowRect) for (var i = 0; i < m_SelectedVariants.Count; ++i) { var index = m_SelectedVariants[i]; - var variant = new ShaderVariantCollection.ShaderVariant(m_Data.shader, (UnityEngine.Rendering.PassType)m_Data.types[index], m_Data.keywords[index]); + var variant = new ShaderVariantCollection.ShaderVariant(m_Data.shader, (UnityEngine.Rendering.PassType)m_FilteredVariantTypes[index], m_FilteredVariantKeywords[index]); m_Data.collection.Add(variant); } // Close our popup diff --git a/Editor/Mono/Inspector/SortingGroupEditor.cs b/Editor/Mono/Inspector/SortingGroupEditor.cs index abb39e0716..2f08dfd8c8 100644 --- a/Editor/Mono/Inspector/SortingGroupEditor.cs +++ b/Editor/Mono/Inspector/SortingGroupEditor.cs @@ -17,6 +17,7 @@ internal class SortingGroupEditor : Editor public virtual void OnEnable() { + alwaysAllowExpansion = true; m_SortingOrder = serializedObject.FindProperty("m_SortingOrder"); m_SortingLayerID = serializedObject.FindProperty("m_SortingLayerID"); } diff --git a/Editor/Mono/Inspector/SortingLayerEditorUtility.cs b/Editor/Mono/Inspector/SortingLayerEditorUtility.cs index 079b0dd800..82777af4b6 100644 --- a/Editor/Mono/Inspector/SortingLayerEditorUtility.cs +++ b/Editor/Mono/Inspector/SortingLayerEditorUtility.cs @@ -12,19 +12,41 @@ internal class SortingLayerEditorUtility { private static class Styles { + private static GUIStyle m_BoldPopupStyle; + public static GUIContent m_SortingLayerStyle = EditorGUIUtility.TrTextContent("Sorting Layer", "Name of the Renderer's sorting layer"); public static GUIContent m_SortingOrderStyle = EditorGUIUtility.TrTextContent("Order in Layer", "Renderer's order within a sorting layer"); + + public static GUIStyle boldPopupStyle + { + get + { + if (m_BoldPopupStyle == null) + { + m_BoldPopupStyle = new GUIStyle(EditorStyles.popup); + m_BoldPopupStyle.fontStyle = FontStyle.Bold; + } + return m_BoldPopupStyle; + } + } + } + + internal static bool HasPrefabOverride(SerializedProperty property) + { + return property != null && property.serializedObject.targetObjectsCount == 1 && property.isInstantiatedPrefab && property.prefabOverride; } public static void RenderSortingLayerFields(SerializedProperty sortingOrder, SerializedProperty sortingLayer) { - EditorGUILayout.SortingLayerField(Styles.m_SortingLayerStyle, sortingLayer, EditorStyles.popup, EditorStyles.label); + var hasPrefabOverride = HasPrefabOverride(sortingLayer); + EditorGUILayout.SortingLayerField(Styles.m_SortingLayerStyle, sortingLayer, hasPrefabOverride ? Styles.boldPopupStyle : EditorStyles.popup, hasPrefabOverride ? EditorStyles.boldLabel : EditorStyles.label); EditorGUILayout.PropertyField(sortingOrder, Styles.m_SortingOrderStyle); } public static void RenderSortingLayerFields(Rect r, SerializedProperty sortingOrder, SerializedProperty sortingLayer) { - EditorGUI.SortingLayerField(r, Styles.m_SortingLayerStyle, sortingLayer, EditorStyles.popup, EditorStyles.label); + var hasPrefabOverride = HasPrefabOverride(sortingLayer); + EditorGUI.SortingLayerField(r, Styles.m_SortingLayerStyle, sortingLayer, hasPrefabOverride ? Styles.boldPopupStyle : EditorStyles.popup, hasPrefabOverride ? EditorStyles.boldLabel : EditorStyles.label); r.y += EditorGUIUtility.singleLineHeight; EditorGUI.PropertyField(r, sortingOrder, Styles.m_SortingOrderStyle); } diff --git a/Editor/Mono/Inspector/SpriteRendererEditor.cs b/Editor/Mono/Inspector/SpriteRendererEditor.cs index a6ce11c6af..2614db5e0d 100644 --- a/Editor/Mono/Inspector/SpriteRendererEditor.cs +++ b/Editor/Mono/Inspector/SpriteRendererEditor.cs @@ -24,7 +24,7 @@ private static class Contents public static readonly GUIContent flipYLabel = EditorGUIUtility.TrTextContent("Y", "Sprite vertical flipping"); public static readonly int flipToggleHash = "FlipToggleHash".GetHashCode(); - public static readonly GUIContent fullTileLabel = EditorGUIUtility.TrTextContent("Tile Mode", "Specify the 9 slice tiling behaviour"); + public static readonly GUIContent fullTileLabel = EditorGUIUtility.TrTextContent("Tile Mode", "Specify the 9-slice tiling behaviour"); public static readonly GUIContent fullTileThresholdLabel = EditorGUIUtility.TrTextContent("Stretch Value", "This value defines how much the center portion will stretch before it tiles."); public static readonly GUIContent drawModeLabel = EditorGUIUtility.TrTextContent("Draw Mode", "Specify the draw mode for the sprite"); public static readonly GUIContent widthLabel = EditorGUIUtility.TrTextContent("Width", "The width dimension value for the sprite"); @@ -88,19 +88,6 @@ public override void OnInspectorGUI() FlipToggles(); - Rect r = GUILayoutUtility.GetRect( - EditorGUILayout.kLabelFloatMinW, EditorGUILayout.kLabelFloatMaxW, - EditorGUI.kSingleLineHeight, EditorGUI.kSingleLineHeight); - - EditorGUI.showMixedValue = m_Material.hasMultipleDifferentValues; - Object currentMaterialRef = m_Material.GetArrayElementAtIndex(0).objectReferenceValue; - Object returnedMaterialRef = EditorGUI.ObjectField(r, Contents.materialLabel, currentMaterialRef, typeof(Material), false); - if (returnedMaterialRef != currentMaterialRef) - { - m_Material.GetArrayElementAtIndex(0).objectReferenceValue = returnedMaterialRef; - } - EditorGUI.showMixedValue = false; - EditorGUILayout.PropertyField(m_DrawMode, Contents.drawModeLabel); m_ShowDrawMode.target = ShouldShowDrawMode(); @@ -141,8 +128,8 @@ public override void OnInspectorGUI() RenderSortingLayerFields(); EditorGUILayout.PropertyField(m_MaskInteraction, Contents.maskInteractionLabel); - EditorGUILayout.PropertyField(m_SpriteSortPoint, Contents.spriteSortPointLabel); + EditorGUILayout.PropertyField(m_Material.GetArrayElementAtIndex(0), Contents.materialLabel, true); RenderRenderingLayer(); diff --git a/Editor/Mono/Inspector/StandardParticlesShaderGUI.cs b/Editor/Mono/Inspector/StandardParticlesShaderGUI.cs index fda108a9ea..6b9f103e66 100644 --- a/Editor/Mono/Inspector/StandardParticlesShaderGUI.cs +++ b/Editor/Mono/Inspector/StandardParticlesShaderGUI.cs @@ -87,6 +87,8 @@ private static class Styles public static GUIContent streamTangentText = EditorGUIUtility.TrTextContent("Tangent (TANGENT.xyzw)"); public static GUIContent streamApplyToAllSystemsText = EditorGUIUtility.TrTextContent("Apply to Systems", "Apply the vertex stream layout to all Particle Systems using this material"); + + public static string undoApplyCustomVertexStreams = L10n.Tr("Apply custom vertex streams from material"); } MaterialProperty blendMode = null; @@ -477,7 +479,7 @@ void DoVertexStreamsArea(Material material) // Display list of streams required to make this shader work bool useLighting = (material.GetFloat("_LightingEnabled") > 0.0f); bool useFlipbookBlending = (material.GetFloat("_FlipbookMode") > 0.0f); - bool useTangents = material.GetTexture("_BumpMap") && useLighting; + bool useTangents = useLighting && material.GetTexture("_BumpMap"); bool useGPUInstancing = ShaderUtil.HasProceduralInstancing(material.shader); if (useGPUInstancing && m_RenderersUsingThisMaterial.Count > 0) @@ -535,6 +537,8 @@ void DoVertexStreamsArea(Material material) // Set the streams on all systems using this material if (GUILayout.Button(Styles.streamApplyToAllSystemsText, EditorStyles.miniButton, GUILayout.ExpandWidth(false))) { + Undo.RecordObjects(m_RenderersUsingThisMaterial.Where(r => r != null).ToArray(), Styles.undoApplyCustomVertexStreams); + foreach (ParticleSystemRenderer renderer in m_RenderersUsingThisMaterial) { if (renderer != null) @@ -717,7 +721,7 @@ void SetMaterialKeywords(Material material) // (MaterialProperty value might come from renderer material property block) bool useDistortion = !hasZWrite && (material.GetFloat("_DistortionEnabled") > 0.0f); SetKeyword(material, "_NORMALMAP", (useLighting || useDistortion) && material.GetTexture("_BumpMap")); - SetKeyword(material, "_METALLICGLOSSMAP", useLighting && (material.GetTexture("_MetallicGlossMap") != null)); + SetKeyword(material, "_METALLICGLOSSMAP", useLighting && material.GetTexture("_MetallicGlossMap")); material.globalIlluminationFlags = MaterialGlobalIlluminationFlags.None; SetKeyword(material, "_EMISSION", material.GetFloat("_EmissionEnabled") > 0.0f); diff --git a/Editor/Mono/Inspector/TextureInspector.cs b/Editor/Mono/Inspector/TextureInspector.cs index 228f419ef2..832775e481 100644 --- a/Editor/Mono/Inspector/TextureInspector.cs +++ b/Editor/Mono/Inspector/TextureInspector.cs @@ -606,7 +606,7 @@ public override void OnPreviewGUI(Rect r, GUIStyle background) RenderTexture rt = t as RenderTexture; if (rt != null) { - if (!SystemInfo.SupportsRenderTextureFormat(rt.format)) + if (!SystemInfo.IsFormatSupported(rt.graphicsFormat, FormatUsage.Render)) return; // can't do this RT format rt.Create(); } @@ -791,15 +791,12 @@ public override string GetInfoString() TextureImporter textureImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(t)) as TextureImporter; string info = t.width.ToString() + "x" + t.height.ToString(); - if (QualitySettings.desiredColorSpace == ColorSpace.Linear) - info += " " + TextureUtil.GetTextureColorSpaceString(t); - bool showSize = true; bool isPackedSprite = textureImporter && textureImporter.qualifiesForSpritePacking; bool isNormalmap = IsNormalMap(t); bool stillNeedsCompression = TextureUtil.DoesTextureStillNeedToBeCompressed(AssetDatabase.GetAssetPath(t)); bool isNPOT = t2 != null && TextureUtil.IsNonPowerOfTwo(t2); - TextureFormat format = TextureUtil.GetTextureFormat(t); + GraphicsFormat format = t.graphicsFormat; showSize = !stillNeedsCompression; if (isNPOT) @@ -812,18 +809,22 @@ public override string GetInfoString() { switch (format) { - case TextureFormat.DXT5: + case GraphicsFormat.RGBA_DXT5_SRGB: + case GraphicsFormat.RGBA_DXT5_UNorm: info += " DXTnm"; break; - case TextureFormat.RGBA32: - case TextureFormat.ARGB32: + case GraphicsFormat.R8G8B8A8_SRGB: + case GraphicsFormat.R8G8B8A8_UNorm: + case GraphicsFormat.B8G8R8A8_SRGB: + case GraphicsFormat.B8G8R8A8_UNorm: info += " Nm 32 bit"; break; - case TextureFormat.ARGB4444: + case GraphicsFormat.R4G4B4A4_UNormPack16: + case GraphicsFormat.B4G4R4A4_UNormPack16: info += " Nm 16 bit"; break; default: - info += " " + TextureUtil.GetTextureFormatString(format); + info += " " + GraphicsFormatUtility.GetFormatString(format); break; } } @@ -834,10 +835,10 @@ public override string GetInfoString() int dummyComressionQuality; textureImporter.ReadTextureImportInstructions(EditorUserBuildSettings.activeBuildTarget, out desiredFormat, out dummyColorSpace, out dummyComressionQuality); - info += "\n " + TextureUtil.GetTextureFormatString(format) + "(Original) " + TextureUtil.GetTextureFormatString(desiredFormat) + "(Atlas)"; + info += "\n " + GraphicsFormatUtility.GetFormatString(format) + "(Original) " + TextureUtil.GetTextureFormatString(desiredFormat) + "(Atlas)"; } else - info += " " + TextureUtil.GetTextureFormatString(format); + info += " " + GraphicsFormatUtility.GetFormatString(format); } if (showSize) diff --git a/Editor/Mono/Inspector/TimeManagerInspector.cs b/Editor/Mono/Inspector/TimeManagerInspector.cs index 4d7aa39df1..a125354939 100644 --- a/Editor/Mono/Inspector/TimeManagerInspector.cs +++ b/Editor/Mono/Inspector/TimeManagerInspector.cs @@ -12,7 +12,7 @@ internal class TimeManagerEditor : Editor class Content { public static readonly GUIContent fixedTimestepLabel = EditorGUIUtility.TrTextContent("Fixed Timestep", "A framerate-independent interval that dictates when physics calculations and FixedUpdate() events are performed."); - public static readonly GUIContent maxAllowedTimestepLabel = EditorGUIUtility.TrTextContent("Maximum Allowed Timestep", "A framerate-independent interval that caps the worst case scenario when framerate is low. Physics calculations and FixedUpdate() events will not be performed for longer time than specified."); + public static readonly GUIContent maxAllowedTimestepLabel = EditorGUIUtility.TrTextContent("Maximum Allowed Timestep", "A framerate-independent interval that caps the worst-case scenario when framerate is low. Physics calculations and FixedUpdate() events will not be performed for longer time than specified."); public static readonly GUIContent timeScaleLabel = EditorGUIUtility.TrTextContent("Time Scale", "The speed at which time progresses. Change this value to simulate bullet-time effects. A value of 1 means real-time. A value of .5 means half speed; a value of 2 is double speed."); public static readonly GUIContent maxParticleTimestepLabel = EditorGUIUtility.TrTextContent("Maximum Particle Timestep", "The maximum time that should be allowed to process particles for a frame."); } diff --git a/Editor/Mono/InternalEditorUtility.bindings.cs b/Editor/Mono/InternalEditorUtility.bindings.cs index b1b1b71cc2..251bfffe5c 100644 --- a/Editor/Mono/InternalEditorUtility.bindings.cs +++ b/Editor/Mono/InternalEditorUtility.bindings.cs @@ -246,6 +246,9 @@ public static void SaveToSerializedFileAndForget(Object[] obj, string path, bool [FreeFunction("InternalEditorUtilityBindings::HierarchyWindowDrag")] extern public static DragAndDropVisualMode HierarchyWindowDrag(HierarchyProperty property, HierarchyDropMode dropMode, Transform parentForDraggedObjects, bool perform); + [FreeFunction("InternalEditorUtilityBindings::HierarchyWindowDragByID")] + extern public static DragAndDropVisualMode HierarchyWindowDragByID(int hierarchyItemInstanceID, HierarchyDropMode dropMode, Transform parentForDraggedObjects, bool perform); + [FreeFunction("InternalEditorUtilityBindings::InspectorWindowDrag")] extern internal static DragAndDropVisualMode InspectorWindowDrag(Object[] targets, bool perform); @@ -615,8 +618,13 @@ public static void SetCustomLighting(Light[] lights, Color ambient) [StaticAccessor("GetRenderManager()", StaticAccessorType.Dot)] extern public static bool HasFullscreenCamera(); + public static Bounds CalculateSelectionBounds(bool usePivotOnlyForParticles, bool onlyUseActiveSelection) + { + return CalculateSelectionBounds(usePivotOnlyForParticles, onlyUseActiveSelection, false); + } + [FreeFunction] - extern public static Bounds CalculateSelectionBounds(bool usePivotOnlyForParticles, bool onlyUseActiveSelection); + extern public static Bounds CalculateSelectionBounds(bool usePivotOnlyForParticles, bool onlyUseActiveSelection, bool ignoreEditableField); internal static Bounds CalculateSelectionBoundsInSpace(Vector3 position, Quaternion rotation, bool rectBlueprintMode) { @@ -720,6 +728,9 @@ private static Bounds GetLocalBounds(GameObject gameObject) [FreeFunction] extern public static DllType DetectDotNetDll(string path); + [FreeFunction] + internal static extern bool IsDotNetDll(string path); + public static bool IsDotNet4Dll(string path) { var dllType = DetectDotNetDll(path); diff --git a/Editor/Mono/InternalEditorUtility.cs b/Editor/Mono/InternalEditorUtility.cs index 0e651502de..7c92ae9991 100644 --- a/Editor/Mono/InternalEditorUtility.cs +++ b/Editor/Mono/InternalEditorUtility.cs @@ -42,7 +42,7 @@ public static Texture2D FindIconForFile(string fileName) case "anim": return EditorGUIUtility.FindTexture(typeof(Animation)); case "meta": return EditorGUIUtility.FindTexture("MetaFile Icon"); case "mixer": return EditorGUIUtility.FindTexture(typeof(UnityEditor.Audio.AudioMixerController)); - case "uxml": return EditorGUIUtility.FindTexture(typeof(UnityEngine.Experimental.UIElements.VisualTreeAsset)); + case "uxml": return EditorGUIUtility.FindTexture(typeof(UnityEngine.UIElements.VisualTreeAsset)); case "uss": return EditorGUIUtility.FindTexture(typeof(StyleSheet)); case "ttf": case "otf": case "fon": case "fnt": diff --git a/Editor/Mono/Networking/PlayerConnection/AttachToPlayerGUI.cs b/Editor/Mono/Networking/PlayerConnection/AttachToPlayerGUI.cs index fddc7584ed..6e9ba45ecf 100644 --- a/Editor/Mono/Networking/PlayerConnection/AttachToPlayerGUI.cs +++ b/Editor/Mono/Networking/PlayerConnection/AttachToPlayerGUI.cs @@ -80,7 +80,7 @@ static class Content { public static readonly GUIContent EnterIPText = UnityEditor.EditorGUIUtility.TrTextContent(""); public static readonly GUIContent AutoconnectedPlayer = UnityEditor.EditorGUIUtility.TrTextContent("(Autoconnected Player)"); - public static readonly GUIContent ConnectingToPlayerMessage = UnityEditor.EditorGUIUtility.TrTextContent("Connecting to player...(this can take a while)"); + public static readonly GUIContent ConnectingToPlayerMessage = UnityEditor.EditorGUIUtility.TrTextContent("Connecting to player... (this can take a while)"); public static readonly string LocalHostProhibited = L10n.Tr(" (Localhost prohibited)"); public static readonly string VersionMismatch = L10n.Tr(" (Version mismatch)"); diff --git a/Editor/Mono/ObjectListArea.cs b/Editor/Mono/ObjectListArea.cs index e44211dfb3..822ce2c916 100644 --- a/Editor/Mono/ObjectListArea.cs +++ b/Editor/Mono/ObjectListArea.cs @@ -659,7 +659,7 @@ CreateAssetUtility GetCreateAssetUtility() return m_State.m_CreateAssetUtility; } - RenameOverlay GetRenameOverlay() + internal RenameOverlay GetRenameOverlay() { return m_State.m_RenameOverlay; } @@ -1490,7 +1490,6 @@ int GetMaxNumVisibleItems() return g.m_Grid.GetMaxVisibleItems(m_TotalRect.height); } - Assert.IsTrue(false, "Unhandled group"); return 0; } diff --git a/Editor/Mono/ObjectNames.cs b/Editor/Mono/ObjectNames.cs index e2cef12ff9..295717d30a 100644 --- a/Editor/Mono/ObjectNames.cs +++ b/Editor/Mono/ObjectNames.cs @@ -28,12 +28,10 @@ private static string GetObjectTypeName(Object o) var behaviour = o as MonoBehaviour; if (behaviour) { - var generatorAsset = ScriptGeneratorAsset.FromMonoBehaviour(behaviour); - var sourceType = (generatorAsset == null) ? " (Script)" : " (" + generatorAsset.label + ")"; var scriptClassName = behaviour.GetScriptClassName(); if (scriptClassName == "InvalidStateMachineBehaviour") - return behaviour.name + sourceType; - return scriptClassName + sourceType; + return behaviour.name + " (Script)"; + return scriptClassName + " (Script)"; } var meshfilter = o as MeshFilter; diff --git a/Editor/Mono/ObjectSelector.cs b/Editor/Mono/ObjectSelector.cs index 762585c043..ee1ae08014 100644 --- a/Editor/Mono/ObjectSelector.cs +++ b/Editor/Mono/ObjectSelector.cs @@ -286,9 +286,9 @@ void FilterSettingsChanged() m_ListArea.Init(listPosition, hierarchyType, filter, true); } - static bool ShouldTreeViewBeUsed(Type type) + static bool ShouldTreeViewBeUsed(String typeStr) { - return type == typeof(AudioMixerGroup); + return (String.Equals(typeof(AudioMixerGroup).Name, typeStr)); } public void Show(UnityObject obj, Type requiredType, SerializedProperty property, bool allowSceneObjects) @@ -395,7 +395,7 @@ internal void Show(UnityObject obj, Type requiredType, SerializedProperty proper if (property != null && property.hasMultipleDifferentValues) initialSelection = 0; // don't select anything on multi selection - if (ShouldTreeViewBeUsed(requiredType)) + if (ShouldTreeViewBeUsed(m_RequiredType)) { m_ObjectTreeWithSearch.Init(position, this, CreateAndSetTreeView, TreeViewSelection, ItemWasDoubleClicked, initialSelection, 0); } @@ -702,7 +702,7 @@ void ResizeBottomPartOfWindow() GUI.changed = false; // Handle preview size - m_PreviewSize = m_PreviewResizer.ResizeHandle(position, kPreviewExpandedAreaHeight + kPreviewMargin * 2 - 20, kMinTopSize + 20, 20) + 20; + m_PreviewSize = m_PreviewResizer.ResizeHandle(position, kPreviewExpandedAreaHeight + kPreviewMargin * 2 - 20, kMinTopSize + 20, m_PreviewSize + 20) + 20; m_TopSize = position.height - m_PreviewSize; bool open = PreviewIsOpen(); diff --git a/Editor/Mono/PackageUtility.bindings.cs b/Editor/Mono/PackageUtility.bindings.cs index c548a47068..54ec0e8129 100644 --- a/Editor/Mono/PackageUtility.bindings.cs +++ b/Editor/Mono/PackageUtility.bindings.cs @@ -62,7 +62,7 @@ internal class PackageUtility public static extern void ExportPackage(string[] guids, string fileName); [NativeThrows] public static extern void ExportPackageAndPackageManagerManifest(string[] guids, string fileName); - public static extern ImportPackageItem[] ExtractAndPrepareAssetList(string packagePath, out string packageIconPath, out bool canPerformReInstall); + public static extern ImportPackageItem[] ExtractAndPrepareAssetList(string packagePath, out string packageIconPath, out bool canPerformReInstall, out string packageManagerDependenciesPath); [FreeFunction("DelayedImportPackageAssets")] public static extern void ImportPackageAssets(string packageName, ImportPackageItem[] items, bool performReInstall); diff --git a/Editor/Mono/PerceptionRemoting/HolographicEmulation/HolographicEmulationWindow.cs b/Editor/Mono/PerceptionRemoting/HolographicEmulation/HolographicEmulationWindow.cs index cfa4ada8b5..98b52506b1 100644 --- a/Editor/Mono/PerceptionRemoting/HolographicEmulation/HolographicEmulationWindow.cs +++ b/Editor/Mono/PerceptionRemoting/HolographicEmulation/HolographicEmulationWindow.cs @@ -27,6 +27,8 @@ internal class HolographicEmulationWindow : EditorWindow [SerializeField] private EmulationMode m_Mode = EmulationMode.None; [SerializeField] + private RemoteDeviceVersion m_DeviceVersion = RemoteDeviceVersion.V1; + [SerializeField] private int m_RoomIndex = 0; [SerializeField] private PlaymodeInputType m_InputType = PlaymodeInputType.LeftController; @@ -46,6 +48,7 @@ internal class HolographicEmulationWindow : EditorWindow private static GUIContent s_ConnectionStatusText = EditorGUIUtility.TrTextContent("Connection Status"); private static GUIContent s_EmulationModeText = EditorGUIUtility.TrTextContent("Emulation Mode"); + private static GUIContent s_DeviceVersionText = EditorGUIUtility.TrTextContent("Device Version"); private static GUIContent s_RoomText = EditorGUIUtility.TrTextContent("Room"); private static GUIContent s_InputText = EditorGUIUtility.TrTextContent("Simulated Input"); private static GUIContent s_RemoteMachineText = EditorGUIUtility.TrTextContent("Remote Machine"); @@ -67,6 +70,12 @@ internal class HolographicEmulationWindow : EditorWindow EditorGUIUtility.TrTextContent("Simulate in Editor") }; + private static GUIContent[] s_DeviceVersionStrings = new GUIContent[] + { + EditorGUIUtility.TrTextContent("HoloLens (1st Gen)"), + EditorGUIUtility.TrTextContent("HoloLens 2") + }; + private static GUIContent[] s_RoomStrings = new GUIContent[] { EditorGUIUtility.TrTextContent("None"), @@ -240,6 +249,9 @@ private void UpdateRemoteMachineHistory() private void RemotingPreferencesOnGUI() { + m_DeviceVersion = (RemoteDeviceVersion)EditorGUILayout.Popup(s_DeviceVersionText, (int)m_DeviceVersion, s_DeviceVersionStrings); + PerceptionRemoting.SetRemoteDeviceVersion(m_DeviceVersion); + EditorGUI.BeginChangeCheck(); m_RemoteMachineAddress = EditorGUILayout.DelayedTextFieldDropDown(s_RemoteMachineText, m_RemoteMachineAddress, m_RemoteMachineHistory); if (EditorGUI.EndChangeCheck()) diff --git a/Editor/Mono/PerformanceTools/FrameDebugger.cs b/Editor/Mono/PerformanceTools/FrameDebugger.cs index 065b0483f2..058033396f 100644 --- a/Editor/Mono/PerformanceTools/FrameDebugger.cs +++ b/Editor/Mono/PerformanceTools/FrameDebugger.cs @@ -16,6 +16,7 @@ using UnityEngine.Experimental.Networking.PlayerConnection; using ConnectionUtility = UnityEditor.Experimental.Networking.PlayerConnection.EditorGUIUtility; using ConnectionGUILayout = UnityEditor.Experimental.Networking.PlayerConnection.EditorGUILayout; +using UnityEngine.Experimental.Rendering; namespace UnityEditorInternal { @@ -785,7 +786,7 @@ private void DrawRenderTargetControls() if (cur.rtWidth <= 0 || cur.rtHeight <= 0) return; - var isDepthOnlyRT = (cur.rtFormat == (int)RenderTextureFormat.Depth || cur.rtFormat == (int)RenderTextureFormat.Shadowmap); + var isDepthOnlyRT = GraphicsFormatUtility.IsDepthFormat((GraphicsFormat)cur.rtFormat); var hasShowableDepth = (cur.rtHasDepthTexture != 0); var showableRTCount = cur.rtCount; if (hasShowableDepth) @@ -853,7 +854,7 @@ private void DrawRenderTargetControls() GUILayout.Label(string.Format("{0}x{1} {2}", cur.rtWidth, cur.rtHeight, - (RenderTextureFormat)cur.rtFormat)); + (GraphicsFormat)cur.rtFormat)); if (cur.rtDim == (int)UnityEngine.Rendering.TextureDimension.Cube) GUILayout.Label("Rendering into cubemap"); } diff --git a/Editor/Mono/PlayerSettings.bindings.cs b/Editor/Mono/PlayerSettings.bindings.cs index fa2993c864..21ab44d08e 100644 --- a/Editor/Mono/PlayerSettings.bindings.cs +++ b/Editor/Mono/PlayerSettings.bindings.cs @@ -11,6 +11,7 @@ namespace UnityEditor { // Resolution dialog setting + [Obsolete("ResolutionDialogSetting is deprecated and will be removed in future versions.", false)] public enum ResolutionDialogSetting { // Never show the resolutions dialog. @@ -435,6 +436,7 @@ public static Guid productGUID public static extern int defaultWebScreenHeight { get; set; } // Defines the behaviour of the Resolution Dialog on product launch. + [Obsolete("displayResolutionDialog is deprecated and will be removed in future versions.", false)] public static extern ResolutionDialogSetting displayResolutionDialog { get; set; } // Returns whether or not the specified aspect ratio is enabled. @@ -521,6 +523,8 @@ public static bool singlePassStereoRendering // Restrict standalone players to a single concurrent running instance. public static extern bool forceSingleInstance { get; set; } + public static extern bool useFlipModelSwapchain { get; set; } + [NativeProperty(TargetType = TargetType.Field)] public static extern bool openGLRequireES31 { @@ -552,6 +556,7 @@ public static extern bool openGLRequireES32 } // The image to display in the Resolution Dialog window. + [Obsolete("resolutionDialogBanner is deprecated and will be removed in future versions.", false)] public static extern Texture2D resolutionDialogBanner { get; set; } // The image to display on the Virtual Reality splash screen. diff --git a/Editor/Mono/PlayerSettingsLumin.bindings.cs b/Editor/Mono/PlayerSettingsLumin.bindings.cs new file mode 100644 index 0000000000..338dbd6e6a --- /dev/null +++ b/Editor/Mono/PlayerSettingsLumin.bindings.cs @@ -0,0 +1,79 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEngine.Bindings; +using UnityObject = UnityEngine.Object; + +namespace UnityEditor +{ + public partial class PlayerSettings : UnityObject + { + [NativeHeader("Runtime/Misc/PlayerSettings.h")] + public sealed partial class Lumin + { + [NativeProperty("LuminIconModelFolderPath")] + public extern static string iconModelFolderPath + { + [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] + get; + [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] + set; + } + + [NativeProperty("LuminIconPortalFolderPath")] + public extern static string iconPortalFolderPath + { + [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] + get; + [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] + set; + } + + [NativeProperty("LuminCertificatePath")] + public extern static string certificatePath + { + [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] + get; + [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] + set; + } + + [NativeProperty("LuminSignPackage")] + public extern static bool signPackage + { + [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] + get; + [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] + set; + } + + [NativeProperty("LuminIsChannelApp")] + public extern static bool isChannelApp + { + [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] + get; + [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] + set; + } + + [NativeProperty("LuminVersionCode")] + public extern static int versionCode + { + [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] + get; + [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] + set; + } + + [NativeProperty("LuminVersionName")] + public extern static string versionName + { + [StaticAccessor("GetPlayerSettings().GetEditorOnly()", StaticAccessorType.Dot)] + get; + [StaticAccessor("GetPlayerSettings().GetEditorOnlyForUpdate()", StaticAccessorType.Dot)] + set; + } + } + } +} diff --git a/Editor/Mono/PlayerSettingsSwitch.bindings.cs b/Editor/Mono/PlayerSettingsSwitch.bindings.cs index 5519a6553d..37613967b1 100644 --- a/Editor/Mono/PlayerSettingsSwitch.bindings.cs +++ b/Editor/Mono/PlayerSettingsSwitch.bindings.cs @@ -148,6 +148,12 @@ extern public static int queueCommandMemory set; } + [StaticAccessor("PlayerSettings", StaticAccessorType.DoubleColon)] + extern public static int defaultSwitchQueueCommandMemory { get; } + + [StaticAccessor("PlayerSettings", StaticAccessorType.DoubleColon)] + extern public static int minimumSwitchQueueCommandMemory { get; } + [StaticAccessor("GetPlayerSettings()", StaticAccessorType.Dot)] extern public static int queueControlMemory { @@ -157,6 +163,24 @@ extern public static int queueControlMemory set; } + [StaticAccessor("PlayerSettings", StaticAccessorType.DoubleColon)] + extern public static int defaultSwitchQueueControlMemory { get; } + + [StaticAccessor("PlayerSettings", StaticAccessorType.DoubleColon)] + extern public static int minimumSwitchQueueControlMemory { get; } + + [StaticAccessor("GetPlayerSettings()", StaticAccessorType.Dot)] + extern public static int queueComputeMemory + { + [NativeMethod("GetSwitchQueueComputeMemory")] + get; + [NativeMethod("SetSwitchQueueComputeMemory")] + set; + } + + [StaticAccessor("PlayerSettings", StaticAccessorType.DoubleColon)] + extern public static int defaultSwitchQueueComputeMemory { get; } + // GPU Pool information. [StaticAccessor("GetPlayerSettings()", StaticAccessorType.Dot)] extern public static int NVNShaderPoolsGranularity diff --git a/Editor/Mono/PointEditor.cs b/Editor/Mono/PointEditor.cs index 0f801c963f..d709d6a6cc 100644 --- a/Editor/Mono/PointEditor.cs +++ b/Editor/Mono/PointEditor.cs @@ -175,8 +175,10 @@ public static bool SelectPoints(IEditablePoint points, Transform cloudTransform, // Go over all the points and add them if they are inside the rect for (int i = 0; i < points.Count; i++) { - var point = HandleUtility.WorldToGUIPoint(points.GetPosition(i)); - if (r.Contains(point)) + var point = HandleUtility.WorldToGUIPointWithDepth(points.GetPosition(i)); + + // the point has to be within the selection and in front of the camera + if (r.Contains(point) && point.z > 0.0f) { if (EditorGUI.actionKey) { diff --git a/Editor/Mono/PostprocessScene.cs b/Editor/Mono/PostprocessScene.cs index 71891c4fc0..04ee821e7a 100644 --- a/Editor/Mono/PostprocessScene.cs +++ b/Editor/Mono/PostprocessScene.cs @@ -2,8 +2,11 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using System; using UnityEngine; using UnityEditor.Build; +using System.Text; +using UnityEngine.SceneManagement; namespace UnityEditor { @@ -16,7 +19,50 @@ public void OnProcessScene(UnityEngine.SceneManagement.Scene scene, Build.Report PlayerSettings.GetBatchingForPlatform(EditorUserBuildSettings.activeBuildTarget, out staticBatching, out dynamicBatching); if (staticBatching != 0) { - InternalStaticBatchingUtility.Combine(null, true, true); + InternalStaticBatchingUtility.Combine(null, true, true, new EditorStaticBatcherGOSorter(scene)); + } + } + + internal class EditorStaticBatcherGOSorter : InternalStaticBatchingUtility.StaticBatcherGOSorter + { + Scene scene; + + public EditorStaticBatcherGOSorter(Scene scene) + { + this.scene = scene; + } + + private static long GetStableHash(UnityEngine.Object instance, string guid) + { + var lfid = UnityEditor.Unsupported.GetFileIDHint(instance); + + using (var md5Hash = System.Security.Cryptography.MD5.Create()) + { + var bytes = Encoding.ASCII.GetBytes(guid); + md5Hash.TransformBlock(bytes, 0, bytes.Length, null, 0); + bytes = BitConverter.GetBytes(lfid); + md5Hash.TransformFinalBlock(bytes, 0, bytes.Length); + return BitConverter.ToInt64(md5Hash.Hash, 0); + } + } + + public override long GetMaterialId(Renderer renderer) + { + if (renderer == null || renderer.sharedMaterial == null) + return 0; + + string path = AssetDatabase.GetAssetPath(renderer.sharedMaterial); + string guid = AssetDatabase.AssetPathToGUID(path); + return GetStableHash(renderer.sharedMaterial, guid); + } + + public override long GetRendererId(Renderer renderer) + { + if (renderer == null) + return -1; + + string guid = AssetDatabase.AssetPathToGUID(scene.path); + return GetStableHash(renderer, guid); } } } diff --git a/Editor/Mono/Prefabs/PrefabImporterEditor.cs b/Editor/Mono/Prefabs/PrefabImporterEditor.cs index d95d7175aa..b293468ef4 100644 --- a/Editor/Mono/Prefabs/PrefabImporterEditor.cs +++ b/Editor/Mono/Prefabs/PrefabImporterEditor.cs @@ -6,6 +6,7 @@ using UnityEditor.Experimental.AssetImporters; using UnityEditor.Experimental.SceneManagement; using UnityEditor.SceneManagement; +using System.Collections.Generic; namespace UnityEditor { @@ -13,12 +14,164 @@ namespace UnityEditor [CanEditMultipleObjects] internal class PrefabImporterEditor : AssetImporterEditor { - static GUIContent s_OpenContent = EditorGUIUtility.TrTextContent("Open Prefab"); - static GUIContent s_BaseContent = EditorGUIUtility.TrTextContent("Base"); - static string s_LocalizedTitleMultiplePrefabs = L10n.Tr("Prefab Assets"); - static string s_LocalizedTitleSinglePrefab = L10n.Tr("Prefab Asset"); + static class Styles + { + public static GUIContent openContent = EditorGUIUtility.TrTextContent("Open Prefab"); + public static GUIContent openHelpText = EditorGUIUtility.TrTextContent("Open Prefab for full editing support."); + public static GUIContent missingScriptsHelpText = EditorGUIUtility.TrTextContent("Prefab has missing scripts. Open Prefab to fix the issue."); + public static GUIContent multiSelectionMissingScriptsHelpText = EditorGUIUtility.TrTextContent("Some of the selected Prefabs have missing scripts and needs to be fixed before editing them. Click to Open Prefab to fix the issue."); + public static GUIContent savingFailedHelpText = EditorGUIUtility.TrTextContent("Saving has failed. Check the Console window to get more insight into what needs to be fixed on the Prefab Asset.\n\nOpen Prefab to fix the issue."); + public static GUIContent baseContent = EditorGUIUtility.TrTextContent("Base"); + public static string localizedTitleMultiplePrefabs = L10n.Tr("Prefab Assets"); + public static string localizedTitleSinglePrefab = L10n.Tr("Prefab Asset"); + public static GUIStyle openButtonStyle = "AC Button"; + } int m_HasMixedBaseVariants = -1; + double m_NextUpdate; + List m_PrefabsWithMissingScript = new List(); + bool m_SavingHasFailed; + List m_TempComponentsResults = new List(); + + public override bool showImportedObject { get { return !hasMissingScripts; } } + + public override bool UseDefaultMargins() + { + return false; + } + + bool isTextFieldCaretShowing + { + get { return EditorGUI.IsEditingTextField() && !EditorGUIUtility.textFieldHasSelection; } + } + + bool readyToAutoSave + { + get { return !m_SavingHasFailed && !hasMissingScripts && GUIUtility.hotControl == 0 && !isTextFieldCaretShowing && !EditorApplication.isCompiling; } + } + + bool hasMissingScripts + { + get { return m_PrefabsWithMissingScript.Count > 0; } + } + + public override void OnEnable() + { + base.OnEnable(); + EditorApplication.update += Update; + } + + public override void OnDisable() + { + EditorApplication.update -= Update; + base.OnDisable(); + } + + protected override void Awake() + { + base.Awake(); + + foreach (var prefabAssetRoot in assetTargets) + { + if (PrefabUtility.HasInvalidComponent(prefabAssetRoot)) + { + m_PrefabsWithMissingScript.Add(AssetDatabase.GetAssetPath(prefabAssetRoot)); + } + } + m_PrefabsWithMissingScript.Sort(); + } + + void OnDestroy() + { + // Ensure to save unsaved changes (regardless of hotcontrol etc) + if (!m_SavingHasFailed && !hasMissingScripts) + SaveDirtyPrefabAssets(); + } + + void Update() + { + var time = EditorApplication.timeSinceStartup; + if (time > m_NextUpdate) + { + m_NextUpdate = time + 0.2; + + if (readyToAutoSave && HasDirtyPrefabAssets()) + SaveDirtyPrefabAssets(); + } + } + + // Internal for testing framework + internal void SaveDirtyPrefabAssets() + { + if (assetTargets == null) + return; + + if (assetTarget == null) + return; + + foreach (var asset in assetTargets) + { + // The asset could have been deleted when this method is called from OnDestroy(). + // E.g delete the selected prefab asset from the Project Browser. + if (asset == null) + continue; + + if (!EditorUtility.IsPersistent(asset)) + continue; + + var rootGameObject = (GameObject)asset; + if (IsDirty(rootGameObject)) + { + bool savedSuccesfully; + PrefabUtility.SavePrefabAsset(rootGameObject, out savedSuccesfully); + if (!savedSuccesfully) + { + string title = L10n.Tr("Saving Failed"); + string message = L10n.Tr("Check the Console window to get more insight into what needs to be fixed on the Prefab Asset.\n\nYou can open Prefab Mode to fix any issues on child GameObjects"); + EditorUtility.DisplayDialog(title, message, L10n.Tr("OK")); + + m_SavingHasFailed = true; + return; + } + } + } + } + + internal bool HasDirtyPrefabAssets() + { + if (assetTarget == null) + return false; + + // We just check one target since we assume that a multi-edit will + // always edit that target. So no need to spend resources on checking + // all targets in multiselection. + return IsDirty((GameObject)assetTarget); + } + + bool IsDirty(GameObject prefabAssetRoot) + { + if (prefabAssetRoot == null) + return false; + + if (EditorUtility.IsDirty(prefabAssetRoot)) + return true; + + // For Prefab Variant Asset we need to also check if the instance handle is dirty + // since this happens when the list of removed component changes + var instanceHandle = PrefabUtility.GetPrefabInstanceHandle(prefabAssetRoot); + if (instanceHandle != null) + if (EditorUtility.IsDirty(instanceHandle)) + return true; + + prefabAssetRoot.GetComponents(m_TempComponentsResults); + foreach (var component in m_TempComponentsResults) + { + if (EditorUtility.IsDirty(component)) + return true; + } + + return false; + } void CacheHasMixedBaseVariants() { @@ -41,16 +194,14 @@ void CacheHasMixedBaseVariants() } } - public override bool showImportedObject { get { return false; } } - internal override string targetTitle { get { if (assetTargets == null || assetTargets.Length == 1 || !m_AllowMultiObjectAccess) - return assetTarget != null ? assetTarget.name : s_LocalizedTitleSinglePrefab; + return assetTarget != null ? assetTarget.name + " (" + Styles.localizedTitleSinglePrefab + ")" : Styles.localizedTitleSinglePrefab; else - return assetTargets.Length + " " + s_LocalizedTitleMultiplePrefabs; + return assetTargets.Length + " " + Styles.localizedTitleMultiplePrefabs; } } @@ -62,7 +213,7 @@ internal override void OnHeaderControlsGUI() using (new EditorGUI.DisabledScope(true)) { CacheHasMixedBaseVariants(); - GUILayout.Label(s_BaseContent); + GUILayout.Label(Styles.baseContent); EditorGUI.showMixedValue = m_HasMixedBaseVariants == 1; EditorGUILayout.ObjectField(variantBase, typeof(GameObject), false); EditorGUI.showMixedValue = false; @@ -77,6 +228,8 @@ internal override void OnHeaderControlsGUI() public override void OnInspectorGUI() { + EditorGUILayout.BeginVertical(EditorStyles.inspectorFullWidthMargins); + // Allow opening prefab even if file is not open for edit. // For things with explicit save operations (scenes, prefabs) we allow editing // and handle the potential version control conflict at the time when the user saves. @@ -84,15 +237,63 @@ public override void OnInspectorGUI() GUI.enabled = true; using (new EditorGUI.DisabledScope(assetTargets.Length > 1)) { - if (GUILayout.Button(s_OpenContent)) + GUILayout.Space(10); + + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button(Styles.openContent, Styles.openButtonStyle)) { // We only support opening one prefab at a time (so do not use 'targets') PrefabStageUtility.OpenPrefab(AssetDatabase.GetAssetPath(assetTarget), null, StageNavigationManager.Analytics.ChangeType.EnterViaAssetInspectorOpenButton); GUIUtility.ExitGUI(); } + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + GUILayout.Space(5); + + if (!hasMissingScripts && !m_SavingHasFailed) + { + EditorGUILayout.HelpBox(Styles.openHelpText.text, MessageType.Info, true); + } } GUI.enabled = wasEnabled; + + if (hasMissingScripts) + { + if (assetTargets.Length > 1) + { + // List all assets that have missing scripts (but only if we have a multi-selection) + GUILayout.Space(5); + EditorGUILayout.HelpBox(Styles.multiSelectionMissingScriptsHelpText.text, MessageType.Warning, true); + using (new EditorGUILayout.HorizontalScope()) + { + GUILayout.Space(10); + + using (new EditorGUILayout.VerticalScope()) + { + foreach (var prefabAssetPath in m_PrefabsWithMissingScript) + { + if (GUILayout.Button(prefabAssetPath, EditorStyles.label)) + { + PrefabStageUtility.OpenPrefab(prefabAssetPath); + } + } + } + } + } + else + { + EditorGUILayout.HelpBox(Styles.missingScriptsHelpText.text, MessageType.Warning, true); + } + } + else if (m_SavingHasFailed) + { + EditorGUILayout.HelpBox(Styles.savingFailedHelpText.text, MessageType.Warning, true); + } + + EditorGUILayout.EndVertical(); } } } diff --git a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverride.cs b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverride.cs index 75941ca0a5..9f8e8a0e3e 100644 --- a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverride.cs +++ b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverride.cs @@ -49,7 +49,9 @@ internal void HandleApplyMenuItems(GenericMenu menu, GenericMenu.MenuFunction2 a menu.AddDisabledItem(menuItemContent); else menu.AddItem(menuItemContent, false, applyAction, prefabAssetPath); - }); + }, + false, + true); } } diff --git a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs index eadb533e3f..c04b58d5b1 100644 --- a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs +++ b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesTreeView.cs @@ -414,6 +414,13 @@ protected override void RowGUI(RowGUIArgs args) internal void ReloadOverridesDisplay() { + // Driven properties are ignored when collecting overrides. + // Properties that affect which properties are driven may have changed + // due to an apply or revert since we last reloaded the overrides display. + // Execute a layout call to get driven properties into a stable state + // before collecting overrides. + Canvas.ForceUpdateCanvases(); + base.Reload(); if (m_Window != null) m_Window.RefreshStatus(); diff --git a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesUtility.cs b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesUtility.cs index 8c054b4bce..f6ccf7c5cb 100644 --- a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesUtility.cs +++ b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesUtility.cs @@ -32,6 +32,9 @@ public static List GetObjectOverrides(GameObject prefabInstance, // that are not part of that source prefab objects component list (these must be added) TransformVisitor transformVisitor = new TransformVisitor(); var modifiedObjects = new List(); + if (PrefabUtility.IsDisconnectedFromPrefabAsset(prefabInstance)) + return modifiedObjects; + System.Action checkMethod; if (includeDefaultOverrides) checkMethod = CheckForModifiedObjectsIncludingDefaultOverrides; @@ -81,6 +84,9 @@ public static List GetAddedComponents(GameObject prefabInstance) // From root of instance traverse all child go and detect any components that are not part of that source prefab objects component list (these must be added) TransformVisitor transformVisitor = new TransformVisitor(); var addedComponents = new List(); + if (PrefabUtility.IsDisconnectedFromPrefabAsset(prefabInstance)) + return addedComponents; + transformVisitor.VisitAll(prefabInstanceRoot.transform, CheckForAddedComponents, addedComponents); return addedComponents; } @@ -115,12 +121,25 @@ public static List GetRemovedComponents(GameObject prefabInsta var prefabInstanceRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(prefabInstance); // From root of asset traverse all children and detect any Components that are not present on the instance object (these must be deleted) - TransformVisitor transformVisitor = new TransformVisitor(); var removedComponents = new List(); + if (PrefabUtility.IsDisconnectedFromPrefabAsset(prefabInstance)) + return removedComponents; + TransformVisitor transformVisitor = new TransformVisitor(); transformVisitor.VisitAll(prefabInstanceRoot.transform, CheckForRemovedComponents, removedComponents); return removedComponents; } + public static List GetRemovedComponentsForSingleGameObject(GameObject prefabInstance) + { + ThrowExceptionIfNullOrNotPartOfPrefabInstance(prefabInstance); + + var removedComponents = new List(); + if (PrefabUtility.IsDisconnectedFromPrefabAsset(prefabInstance)) + return removedComponents; + CheckForRemovedComponents(prefabInstance.transform, removedComponents); + return removedComponents; + } + static void CheckForRemovedComponents(Transform transform, object userData) { GameObject instanceGameObject = transform.gameObject; @@ -175,6 +194,9 @@ public static List GetAddedGameObjects(GameObject prefabInstanc // From root instance traverse all children and detect any GameObjects that are not a prefab gameobject (these must be added) TransformVisitor transformVisitor = new TransformVisitor(); var addedGameObjects = new List(); + if (PrefabUtility.IsDisconnectedFromPrefabAsset(prefabInstance)) + return addedGameObjects; + transformVisitor.VisitAndConditionallyEnterChildren( prefabInstanceRoot.transform, CheckForAddedGameObjectAndIfSoAddItAndReturnFalse, diff --git a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesWindow.cs b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesWindow.cs index ac3788fc54..6231cb1044 100644 --- a/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesWindow.cs +++ b/Editor/Mono/Prefabs/PrefabOverrides/PrefabOverridesWindow.cs @@ -287,6 +287,12 @@ public override void OnGUI(Rect rect) GUILayout.EndHorizontal(); } + struct ApplyAllUndo + { + public GameObject correspondingSourceObject; + public HashSet prefabHierarchy; + }; + bool ApplyAll() { // Collect Prefab Asset paths and also check if there's more than one of the same. @@ -313,9 +319,37 @@ bool ApplyAll() if (!PrefabUtility.PromptAndCheckoutPrefabIfNeeded(prefabAssetPaths.ToArray(), PrefabUtility.SaveVerb.Apply)) return false; + var undoStructs = new List(); + var actionName = "ApplyAll"; + for (var i = 0; i < m_SelectedGameObjects.Length; i++) + { + var us = new ApplyAllUndo(); + us.correspondingSourceObject = (GameObject)PrefabUtility.GetCorrespondingObjectFromSource(m_SelectedGameObjects[i]); + Undo.RegisterFullObjectHierarchyUndo(us.correspondingSourceObject, actionName); // handles changes to existing objects and object what will be deleted but not objects that are created + GameObject prefabInstanceRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(m_SelectedGameObjects[i]); + Undo.RegisterFullObjectHierarchyUndo(prefabInstanceRoot, actionName); + + us.prefabHierarchy = new HashSet(); + PrefabUtility.GetObjectListFromHierarchy(us.prefabHierarchy, us.correspondingSourceObject); + undoStructs.Add(us); + } + // Apply sequentially. - for (int i = 0; i < m_SelectedGameObjects.Length; i++) - PrefabUtility.ApplyPrefabInstance(m_SelectedGameObjects[i], InteractionMode.UserAction); + AssetDatabase.StartAssetEditing(); + try + { + foreach (var t in m_SelectedGameObjects) + PrefabUtility.ApplyPrefabInstance(t, InteractionMode.UserAction); + } + finally + { + AssetDatabase.StopAssetEditing(); + } + + foreach (var t in undoStructs) + { + PrefabUtility.RegisterNewObjects(t.correspondingSourceObject, t.prefabHierarchy, actionName); + } EditorUtility.ForceRebuildInspectors(); return true; @@ -326,7 +360,6 @@ bool RevertAll() for (int i = 0; i < m_SelectedGameObjects.Length; i++) PrefabUtility.RevertPrefabInstance(m_SelectedGameObjects[i], InteractionMode.UserAction); - EditorUtility.ForceRebuildInspectors(); return true; } diff --git a/Editor/Mono/Prefabs/PrefabUtility.bindings.cs b/Editor/Mono/Prefabs/PrefabUtility.bindings.cs index 08a6acc617..dadd85a9b6 100644 --- a/Editor/Mono/Prefabs/PrefabUtility.bindings.cs +++ b/Editor/Mono/Prefabs/PrefabUtility.bindings.cs @@ -86,7 +86,7 @@ public sealed partial class PrefabUtility [StaticAccessor("PrefabUtilityBindings", StaticAccessorType.DoubleColon)] [NativeThrows] - extern static private Object InstantiatePrefab_internal(Object target, Scene destinationScene); + extern static private Object InstantiatePrefab_internal(Object target, Scene destinationScene, Transform parent); [StaticAccessor("PrefabUtilityBindings", StaticAccessorType.DoubleColon)] [NativeThrows] @@ -167,56 +167,20 @@ internal static GameObject CreateVariant(GameObject assetRoot, string path) [NativeMethod("CreateVariant", IsFreeFunction = true)] extern private static GameObject CreateVariant_Internal([NotNull] GameObject original, string path); - private enum PrefabCreationFlags - { - None = 0, - CreateVariant = 1, - } - - // TODO: Having an non-obsolete method that takes an obsolete enum types as parameter is no good. -#pragma warning disable 0618 // Type or member is obsolete - private static GameObject SavePrefab(GameObject inputObject, string path, ReplacePrefabOptions replaceOptions, PrefabCreationFlags creationFlags, out bool success) - { - if (inputObject == null) - throw new ArgumentNullException("inputObject is null"); - - if (String.IsNullOrEmpty(path)) - throw new ArgumentNullException("path is null or empty"); - - if (!Paths.IsValidAssetPath(path, ".prefab")) - throw new ArgumentException("Given path is not valid: '" + path + "'"); - - string directory = Path.GetDirectoryName(path); - - bool isRootFolder = false; - bool isImmutableFolder = false; - bool isValidAssetFolder = AssetDatabase.GetAssetFolderInfo(directory, out isRootFolder, out isImmutableFolder); - if (isValidAssetFolder && isImmutableFolder) - throw new ArgumentException("Saving Prefab to immutable folder is not allowed: '" + path + "'"); - - if (directory.Length > 0 && !Directory.Exists(directory)) - throw new ArgumentException("Given path does not exist: '" + path + "'"); - - string prefabGUID = AssetDatabase.AssetPathToGUID(path); - if (!VerifyNestingFromScript(new GameObject[] {inputObject}, prefabGUID, PrefabUtility.GetPrefabInstanceHandle(inputObject))) - throw new ArgumentException("Cyclic nesting detected"); + [StaticAccessor("PrefabUtilityBindings", StaticAccessorType.DoubleColon)] + extern private static GameObject SavePrefab_Internal([NotNull] GameObject root, string path, bool connectToInstance, out bool success); - return SavePrefab_Internal(inputObject, path, replaceOptions, creationFlags, out success); - } + [StaticAccessor("PrefabUtilityBindings", StaticAccessorType.DoubleColon)] + extern private static GameObject ApplyPrefabInstance_Internal([NotNull] GameObject root); - private static GameObject SavePrefab(GameObject inputObject, string path, ReplacePrefabOptions replaceOptions, PrefabCreationFlags creationFlags) - { - bool success; - return SavePrefab(inputObject, path, replaceOptions, creationFlags, out success); - } + [StaticAccessor("PrefabUtilityBindings", StaticAccessorType.DoubleColon)] + extern private static GameObject SaveAsPrefabAsset_Internal([NotNull] GameObject root, string path, out bool success); -#pragma warning restore 0618 // Type or member is obsolete + [StaticAccessor("PrefabUtilityBindings", StaticAccessorType.DoubleColon)] + extern private static GameObject SaveAsPrefabAssetAndConnect_Internal([NotNull] GameObject root, string path, out bool success); - // TODO: Having an non-obsolete method that takes an obsolete enum types as parameter is no good. [StaticAccessor("PrefabUtilityBindings", StaticAccessorType.DoubleColon)] -#pragma warning disable 0618 // Type or member is obsolete - extern private static GameObject SavePrefab_Internal([NotNull] GameObject root, string path, ReplacePrefabOptions replaceOptions, PrefabCreationFlags createOptions, out bool success); -#pragma warning restore 0618 // Type or member is obsolete + extern private static GameObject SavePrefabAsset_Internal([NotNull] GameObject root, out bool success); internal static void AddGameObjectsToPrefabAndConnect(GameObject[] gameObjects, Object targetPrefab) { diff --git a/Editor/Mono/Prefabs/PrefabUtility.cs b/Editor/Mono/Prefabs/PrefabUtility.cs index fba53d5971..25fa4f6bb1 100644 --- a/Editor/Mono/Prefabs/PrefabUtility.cs +++ b/Editor/Mono/Prefabs/PrefabUtility.cs @@ -9,6 +9,7 @@ using UnityEngine; using UnityEngine.Assertions; using UnityEditor; +using UnityEditor.Utils; using UnityEngine.SceneManagement; using UnityEditor.SceneManagement; using Object = UnityEngine.Object; @@ -157,7 +158,7 @@ internal static void ExtractMaterialsFromAsset(Object[] targets, string destinat } } - private static void GetObjectListFromHierarchy(HashSet hierarchyInstanceIDs, GameObject gameObject) + internal static void GetObjectListFromHierarchy(HashSet hierarchyInstanceIDs, GameObject gameObject) { Transform transform = null; List components = new List(); @@ -220,7 +221,7 @@ private static void CollectAddedObjects(GameObject gameObject, HashSet hier } } - private static void RegisterNewObjects(GameObject newHierarchy, HashSet hierarchyInstanceIDs, string actionName) + internal static void RegisterNewObjects(GameObject newHierarchy, HashSet hierarchyInstanceIDs, string actionName) { var danglingObjects = new List(); @@ -285,7 +286,7 @@ private static void RegisterNewObjects(GameObject newHierarchy, HashSet hie } } - static void ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(Object prefabInstanceObject) + static void ThrowExceptionIfNotValidPrefabInstanceObject(Object prefabInstanceObject, bool isApply) { if (!(prefabInstanceObject is GameObject || prefabInstanceObject is Component)) throw new ArgumentException("Calling apply or revert methods on an object which is not a GameObject or Component is not supported.", nameof(prefabInstanceObject)); @@ -293,18 +294,21 @@ static void ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(Object pre throw new NullReferenceException("Cannot apply or revert object. Object is null."); if (!PrefabUtility.IsPartOfPrefabInstance(prefabInstanceObject)) throw new ArgumentException("Calling apply or revert methods on an object which is not part of a Prefab instance is not supported.", nameof(prefabInstanceObject)); - ThrowExceptionIfInstanceIsPersistent(prefabInstanceObject); + + // We support revert operations on Prefab Assets, but not apply operations. + if (isApply) + ThrowExceptionIfInstanceIsPersistent(prefabInstanceObject); } static void ThrowExceptionIfInstanceIsPersistent(Object prefabInstanceObject) { if (EditorUtility.IsPersistent(prefabInstanceObject)) - throw new ArgumentException("Calling apply or revert methods on an instance which is part of a Prefab Asset is not supported.", nameof(prefabInstanceObject)); + throw new ArgumentException("Calling apply methods on an instance which is part of a Prefab Asset is not supported.", nameof(prefabInstanceObject)); } public static void RevertPrefabInstance(GameObject instanceRoot, InteractionMode action) { - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(instanceRoot); + ThrowExceptionIfNotValidPrefabInstanceObject(instanceRoot, false); bool isDisconnected = PrefabUtility.IsDisconnectedFromPrefabAsset(instanceRoot); @@ -324,12 +328,11 @@ public static void RevertPrefabInstance(GameObject instanceRoot, InteractionMode if (action == InteractionMode.UserAction) { + RegisterNewObjects(prefabInstanceRoot, hierarchy, actionName); if (isDisconnected) { Undo.RegisterCreatedObjectUndo(GetPrefabInstanceHandle(prefabInstanceRoot), actionName); } - - RegisterNewObjects(prefabInstanceRoot, hierarchy, actionName); } } @@ -337,9 +340,10 @@ public static void ApplyPrefabInstance(GameObject instanceRoot, InteractionMode { DateTime startTime = DateTime.UtcNow; - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(instanceRoot); + ThrowExceptionIfNotValidPrefabInstanceObject(instanceRoot, true); GameObject prefabInstanceRoot = GetOutermostPrefabInstanceRoot(instanceRoot); + var isDisconnected = GetPrefabInstanceHandle(prefabInstanceRoot) == null; var actionName = "Apply instance to prefab"; Object correspondingSourceObject = GetCorrespondingObjectFromSource(prefabInstanceRoot); @@ -359,6 +363,12 @@ public static void ApplyPrefabInstance(GameObject instanceRoot, InteractionMode if (action == InteractionMode.UserAction) { RegisterNewObjects(correspondingSourceObject as GameObject, prefabHierarchy, actionName); // handles created objects + if (isDisconnected) + { + var prefabInstanceHandle = GetPrefabInstanceHandle(prefabInstanceRoot); + Assert.IsNotNull(prefabInstanceHandle); + Undo.RegisterCreatedObjectUndo(prefabInstanceHandle, actionName); + } } Analytics.SendApplyEvent( @@ -390,7 +400,7 @@ public static void ApplyPropertyOverride(SerializedProperty instanceProperty, st DateTime startTime = DateTime.UtcNow; Object prefabInstanceObject = instanceProperty.serializedObject.targetObject; - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(prefabInstanceObject); + ThrowExceptionIfNotValidPrefabInstanceObject(prefabInstanceObject, true); ApplyPropertyOverrides(prefabInstanceObject, instanceProperty, assetPath, true, action); @@ -490,12 +500,43 @@ static void ApplyPropertyOverrides(Object prefabInstanceObject, SerializedProper } } - // Write modified value to prefab source object. - for (int i = 0; i < serializedObjects.Count; i++) + // Ensure importing of saved Prefab Assets only kicks in after all Prefab Asset have been saved + AssetDatabase.StartAssetEditing(); + + try { - serializedObjects[i].ApplyModifiedProperties(); - if (action == InteractionMode.UserAction) - Undo.FlushUndoRecordObjects(); // flush'es ensure that SavePrefab() on undo/redo on the source happens in the right order + // Write modified value to prefab source object. + for (int i = 0; i < serializedObjects.Count; i++) + { + if (serializedObjects[i].ApplyModifiedProperties()) + SaveChangesToPrefabFileIfPersistent(serializedObjects[i]); + + if (action == InteractionMode.UserAction) + Undo.FlushUndoRecordObjects(); // flush'es ensure that SavePrefab() on undo/redo on the source happens in the right order + } + } + finally + { + AssetDatabase.StopAssetEditing(); + } + } + + static void SaveChangesToPrefabFileIfPersistent(SerializedObject serializedObject) + { + if (!EditorUtility.IsPersistent(serializedObject.targetObject)) + return; + + GameObject go = serializedObject.targetObject as GameObject; + if (go == null) + { + var cmp = serializedObject.targetObject as Component; + if (cmp != null) + go = cmp.gameObject; + } + + if (go != null) + { + SavePrefabAsset(go.transform.root.gameObject); } } @@ -663,7 +704,7 @@ static void ApplySingleProperty( public static void RevertPropertyOverride(SerializedProperty instanceProperty, InteractionMode action) { Object prefabInstanceObject = instanceProperty.serializedObject.targetObject; - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(prefabInstanceObject); + ThrowExceptionIfNotValidPrefabInstanceObject(prefabInstanceObject, false); instanceProperty.prefabOverride = false; // Because prefabOverride changed ApplyModifiedProperties will do a prefab merge causing the revert. @@ -677,7 +718,7 @@ public static void ApplyObjectOverride(Object instanceComponentOrGameObject, str { DateTime startTime = DateTime.UtcNow; - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(instanceComponentOrGameObject); + ThrowExceptionIfNotValidPrefabInstanceObject(instanceComponentOrGameObject, true); ApplyPropertyOverrides(instanceComponentOrGameObject, null, assetPath, false, action); @@ -693,7 +734,7 @@ public static void ApplyObjectOverride(Object instanceComponentOrGameObject, str public static void RevertObjectOverride(Object instanceComponentOrGameObject, InteractionMode action) { - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(instanceComponentOrGameObject); + ThrowExceptionIfNotValidPrefabInstanceObject(instanceComponentOrGameObject, false); if (action == InteractionMode.UserAction) Undo.RegisterCompleteObjectUndo(instanceComponentOrGameObject, "Revert component property overrides"); @@ -764,8 +805,6 @@ public static void RevertAddedComponent(Component component, InteractionMode act if (!PrefabUtility.IsAddedComponentOverride(component)) throw new ArgumentException("Cannot revert added component. Component is not an added component override on a Prefab instance.", nameof(component)); - ThrowExceptionIfInstanceIsPersistent(component); - if (action == InteractionMode.UserAction) { string dependentComponents = string.Join( @@ -820,7 +859,7 @@ public static void ApplyRemovedComponent(GameObject instanceGameObject, Componen { DateTime startTime = DateTime.UtcNow; - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(instanceGameObject); + ThrowExceptionIfNotValidPrefabInstanceObject(instanceGameObject, true); if (assetComponent == null) throw new ArgumentNullException(nameof(assetComponent), "Prefab source may not be null."); @@ -877,7 +916,7 @@ private static void RemoveRemovedComponentOverride(Object instanceObject, Compon public static void RevertRemovedComponent(GameObject instanceGameObject, Component assetComponent, InteractionMode action) { - ThrowExceptionIfNotValidNonPersistentPrefabInstanceObject(instanceGameObject); + ThrowExceptionIfNotValidPrefabInstanceObject(instanceGameObject, false); var actionName = "Revert Prefab removed component"; var prefabInstanceObject = PrefabUtility.GetPrefabInstanceHandle(instanceGameObject); @@ -1010,7 +1049,8 @@ internal static void HandleApplyMenuItems( string thingThatChanged, Object instanceOrAssetObject, Action addApplyMenuItemAction, - bool defaultOverrideComparedToSomeSources = false) + bool defaultOverrideComparedToSomeSources = false, + bool includeSelfAsTarget = false) { // If thingThatChanged word is empty, apply menu items directly into menu. // Otherwise, insert as sub-menu named after thingThatChanged. @@ -1019,7 +1059,7 @@ internal static void HandleApplyMenuItems( if (thingThatChanged != String.Empty) thingThatChanged += "/"; - List applyTargets = GetApplyTargets(instanceOrAssetObject, defaultOverrideComparedToSomeSources); + List applyTargets = GetApplyTargets(instanceOrAssetObject, defaultOverrideComparedToSomeSources, includeSelfAsTarget); if (applyTargets == null || applyTargets.Count == 0) return; @@ -1141,6 +1181,12 @@ public static Object CreateEmptyPrefab(string path) } public static GameObject SavePrefabAsset(GameObject asset) + { + bool savedSuccesfully; + return SavePrefabAsset(asset, out savedSuccesfully); + } + + public static GameObject SavePrefabAsset(GameObject asset, out bool savedSuccessfully) { if (asset == null) throw new ArgumentNullException("Parameter prefabAssetGameObject is null"); @@ -1160,12 +1206,34 @@ public static GameObject SavePrefabAsset(GameObject asset) if (root != asset) throw new ArgumentException("GameObject to save Prefab from must be a Prefab root"); -#pragma warning disable CS0618 // Type or member is obsolete - return SavePrefab(root, path, ReplacePrefabOptions.Default, PrefabCreationFlags.None); -#pragma warning restore CS0618 // Type or member is obsolete + return SavePrefabAsset_Internal(root, out savedSuccessfully); + } + + private static void ValidatePath(GameObject instanceRoot, string path) + { + if (String.IsNullOrEmpty(path)) + throw new ArgumentNullException("path is null or empty"); + + if (!Paths.IsValidAssetPath(path, ".prefab")) + throw new ArgumentException("Given path is not valid: '" + path + "'"); + + string directory = Path.GetDirectoryName(path); + + bool isRootFolder = false; + bool isImmutableFolder = false; + bool isValidAssetFolder = AssetDatabase.GetAssetFolderInfo(directory, out isRootFolder, out isImmutableFolder); + if (isValidAssetFolder && isImmutableFolder) + throw new ArgumentException("Saving Prefab to immutable folder is not allowed: '" + path + "'"); + + if (directory.Length > 0 && !Directory.Exists(directory)) + throw new ArgumentException("Given path does not exist: '" + path + "'"); + + string prefabGUID = AssetDatabase.AssetPathToGUID(path); + if (!VerifyNestingFromScript(new GameObject[] {instanceRoot}, prefabGUID, PrefabUtility.GetPrefabInstanceHandle(instanceRoot))) + throw new ArgumentException("Cyclic nesting detected"); } - private static void SaveAsPrefabAssetArgumentCheck(GameObject instanceRoot) + private static void SaveAsPrefabAssetArgumentCheck(GameObject instanceRoot, string path) { if (instanceRoot == null) throw new ArgumentNullException("Parameter root is null"); @@ -1182,6 +1250,16 @@ private static void SaveAsPrefabAssetArgumentCheck(GameObject instanceRoot) if (actualInstanceRoot != instanceRoot) throw new ArgumentException("Can't save part of a Prefab instance as a Prefab"); } + + ValidatePath(instanceRoot, path); + } + + private static void ReplacePrefabArgumentCheck(GameObject root, string path) + { + if (root == null) + throw new ArgumentNullException("Parameter root is null"); + + ValidatePath(root, path); } private static bool IsPrefabInstanceRoot(GameObject gameObject) @@ -1192,15 +1270,9 @@ private static bool IsPrefabInstanceRoot(GameObject gameObject) public static GameObject SaveAsPrefabAsset(GameObject instanceRoot, string assetPath, out bool success) { - SaveAsPrefabAssetArgumentCheck(instanceRoot); + SaveAsPrefabAssetArgumentCheck(instanceRoot, assetPath); - PrefabCreationFlags creationFlags = PrefabCreationFlags.None; - if (IsPrefabInstanceRoot(instanceRoot)) - creationFlags = PrefabCreationFlags.CreateVariant; - -#pragma warning disable CS0618 // Type or member is obsolete - return SavePrefab(instanceRoot, assetPath, ReplacePrefabOptions.Default, creationFlags, out success); -#pragma warning restore CS0618 // Type or member is obsolete + return SaveAsPrefabAsset_Internal(instanceRoot, assetPath, out success); } public static GameObject SaveAsPrefabAsset(GameObject instanceRoot, string assetPath) @@ -1217,7 +1289,7 @@ public static GameObject SaveAsPrefabAssetAndConnect(GameObject instanceRoot, st public static GameObject SaveAsPrefabAssetAndConnect(GameObject instanceRoot, string assetPath, InteractionMode action, out bool success) { - SaveAsPrefabAssetArgumentCheck(instanceRoot); + SaveAsPrefabAssetArgumentCheck(instanceRoot, assetPath); var actionName = "Connect to Prefab"; @@ -1226,13 +1298,7 @@ public static GameObject SaveAsPrefabAssetAndConnect(GameObject instanceRoot, st Undo.RegisterFullObjectHierarchyUndo(instanceRoot, actionName); } - PrefabCreationFlags creationFlags = PrefabCreationFlags.None; - if (IsPrefabInstanceRoot(instanceRoot)) - creationFlags = PrefabCreationFlags.CreateVariant; - -#pragma warning disable CS0618 // Type or member is obsolete - var assetRoot = SavePrefab(instanceRoot, assetPath, ReplacePrefabOptions.ConnectToPrefab, creationFlags, out success); -#pragma warning restore CS0618 // Type or member is obsolete + var assetRoot = SaveAsPrefabAssetAndConnect_Internal(instanceRoot, assetPath, out success); if (!success) { @@ -1281,35 +1347,9 @@ internal static void ApplyPrefabInstance(GameObject instance) var assetObject = GetCorrespondingObjectFromSource(instance); string path = AssetDatabase.GetAssetPath(assetObject); -#pragma warning disable CS0618 // Type or member is obsolete - SavePrefab(instance, path, ReplacePrefabOptions.ConnectToPrefab, PrefabCreationFlags.None); -#pragma warning restore CS0618 // Type or member is obsolete - } - - // TOOO: Remove entirely once regular methods handle merging - // based on both ids and names on a smarter and more granular level. - internal static GameObject ReplacePrefabAssetNameBased(GameObject root, string targetPrefab, bool connectToInstance) - { -#pragma warning disable CS0618 // Type or member is obsolete - var options = ReplacePrefabOptions.ReplaceNameBased; - if (connectToInstance) - options |= ReplacePrefabOptions.ConnectToPrefab; - - var createOptions = PrefabCreationFlags.None; - - if (IsPartOfNonAssetPrefabInstance(root)) - { - if (!IsOutermostPrefabInstanceRoot(root)) - throw new ArgumentException("Can't replace with part of Prefab instance. Please specify instance root object or a non-instance object."); - - createOptions = PrefabCreationFlags.CreateVariant; - } - - if (IsPartOfPrefabAsset(root) && connectToInstance) - throw new ArgumentException("Argument connectToInstance is true but root object is an asset not an instance"); + SaveAsPrefabAssetArgumentCheck(instance, path); - return SavePrefab(root, targetPrefab, options, createOptions); -#pragma warning restore CS0618 // Type or member is obsolete + ApplyPrefabInstance_Internal(instance); } // Can't use UnityUpgradable since it doesn't currently support swapping parameter order. @@ -1322,13 +1362,8 @@ public static GameObject CreatePrefab(string path, GameObject go) [Obsolete("Use SaveAsPrefabAsset or SaveAsPrefabAssetAndConnect instead.")] public static GameObject CreatePrefab(string path, GameObject go, ReplacePrefabOptions options) { - if (options == ReplacePrefabOptions.ConnectToPrefab) + if ((options & ReplacePrefabOptions.ConnectToPrefab) != 0) return SaveAsPrefabAssetAndConnect(go, path, InteractionMode.AutomatedAction); - else if ((options & ReplacePrefabOptions.ReplaceNameBased) != 0) - { - bool connectToPrefab = (options & ReplacePrefabOptions.ConnectToPrefab) != 0; - return ReplacePrefabAssetNameBased(go, path, connectToPrefab); - } else return SaveAsPrefabAsset(go, path); } @@ -1336,13 +1371,18 @@ public static GameObject CreatePrefab(string path, GameObject go, ReplacePrefabO // Instantiates the given prefab. public static Object InstantiatePrefab(Object assetComponentOrGameObject) { - return InstantiatePrefab_internal(assetComponentOrGameObject, EditorSceneManager.GetTargetSceneForNewGameObjects()); + return InstantiatePrefab_internal(assetComponentOrGameObject, EditorSceneManager.GetTargetSceneForNewGameObjects(), null); } // Instantiates the given prefab in a given scene public static Object InstantiatePrefab(Object assetComponentOrGameObject, Scene destinationScene) { - return InstantiatePrefab_internal(assetComponentOrGameObject, destinationScene); + return InstantiatePrefab_internal(assetComponentOrGameObject, destinationScene, null); + } + + public static Object InstantiatePrefab(Object assetComponentOrGameObject, Transform parent) + { + return InstantiatePrefab_internal(assetComponentOrGameObject, EditorSceneManager.GetTargetSceneForNewGameObjects(), parent); } [Obsolete("Use SaveAsPrefabAsset with a path instead.")] @@ -1388,7 +1428,20 @@ public static GameObject ReplacePrefab(GameObject go, Object targetPrefab, Repla } var assetPath = AssetDatabase.GetAssetPath(targetPrefabObject); - return SavePrefab(go, assetPath, replaceOptions, PrefabCreationFlags.None); + + ReplacePrefabArgumentCheck(go, assetPath); + + bool success = false; + return SavePrefab_Internal(go, assetPath, (replaceOptions & ReplacePrefabOptions.ConnectToPrefab) != 0, out success); + } + + // Returns the corresponding object from its immediate source from a connected Prefab, + // or null if it can't be found, or the Prefab instance is disconnected. + internal static TObject GetCorrespondingConnectedObjectFromSource(TObject componentOrGameObject) where TObject : Object + { + if (IsDisconnectedFromPrefabAsset(GetGameObject(componentOrGameObject))) + return null; + return (TObject)GetCorrespondingObjectFromSource_internal(componentOrGameObject); } // Returns the corresponding object from its immediate source, or null if it can't be found. @@ -1491,6 +1544,9 @@ public static bool IsAddedGameObjectOverride(GameObject gameObject) if (parent == null) return false; + if (IsDisconnectedFromPrefabAsset(parent)) + return false; + // Can't be added to a prefab instance if the parent is not part of a prefab instance. GameObject parentAsset = (GameObject)PrefabUtility.GetCorrespondingObjectFromSource(parent.gameObject); if (parentAsset == null) @@ -1661,6 +1717,12 @@ public static PrefabAssetType GetPrefabAssetType(Object componentOrGameObject) public static GameObject LoadPrefabContents(string assetPath) { + if (!File.Exists(assetPath)) + throw new ArgumentException(string.Format("Path: {0}, does not exist", assetPath)); + + if (Path.GetExtension(assetPath) != ".prefab") + throw new ArgumentException(string.Format("Path: {0}, is not a prefab file", assetPath)); + var previewScene = EditorSceneManager.OpenPreviewScene(assetPath); var roots = previewScene.GetRootGameObjects(); if (roots.Length != 1) @@ -1768,7 +1830,7 @@ internal static bool IsObjectOnRootInAsset(Object componentOrGameObject, string return goInAsset.transform.root == goInAsset.transform; } - internal static List GetApplyTargets(Object instanceOrAssetObject, bool defaultOverrideComparedToSomeSources) + internal static List GetApplyTargets(Object instanceOrAssetObject, bool defaultOverrideComparedToSomeSources, bool includeSelfAsTarget = false) { List applyTargets = new List(); @@ -1777,8 +1839,8 @@ internal static List GetApplyTargets(Object instanceOrAssetObject, bool instanceGameObject = (instanceOrAssetObject as Component).gameObject; Object source = instanceOrAssetObject; - if (!EditorUtility.IsPersistent(source)) - source = PrefabUtility.GetCorrespondingObjectFromSource(instanceOrAssetObject); + if (!EditorUtility.IsPersistent(source) || !includeSelfAsTarget) + source = PrefabUtility.GetCorrespondingObjectFromSource(source); if (source == null) return applyTargets; diff --git a/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs b/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs index 3dc2e83a95..368e537f42 100644 --- a/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs +++ b/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs @@ -95,7 +95,7 @@ internal class TwoDProperties internal class LanguageProperties { - public static readonly GUIContent editorLanguageExperimental = EditorGUIUtility.TrTextContent("Editor Language(Experimental)"); + public static readonly GUIContent editorLanguageExperimental = EditorGUIUtility.TrTextContent("Editor Language (Experimental)"); public static readonly GUIContent editorLanguage = EditorGUIUtility.TrTextContent("Editor language"); } @@ -141,7 +141,6 @@ private struct GICacheSettings private static SystemLanguage[] m_stableLanguages = { SystemLanguage.English }; private bool m_AllowAlphaNumericHierarchy = false; - private bool m_AsyncShaderCompilation = true; private string[] m_ScriptApps; private string[] m_ScriptAppsEditions; @@ -478,8 +477,6 @@ private void ShowGeneral(string searchContext) bool oldAlphaNumeric = m_AllowAlphaNumericHierarchy; m_AllowAlphaNumericHierarchy = EditorGUILayout.Toggle(GeneralProperties.enableAlphaNumericSorting, m_AllowAlphaNumericHierarchy); - m_AsyncShaderCompilation = EditorGUILayout.Toggle(GeneralProperties.asyncShaderCompilation, m_AsyncShaderCompilation); - if (InternalEditorUtility.IsGpuDeviceSelectionSupported()) { // Cache gpu devices @@ -787,7 +784,6 @@ private void WritePreferences() EditorPrefs.SetString("Editor.kEditorLocale", m_SelectedLanguage); EditorPrefs.SetBool("AllowAlphaNumericHierarchy", m_AllowAlphaNumericHierarchy); - EditorPrefs.SetBool("AsynchronousShaderCompilation", m_AsyncShaderCompilation); EditorPrefs.SetString("GpuDeviceName", m_GpuDevice); EditorPrefs.SetBool("GICacheEnableCustomPath", m_GICacheSettings.m_EnableCustomPath); @@ -895,7 +891,6 @@ private void ReadPreferences() m_EnableEditorLocalization = EditorPrefs.GetBool("Editor.kEnableEditorLocalization", true); m_SelectedLanguage = EditorPrefs.GetString("Editor.kEditorLocale", LocalizationDatabase.GetDefaultEditorLanguage().ToString()); m_AllowAlphaNumericHierarchy = EditorPrefs.GetBool("AllowAlphaNumericHierarchy", false); - m_AsyncShaderCompilation = EditorPrefs.GetBool("AsynchronousShaderCompilation", true); m_CompressAssetsOnImport = Unsupported.GetApplicationSettingCompressAssetsOnImport(); m_GpuDevice = EditorPrefs.GetString("GpuDeviceName"); diff --git a/Editor/Mono/ProjectBrowser.cs b/Editor/Mono/ProjectBrowser.cs index 35fbe7f4a5..65cdcce3c3 100644 --- a/Editor/Mono/ProjectBrowser.cs +++ b/Editor/Mono/ProjectBrowser.cs @@ -144,6 +144,10 @@ bool useTreeViewSelectionInsteadOfMainSelection [SerializeField] ObjectListAreaState m_ListAreaState; // state that survives assembly reloads ObjectListArea m_ListArea; + internal ObjectListArea ListArea // Exposed for usage in tests + { + get { return m_ListArea; } + } int m_ListKeyboardControlID; bool m_GrabKeyboardFocusForListArea = false; @@ -354,15 +358,13 @@ private void OnProjectChanged() { if (m_AssetTree != null) { - m_AssetTree = null; - InitOneColumnView(); + m_AssetTree.ReloadData(); SetSearchFoldersFromCurrentSelection(); // We could have moved, deleted or renamed a folder so ensure we get folder paths by instanceID } if (m_FolderTree != null) { - m_FolderTree = null; - InitTwoColumnView(); + m_FolderTree.ReloadData(); SetSearchFolderFromFolderTreeSelection(); // We could have moved, deleted or renamed a folder so ensure we get folders paths by instanceID } @@ -778,7 +780,7 @@ void SetViewMode(ViewMode newViewMode) RepaintImmediately(); } - void EndRenaming() + public void EndRenaming() { if (m_AssetTree != null) m_AssetTree.EndNameEditing(true); @@ -2639,7 +2641,7 @@ void BottomBar() EditorGUIUtility.SetIconSize(new Vector2(0, 0)); } - void SelectAssetsFolder() + public void SelectAssetsFolder() { ShowFolderContents(AssetDatabase.GetMainAssetOrInProgressProxyInstanceID("Assets"), true); } diff --git a/Editor/Mono/ProjectWindow/ProjectWindowUtil.cs b/Editor/Mono/ProjectWindow/ProjectWindowUtil.cs index d031ced457..91f83b73ad 100644 --- a/Editor/Mono/ProjectWindow/ProjectWindowUtil.cs +++ b/Editor/Mono/ProjectWindow/ProjectWindowUtil.cs @@ -15,6 +15,7 @@ using UnityEditor.Utils; using UnityEngine; using UnityEngine.Internal; +using UnityEngine.Scripting; using Object = UnityEngine.Object; namespace UnityEditor @@ -297,10 +298,19 @@ public static void CreateAssetWithContent(string filename, string content, Textu StartNameEditingIfProjectWindowExists(0, action, filename, icon, null); } - static void CreateScriptAsset(string templatePath, string destName) + [RequiredByNativeCode] + public static void CreateScriptAssetFromTemplateFile(string templatePath, string defaultNewFileName) { + if (templatePath == null) + throw new ArgumentNullException(nameof(templatePath)); + if (!File.Exists(templatePath)) + throw new FileNotFoundException($"The template file \"{templatePath}\" could not be found.", templatePath); + + if (string.IsNullOrEmpty(defaultNewFileName)) + defaultNewFileName = Path.GetFileName(templatePath); + Texture2D icon = null; - switch (Path.GetExtension(destName)) + switch (Path.GetExtension(defaultNewFileName)) { case ".cs": icon = EditorGUIUtility.IconContent("cs Script Icon").image as Texture2D; @@ -315,7 +325,7 @@ static void CreateScriptAsset(string templatePath, string destName) icon = EditorGUIUtility.IconContent().image as Texture2D; break; } - StartNameEditingIfProjectWindowExists(0, ScriptableObject.CreateInstance(), destName, icon, templatePath); + StartNameEditingIfProjectWindowExists(0, ScriptableObject.CreateInstance(), defaultNewFileName, icon, templatePath); } public static void ShowCreatedAsset(Object o) diff --git a/Editor/Mono/RetainedMode.cs b/Editor/Mono/RetainedMode.cs index d484034930..5e8d7aeac8 100644 --- a/Editor/Mono/RetainedMode.cs +++ b/Editor/Mono/RetainedMode.cs @@ -13,10 +13,8 @@ using UnityEngine.UIElements.StyleSheets; using UnityEngine.Scripting; -using UXMLImporterImpl = UnityEditor.Experimental.UIElements.UXMLImporterImpl; +using UXMLImporterImpl = UnityEditor.UIElements.UXMLImporterImpl; -using ExperimentalUI = UnityEngine.Experimental.UIElements; -using EditorExperimentalUI = UnityEditor.Experimental.UIElements; namespace UnityEditor { @@ -38,16 +36,9 @@ static RetainedMode() UIElementsUtility.s_BeginContainerCallback = OnBeginContainer; UIElementsUtility.s_EndContainerCallback = OnEndContainer; - ExperimentalUI.UIElementsUtility.s_BeginContainerCallback = (v) => OnBeginContainer(null); - ExperimentalUI.UIElementsUtility.s_EndContainerCallback = (v) => OnEndContainer(null); - Panel.loadResourceFunc = StyleSheetResourceUtil.LoadResource; StyleSheetApplicator.getCursorIdFunc = UIElementsEditorUtility.GetCursorId; Panel.TimeSinceStartup = () => (long)(EditorApplication.timeSinceStartup * 1000.0f); - - ExperimentalUI.Panel.loadResourceFunc = StyleSheetResourceUtil.LoadResource; - ExperimentalUI.StyleSheets.StyleSheetApplicator.getCursorIdFunc = EditorExperimentalUI.UIElementsEditorUtility.GetCursorId; - ExperimentalUI.Panel.TimeSinceStartup = () => (long)(EditorApplication.timeSinceStartup * 1000.0f); } static void OnBeginContainer(IMGUIContainer c) @@ -72,78 +63,37 @@ static void UpdateSchedulers() { DataWatchService.sharedInstance.PollNativeData(); + UIElementsUtility.GetAllPanels(panelsIteration); + foreach (var panel in panelsIteration) { - UIElementsUtility.GetAllPanels(panelsIteration); - foreach (var panel in panelsIteration) - { - // Game panels' scheduler are ticked by the engine - if (panel.contextType != ContextType.Editor) - continue; - - // Dispatch all timer update messages to each scheduled item - panel.timerEventScheduler.UpdateScheduledEvents(); - panel.UpdateBindings(); - } - } - - //temporary Experimental wrapper - { - var iterator = ExperimentalUI.UIElementsUtility.GetPanelsIterator(); - while (iterator.MoveNext()) - { - var panel = iterator.Current.Value; + // Game panels' scheduler are ticked by the engine + if (panel.contextType != ContextType.Editor) + continue; - // Game panels' scheduler are ticked by the engine - if (panel.contextType != ExperimentalUI.ContextType.Editor) - continue; - - // Dispatch all timer update messages to each scheduled item - panel.timerEventScheduler.UpdateScheduledEvents(); - panel.UpdateBindings(); - } + // Dispatch all timer update messages to each scheduled item + panel.timerEventScheduler.UpdateScheduledEvents(); + panel.UpdateBindings(); } } [RequiredByNativeCode] static void RequestRepaintForPanels() { + var iterator = UIElementsUtility.GetPanelsIterator(); + while (iterator.MoveNext()) { - var iterator = UIElementsUtility.GetPanelsIterator(); - while (iterator.MoveNext()) - { - var panel = iterator.Current.Value; + var panel = iterator.Current.Value; - // Game panels' scheduler are ticked by the engine - if (panel.contextType != ContextType.Editor) - continue; + // Game panels' scheduler are ticked by the engine + if (panel.contextType != ContextType.Editor) + continue; - // Dispatch might have triggered a repaint request. - if (panel.isDirty) - { - var guiView = panel.ownerObject as GUIView; - if (guiView != null) - guiView.Repaint(); - } - } - } - - { - var iterator = ExperimentalUI.UIElementsUtility.GetPanelsIterator(); - while (iterator.MoveNext()) + // Dispatch might have triggered a repaint request. + if (panel.isDirty) { - var panel = iterator.Current.Value; - - // Game panels' scheduler are ticked by the engine - if (panel.contextType != ExperimentalUI.ContextType.Editor) - continue; - - // Dispatch might have triggered a repaint request. - if (panel.isDirty) - { - var guiView = panel.ownerObject as GUIView; - if (guiView != null) - guiView.Repaint(); - } + var guiView = panel.ownerObject as GUIView; + if (guiView != null) + guiView.Repaint(); } } } @@ -172,7 +122,6 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse // the inline stylesheet cache might get out of date. // Usually called by the USS importer, which might not get called here UnityEngine.UIElements.StyleSheets.StyleSheetCache.ClearCaches(); - ExperimentalUI.StyleSheets.StyleSheetCache.ClearCaches(); if (UxmlLiveReloadIsEnabled && Unsupported.IsDeveloperMode()) { // Delay the view reloading so we do not try to reload the view that @@ -192,26 +141,13 @@ private static void OneShotUxmlLiveReload() { try { + var it = UIElementsUtility.GetPanelsIterator(); + while (it.MoveNext()) { - var it = ExperimentalUI.UIElementsUtility.GetPanelsIterator(); - while (it.MoveNext()) - { - var view = it.Current.Value.ownerObject as HostView; - if (view != null && view.actualView != null && !(view.actualView is UIElementsDebugger)) - { - view.Reload(view.actualView); - } - } - } - { - var it = UIElementsUtility.GetPanelsIterator(); - while (it.MoveNext()) + var view = it.Current.Value.ownerObject as HostView; + if (view != null && view.actualView != null && !(view.actualView is UIElementsDebugger)) { - var view = it.Current.Value.ownerObject as HostView; - if (view != null && view.actualView != null && !(view.actualView is UIElementsDebugger)) - { - view.Reload(view.actualView); - } + view.Reload(view.actualView); } } } @@ -228,43 +164,22 @@ public static void FlagStyleSheetChange() { // clear caches that depend on loaded style sheets UnityEngine.UIElements.StyleSheets.StyleSheetCache.ClearCaches(); - ExperimentalUI.StyleSheets.StyleSheetCache.ClearCaches(); - - { - // for now we don't bother tracking which panel depends on which style sheet - var iterator = ExperimentalUI.UIElementsUtility.GetPanelsIterator(); - while (iterator.MoveNext()) - { - var panel = iterator.Current.Value; - // In-game doesn't support styling - if (panel.contextType != ExperimentalUI.ContextType.Editor) - continue; - - panel.DirtyStyleSheets(); - - var guiView = panel.ownerObject as GUIView; - if (guiView != null) - guiView.Repaint(); - } - } + // for now we don't bother tracking which panel depends on which style sheet + var iterator = UIElementsUtility.GetPanelsIterator(); + while (iterator.MoveNext()) { - // for now we don't bother tracking which panel depends on which style sheet - var iterator = UIElementsUtility.GetPanelsIterator(); - while (iterator.MoveNext()) - { - var panel = iterator.Current.Value; + var panel = iterator.Current.Value; - // In-game doesn't support styling - if (panel.contextType != ContextType.Editor) - continue; + // In-game doesn't support styling + if (panel.contextType != ContextType.Editor) + continue; - panel.DirtyStyleSheets(); + panel.DirtyStyleSheets(); - var guiView = panel.ownerObject as GUIView; - if (guiView != null) - guiView.Repaint(); - } + var guiView = panel.ownerObject as GUIView; + if (guiView != null) + guiView.Repaint(); } } } diff --git a/Editor/Mono/SceneHierarchy.cs b/Editor/Mono/SceneHierarchy.cs index 8eabfa19e8..085b337429 100644 --- a/Editor/Mono/SceneHierarchy.cs +++ b/Editor/Mono/SceneHierarchy.cs @@ -469,8 +469,12 @@ public virtual void OnBecameVisible() public virtual void OnLostFocus() { - // Added because this window uses RenameOverlay - treeView.EndNameEditing(true); + // On lost focus can be called before OnEnable have been called + if (m_TreeView != null) + { + // Added because this window uses RenameOverlay + m_TreeView.EndNameEditing(true); + } } public virtual void OnEnable() @@ -580,7 +584,7 @@ public void OnGUI(Rect rect) float searchPathHeight = DoSearchResultPathGUI(); DoTreeView(searchPathHeight); - DoSceneVisibilityBackgroundOverflow(); + DoSceneVisibilityBackgroundOverflow(searchPathHeight); DoPingRequest(); ExecuteCommands(); @@ -594,9 +598,24 @@ public static bool IsSceneHeaderInHierarchyWindow(Scene scene) void TreeViewItemDoubleClicked(int instanceID) { - Scene scene = EditorSceneManager.GetSceneByHandle(instanceID); + bool setActiveScene = false; + Scene scene = EditorSceneManager.GetSceneByHandle(instanceID); if (IsSceneHeaderInHierarchyWindow(scene)) + { + setActiveScene = true; + } + else if (SubSceneGUI.IsUsingSubScenes()) + { + var gameObject = EditorUtility.InstanceIDToObject(instanceID) as GameObject; + if (gameObject != null && SubSceneGUI.IsSubSceneHeader(gameObject)) + { + scene = SubSceneGUI.GetSubScene(gameObject); + setActiveScene = true; + } + } + + if (setActiveScene) { // scene header selected if (scene.isLoaded && !EditorSceneManager.IsPreviewScene(scene)) @@ -745,11 +764,17 @@ void OnEvent() // Tree view item handle their own scene visibility background. // So the background doesn't stop if we don't have enough item to fill the entire tree view rect, we draw the background in the unused space. - private void DoSceneVisibilityBackgroundOverflow() + private void DoSceneVisibilityBackgroundOverflow(float reservedFooterSpace) { - Vector2 sizeTaken = treeView.gui.GetTotalSize(); + float treeViewHeight = treeView.gui.GetTotalSize().y; Rect rectWithNoRows = treeViewRect; - rectWithNoRows.yMin += sizeTaken.y; + + //If the tree view already covers the entire rect, we don't need to fill the overflow + if (rectWithNoRows.height <= treeViewHeight) + return; + + rectWithNoRows.yMin += treeViewHeight; + rectWithNoRows.height -= reservedFooterSpace; SceneVisibilityHierarchyGUI.DrawBackground(rectWithNoRows); } @@ -974,7 +999,7 @@ void CreateGameObjectContextClick(GenericMenu menu, int contextClickedItemID) menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Rename")); menu.AddItem(EditorGUIUtility.TrTextContent("Duplicate"), false, DuplicateGO); - if (GetIsCustomParentSelected() || GetIsNotEditable()) + if (GetIsCustomParentSelected()) menu.AddDisabledItem(EditorGUIUtility.TrTextContent("Delete")); else menu.AddItem(EditorGUIUtility.TrTextContent("Delete"), false, DeleteGO); @@ -1038,7 +1063,7 @@ void CreateGameObjectContextClick(GenericMenu menu, int contextClickedItemID) info.instanceObject = go; info.assetPath = AssetDatabase.GetAssetPath(sourceGo); GameObject rootGo = PrefabUtility.GetRootGameObject(sourceGo); - if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootGo)) + if (!PrefabUtility.IsPartOfPrefabThatCanBeAppliedTo(rootGo) || EditorUtility.IsPersistent(parentTransform)) menu.AddDisabledItem(menuItemContent); else menu.AddItem(menuItemContent, false, TargetChoiceHandler.ApplyPrefabAddedGameObject, info); @@ -1070,6 +1095,9 @@ void CreateGameObjectContextClick(GenericMenu menu, int contextClickedItemID) // Sets includeCreateEmptyChild to false, since that item is superfluous here (the normal "Create Empty" is added as a child anyway) AddCreateGameObjectItemsToMenu(menu, selectedGameObjects, false, false, targetSceneForCreation); } + + SceneHierarchyHooks.AddCustomGameObjectContextMenuItems(menu, contextClickedItemID == 0 ? null : (GameObject)EditorUtility.InstanceIDToObject(contextClickedItemID)); + menu.ShowAsContext(); } @@ -1187,6 +1215,9 @@ void CreateMultiSceneHeaderContextClick(GenericMenu menu, int contextClickedItem menu.AddSeparator(""); AddCreateGameObjectItemsToSceneMenu(menu, scene); } + + // Let users add extra items + SceneHierarchyHooks.AddCustomSceneHeaderContextMenuItems(menu, scene); } int GetNumLoadedScenesInSelection() @@ -1267,7 +1298,9 @@ void ItemContextClick(int contextClickedItemID) } else { - CreateGameObjectContextClick(menu, contextClickedItemID); + var gameObject = (GameObject)EditorUtility.InstanceIDToObject(contextClickedItemID); + if (!SubSceneGUI.HandleGameObjectContextMenu(menu, gameObject)) + CreateGameObjectContextClick(menu, contextClickedItemID); } menu.ShowAsContext(); @@ -1603,9 +1636,18 @@ private void SelectPrefabRoot() TreeViewSelectionChanged(newSelection); } + public void CollapseAll() + { + treeViewState.expandedIDs.Clear(); + ReloadData(); + } + public virtual void AddItemsToWindowMenu(GenericMenu menu) { + menu.AddItem(EditorGUIUtility.TrTextContent("Collapse All"), false, CollapseAll); + menu.AddSeparator(""); m_LockTracker.AddItemsToMenu(menu); + if (Unsupported.IsDeveloperMode()) { menu.AddItem(new GUIContent("DEVELOPER/Debug Mode - Hierarchy "), s_Debug, () => s_Debug = !s_Debug); diff --git a/Editor/Mono/SceneHierarchyHooks.cs b/Editor/Mono/SceneHierarchyHooks.cs new file mode 100644 index 0000000000..774551760a --- /dev/null +++ b/Editor/Mono/SceneHierarchyHooks.cs @@ -0,0 +1,49 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using UnityEngine; +using UnityEngine.SceneManagement; +using System; + + +namespace UnityEditor.SceneManagement +{ + public static class SceneHierarchyHooks + { + public struct SubSceneInfo + { + public Transform transform; + public Scene scene; + public SceneAsset sceneAsset; + public string sceneName; + public Color32 color; + + + public bool isValid + { + get { return transform != null; } + } + } + + public static Func provideSubScenes; + public static event Action addItemsToGameObjectContextMenu; + public static event Action addItemsToSceneHeaderContextMenu; + + public static void ReloadAllSceneHierarchies() + { + foreach (var window in SceneHierarchyWindow.GetAllSceneHierarchyWindows()) + window.sceneHierarchy.ReloadData(); + } + + internal static void AddCustomGameObjectContextMenuItems(GenericMenu menu, GameObject gameObject) + { + addItemsToGameObjectContextMenu?.Invoke(menu, gameObject); + } + + internal static void AddCustomSceneHeaderContextMenuItems(GenericMenu menu, Scene scene) + { + addItemsToSceneHeaderContextMenu?.Invoke(menu, scene); + } + } +} diff --git a/Editor/Mono/SceneHierarchyStageHandling.cs b/Editor/Mono/SceneHierarchyStageHandling.cs index d590a5f6bd..f1eee9c597 100644 --- a/Editor/Mono/SceneHierarchyStageHandling.cs +++ b/Editor/Mono/SceneHierarchyStageHandling.cs @@ -46,6 +46,7 @@ public void OnEnable() StageNavigationManager.instance.prefabStageReloaded += OnPrefabStageReloaded; StageNavigationManager.instance.prefabStageToBeDestroyed += OnPrefabStageBeingDestroyed; PrefabStage.prefabIconChanged += OnPrefabStageIconChanged; + PrefabStage.prefabRootTransformChanged += OnPrefabStageRootTransformChanged; // To support expanded state of new unsaved GameObject in Prefab Mode across domain reloading we do not load the // last saved expanded state here but instead rely on the fact that the Hierarchy serializes its own expanded state already. @@ -61,6 +62,7 @@ public void OnDisable() StageNavigationManager.instance.prefabStageReloaded -= OnPrefabStageReloaded; StageNavigationManager.instance.prefabStageToBeDestroyed -= OnPrefabStageBeingDestroyed; PrefabStage.prefabIconChanged -= OnPrefabStageIconChanged; + PrefabStage.prefabRootTransformChanged -= OnPrefabStageRootTransformChanged; } void OnPrefabStageBeingDestroyed(StageNavigationItem prefabStage) @@ -186,6 +188,10 @@ void SaveHierarchyState(SceneHierarchyWindow hierarchyWindow, StageNavigationIte { if (stage == null) return; + + if (stage.prefabStage != null && !stage.prefabStage.isValid) + return; + string key = StageUtility.CreateWindowAndStageIdentifier(hierarchyWindow.windowGUID, stage); var state = m_StateCache.GetState(key); if (state == null) @@ -216,6 +222,11 @@ void OnPrefabStageIconChanged(PrefabStage prefabStage) m_PrefabHeaderContent.image = prefabStage.prefabFileIcon; } + void OnPrefabStageRootTransformChanged(PrefabStage prefabStage) + { + m_SceneHierarchy.customParentForNewGameObjects = prefabStage.prefabContentsRoot.transform; + } + void CachePrefabHeaderText(StageNavigationItem stage) { if (!stage.isPrefabStage) @@ -257,7 +268,7 @@ public void PrefabStageHeaderGUI(Rect rect) } var prefabStage = currentItem.prefabStage; - if (prefabStage == null) + if (prefabStage == null || !prefabStage.isValid) return; // Cache header text @@ -306,7 +317,11 @@ public void PrefabStageHeaderGUI(Rect rect) overlayRect.width = 16; overlayRect.y += (overlayRect.height - 16) / 2; overlayRect.height = 16; - AssetsTreeViewGUI.OnIconOverlayGUI(AssetDatabase.LoadMainAssetAtPath(currentItem.prefabAssetPath).GetInstanceID(), overlayRect, true); + + // The source prefab can have been deleted while open in Prefab Mode so the library object can be null here (case 1086613) + var prefabAsset = AssetDatabase.LoadMainAssetAtPath(currentItem.prefabAssetPath); + if (prefabAsset != null) + AssetsTreeViewGUI.OnIconOverlayGUI(prefabAsset.GetInstanceID(), overlayRect, true); } } } diff --git a/Editor/Mono/SceneManagement/SceneSetup.cs b/Editor/Mono/SceneManagement/SceneSetup.cs index 857c8c5f9e..d3667418a7 100644 --- a/Editor/Mono/SceneManagement/SceneSetup.cs +++ b/Editor/Mono/SceneManagement/SceneSetup.cs @@ -20,6 +20,8 @@ public class SceneSetup private bool m_IsLoaded = false; [SerializeField] private bool m_IsActive = false; + [SerializeField] + private bool m_IsSubScene = false; public string path { @@ -38,5 +40,11 @@ public bool isActive get { return m_IsActive; } set { m_IsActive = value; } } + + public bool isSubScene + { + get { return m_IsSubScene; } + set { m_IsSubScene = value; } + } } } diff --git a/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs b/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs index eb54a144f6..33258aee8b 100644 --- a/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs +++ b/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs @@ -26,6 +26,7 @@ public class PrefabStage public static event Action prefabSaving; public static event Action prefabSaved; internal static event Action prefabIconChanged; + internal static event Action prefabRootTransformChanged; internal static event Action prefabStageSavedAsNewPrefab; GameObject m_PrefabContentsRoot; // Prefab asset being edited @@ -39,6 +40,7 @@ public class PrefabStage Texture2D m_PrefabFileIcon; bool m_TemporarilyDisableAutoSave; float m_LastSavingDuration = 0f; + Transform m_LastRootTransform; const float kDurationBeforeShowingSavingBadge = 1.0f; bool m_AnalyticsDidUserModify; @@ -120,9 +122,9 @@ internal bool temporarilyDisableAutoSave get { return m_TemporarilyDisableAutoSave; } } - internal bool initialized + internal bool isValid { - get { return m_PrefabContentsRoot != null; } + get { return m_PrefabContentsRoot != null && m_PrefabContentsRoot.scene == m_PreviewScene; } } internal PrefabStage() @@ -131,7 +133,13 @@ internal PrefabStage() internal bool LoadStage(string prefabPath) { - if (initialized) + if (!File.Exists(prefabPath)) + { + Debug.LogError("LoadStage with an invalid path: Prefab file not found " + prefabPath); + return false; + } + + if (isValid) Cleanup(); m_PrefabAssetPath = prefabPath; @@ -146,6 +154,7 @@ internal bool LoadStage(string prefabPath) { PrefabStageUtility.HandleReparentingIfNeeded(m_PrefabContentsRoot, isUIPrefab); m_PrefabFileIcon = DeterminePrefabFileIconFromInstanceRootGameObject(); + m_LastRootTransform = m_PrefabContentsRoot.transform; m_InitialSceneDirtyID = m_PreviewScene.dirtyID; UpdateEnvironmentHideFlags(); } @@ -155,7 +164,7 @@ internal bool LoadStage(string prefabPath) Cleanup(); } - return initialized; + return isValid; } // Returns true if opened successfully @@ -163,16 +172,13 @@ internal bool OpenStage(string prefabPath) { if (LoadStage(prefabPath)) { - if (prefabStageOpened != null) - { - prefabStageOpened(this); + prefabStageOpened?.Invoke(this); - // Update environment scene objects after the 'prefabStageOpened' user callback so we can - // ensure: correct hideflags and that our prefab root is not under a prefab instance (which would mark it as an added object). - // Note: The user can have reparented and created new GameObjects in the environment scene during this callback. - EnsureParentOfPrefabRootIsUnpacked(); - UpdateEnvironmentHideFlags(); - } + // Update environment scene objects after the 'prefabStageOpened' user callback so we can ensure: correct hideflags and + // that our prefab root is not under a prefab instance (which would mark it as an added object). + // Note: The user can have reparented and created new GameObjects in the environment scene during this callback. + EnsureParentOfPrefabRootIsUnpacked(); + UpdateEnvironmentHideFlags(); return true; } return false; @@ -180,25 +186,22 @@ internal bool OpenStage(string prefabPath) internal void CloseStage() { - if (!initialized) - return; - - prefabStageClosing?.Invoke(this); + if (isValid) + prefabStageClosing?.Invoke(this); Cleanup(); } void Cleanup() { - if (m_PreviewScene.IsValid()) + if (m_PrefabContentsRoot != null && m_PrefabContentsRoot.scene != m_PreviewScene) { - List roots = new List(); - m_PreviewScene.GetRootGameObjects(roots); - foreach (var go in roots) - UnityEngine.Object.DestroyImmediate(go); - PrefabStageUtility.DestroyPreviewScene(m_PreviewScene); + UnityEngine.Object.DestroyImmediate(m_PrefabContentsRoot); } + if (m_PreviewScene.IsValid()) + PrefabStageUtility.DestroyPreviewScene(m_PreviewScene); // Automatically deletes all GameObjects in scene + m_PrefabContentsRoot = null; m_HideFlagUtility = null; m_PrefabAssetPath = null; @@ -221,9 +224,20 @@ void ReloadStage() Debug.Log("RELOADING done"); } + internal string GetErrorMessage() + { + if (m_PrefabContentsRoot == null) + return L10n.Tr("Error: The Prefab contents root has been deleted.\n\nPrefab: ") + m_PrefabAssetPath; + + if (m_PrefabContentsRoot.scene != m_PreviewScene) + return L10n.Tr("Error: The root GameObject of the opened Prefab has been moved out of the Prefab Stage scene by a script.\n\nPrefab: ") + m_PrefabAssetPath; + + return null; + } + internal void Update() { - if (!initialized) + if (!isValid) return; if (HasSceneBeenModified()) @@ -234,6 +248,15 @@ internal void Update() HandlePrefabChangedOnDisk(); DetectSceneDirtinessChange(); DetectPrefabFileIconChange(); + DetectPrefabRootTransformChange(); + } + + void DetectPrefabRootTransformChange() + { + var currentTransform = m_PrefabContentsRoot.transform; + if (currentTransform != m_LastRootTransform) + prefabRootTransformChanged?.Invoke(this); + m_LastRootTransform = currentTransform; } void DetectPrefabFileIconChange() @@ -305,6 +328,10 @@ void HandlePrefabChangedOnDisk() if (m_PrefabWasChangedOnDisk) { m_PrefabWasChangedOnDisk = false; + + if (!File.Exists(m_PrefabAssetPath)) + return; + if (HasSceneBeenModified()) { var title = L10n.Tr("Prefab Has Been Changed on Disk"); @@ -344,7 +371,7 @@ bool PromptIfMissingBasePrefabForVariant() // Returns true if saved succesfully (internal so we can use it in Tests) internal bool SavePrefab() { - if (!initialized) + if (!isValid) return false; m_AnalyticsDidUserSave = true; @@ -404,7 +431,7 @@ internal bool SavePrefab() internal bool SaveAsNewPrefab(string newPath, bool asCopy) { - if (!initialized) + if (!isValid) return false; if (newPath == m_PrefabAssetPath) @@ -438,12 +465,6 @@ internal bool SaveAsNewPrefab(string newPath, bool asCopy) internal bool SaveAsNewPrefabWithSavePanel() { Assert.IsTrue(m_PrefabContentsRoot != null, "We should have a valid m_PrefabContentsRoot when saving to prefab asset"); - bool editablePrefab = !AnimationMode.InAnimationMode(); - if (!editablePrefab) - { - EditorUtility.DisplayDialog(L10n.Tr("Cannot Save Prefab"), L10n.Tr("Cannot save prefab in Animation Preview Mode"), L10n.Tr("OK")); - return false; - } string directoryOfCurrentPrefab = Path.GetDirectoryName(m_PrefabAssetPath); string nameOfCurrentPrefab = Path.GetFileNameWithoutExtension(m_PrefabAssetPath); diff --git a/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStageUtility.cs b/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStageUtility.cs index c89c10ec28..e3afdfbb2f 100644 --- a/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStageUtility.cs +++ b/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStageUtility.cs @@ -86,13 +86,20 @@ internal static bool SaveCurrentModifiedPrefabStagesIfUserWantsTo() internal static bool IsGameObjectThePrefabRootInAnyPrefabStage(GameObject gameObject) { PrefabStage prefabStage = GetCurrentPrefabStage(); - if (prefabStage != null) + if (prefabStage != null && prefabStage.isValid) { return prefabStage.prefabContentsRoot == gameObject; } return false; } + [UsedByNativeCode] + internal static bool IsGameObjectInInvalidPrefabStage(GameObject gameObject) + { + PrefabStage prefabStage = GetCurrentPrefabStage(); + return (prefabStage != null && prefabStage.scene == gameObject.scene && !prefabStage.isValid); + } + static bool IsDynamicallyCreatedDuringLoad(GameObject gameObject) { return Unsupported.GetFileIDHint(gameObject) == 0; @@ -136,7 +143,7 @@ static GameObject FindFirstGameObjectThatMatchesFileID(Transform searchRoot, UIn return result; } - static GameObject RepairBrokenPrefabIfNeeded(string prefabAssetPath, GameObject[] environmentRoots, GameObject[] rootsAfterLoadingPrefab) + static void RemoveBrokenPrefabRootsIfNeeded(string prefabAssetPath, GameObject[] environmentRoots, GameObject[] rootsAfterLoadingPrefab, UInt64 prefabAssetRootFileID) { var rootsLoadedFromFile = rootsAfterLoadingPrefab.Except(environmentRoots).ToList(); @@ -146,40 +153,61 @@ static GameObject RepairBrokenPrefabIfNeeded(string prefabAssetPath, GameObject[ if (rootsLoadedFromFile.Count >= 2) { - Debug.LogError(string.Format("Prefab Mode: Multiple roots detected. Combined under new generated root. Prefab '{0}'", prefabAssetPath)); - var root = ObjectFactory.CreateGameObject("Replacement Root"); - var rootTransform = root.GetComponent(); - var previewScene = rootsLoadedFromFile[0].scene; - SceneManager.MoveGameObjectToScene(root.gameObject, previewScene); + Debug.LogError(string.Format("Prefab Mode: Broken Prefab with multiple roots detected ('{0}')", prefabAssetPath)); + // First see if we can find a valid root at all. The root could have been reparenting in User land in Awake. + // Keep only the same root as the PrefabImporter if possible. + GameObject root = null; foreach (var go in rootsLoadedFromFile) { - go.GetComponent().parent = rootTransform; + if (GetPrefabOrVariantFileID(go) == prefabAssetRootFileID) + root = go; } - return root; - } - return null; + // If we found the correct root we can delete the other roots + if (root != null) + { + foreach (var go in rootsLoadedFromFile) + { + if (go != root) + UnityEngine.Object.DestroyImmediate(go); + } + } + } } static GameObject FindPrefabRoot(string prefabAssetPath, GameObject[] environmentRoots, GameObject[] rootsAfterLoadingPrefab) { - var assetRoot = AssetDatabase.LoadAssetAtPath(prefabAssetPath); + var assetRoot = AssetDatabase.LoadMainAssetAtPath(prefabAssetPath) as GameObject; if (assetRoot == null) { Debug.LogError(string.Format("Opening Prefab Mode failed: The Prefab at '{0}' is broken.", prefabAssetPath)); return null; } - var repairedRoot = RepairBrokenPrefabIfNeeded(prefabAssetPath, environmentRoots, rootsAfterLoadingPrefab); - if (repairedRoot != null) - return repairedRoot; - - // Normal use case: Find the prefab root or variant root among the roots of the scene (or as a child) + // Find the prefab root or variant root among the roots of the scene (or as a child) UInt64 prefabAssetRootFileID = GetPersistentPrefabOrVariantFileIdentifier(assetRoot); + // Check for broken prefabs with multiple roots + RemoveBrokenPrefabRootsIfNeeded(prefabAssetPath, environmentRoots, rootsAfterLoadingPrefab, prefabAssetRootFileID); + + // Fast path (most common): check all roots first + foreach (var prefabRoot in rootsAfterLoadingPrefab) + { + if (prefabRoot == null) + continue; + + UInt64 id = GetPrefabOrVariantFileID(prefabRoot); + if (id == prefabAssetRootFileID) + return prefabRoot; + } + + // If not found in list of roots then check descendants foreach (var root in rootsAfterLoadingPrefab) { + if (root == null) + continue; + var prefabRoot = FindFirstGameObjectThatMatchesFileID(root.transform, prefabAssetRootFileID); if (prefabRoot != null) return prefabRoot; @@ -283,31 +311,31 @@ static void AppendEnvironmentName(Transform transform, object userData) static Scene CreateDefaultPreviewScene() { Scene previewScene = EditorSceneManager.NewPreviewScene(); - Unsupported.SetOverrideRenderSettings(previewScene); // Setup default render settings for this preview scene + Unsupported.SetOverrideLightingSettings(previewScene); UnityEngine.RenderSettings.defaultReflectionMode = UnityEngine.Rendering.DefaultReflectionMode.Custom; - UnityEngine.RenderSettings.customReflection = GetDefaultReflection(); // ensure chrome materials do not render balck - UnityEngine.RenderSettings.skybox = null; // do not use skybox for the default previewscene, we want the flat Prefab Mode background color to let it stand out from normal scenes - UnityEngine.RenderSettings.ambientMode = AmbientMode.Trilight; // do not use skybox ambient but simple trilight ambient for simplicity - Unsupported.RestoreOverrideRenderSettings(); + UnityEngine.RenderSettings.customReflection = GetDefaultReflection(); // ensure chrome materials do not render black + UnityEngine.RenderSettings.skybox = AssetDatabase.GetBuiltinExtraResource("Default-Skybox.mat") as Material; + UnityEngine.RenderSettings.ambientMode = AmbientMode.Skybox; + UnityEditorInternal.InternalEditorUtility.CalculateAmbientProbeFromSkybox(); + Unsupported.RestoreOverrideLightingSettings(); return previewScene; } - static Cubemap s_DefaultHDRI; + static Cubemap s_DefaultReflection; static Cubemap GetDefaultReflection() { - if (s_DefaultHDRI == null) + const string path = "PrefabMode/DefaultReflectionForPrefabMode.exr"; + if (s_DefaultReflection == null) { - s_DefaultHDRI = EditorGUIUtility.Load("LookDevView/DefaultHDRI.exr") as Cubemap; - if (s_DefaultHDRI == null) - s_DefaultHDRI = EditorGUIUtility.Load("LookDevView/DefaultHDRI.asset") as Cubemap; + s_DefaultReflection = EditorGUIUtility.Load(path) as Cubemap; } - if (s_DefaultHDRI == null) - Debug.LogError("Could not find DefaultHDRI"); - return s_DefaultHDRI; + if (s_DefaultReflection == null) + Debug.LogError("Could not find: " + path); + return s_DefaultReflection; } internal static void DestroyPreviewScene(Scene previewScene) @@ -333,10 +361,16 @@ internal static bool IsUIPrefab(string prefabAssetPath) // We require a RectTransform and a CanvasRenderer to be considered a UI prefab. // E.g 3D TextMeshPro uses RectTransform but a MeshRenderer so should not be considered a UI prefab // This function needs to be peformant since it is called every time a prefab is opened in a prefab stage. - var root = AssetDatabase.LoadAssetAtPath(prefabAssetPath); + var root = AssetDatabase.LoadMainAssetAtPath(prefabAssetPath) as GameObject; if (root == null) return false; - return root.GetComponent() != null && root.GetComponentInChildren(true) != null; + + // In principle, RectTransforms can be used for other things than UI, + // so only treat as UI Prefab if it has both a RectTransform on the root + // AND either a Canvas on the root or a CanvasRenderer somewhere in the hierarchy. + bool rectTransformOnRoot = root.GetComponent() != null; + bool uiSpecificComponentPresent = (root.GetComponent() != null || root.GetComponentInChildren(true) != null); + return rectTransformOnRoot && uiSpecificComponentPresent; } static void HandleUIReparentingIfNeeded(GameObject instanceRoot) @@ -344,7 +378,33 @@ static void HandleUIReparentingIfNeeded(GameObject instanceRoot) // We need a Canvas in order to render UI so ensure the prefab instance is under a Canvas Canvas canvas = instanceRoot.GetComponent(); if (canvas != null) - return; + { + // We have a Canvas. Check if it's suitable to use as root Canvas. + if (canvas.renderMode == RenderMode.WorldSpace) + { + // Do nothing; do not early out and use Canvas as root Canvas. + // We can't know if a World Space Canvas was a root or not in all cases, + // but it's important to not make it a root if its RectTransform + // has stretching (non-identical min and max anchors); otherwise it will + // be previewed stretching to a single point (or less!). + // The downsides of making a World Space Canvas that was a root into a + // nested Canvas in Prefab Mode are less severe (a few settings on the + // Canvas component will be hidden), so we make it always nested + // as the lesser evil. Note that regardless, there is no data loss, + // since World Space canvases don't drive their RectTransform. + } + else + { + // A Screen Space Canvas whose RectTransform values are not all 0 + // can't have been driven when it was created, which means it can't + // have been a root Canvas. In that case it shouldn't be used as root + // Canvas here either, since that would cause its RectTransform values + // to be overridden with driven values, and then serialized as 0. + RectTransform rt = (RectTransform)canvas.transform; + if (rt.sizeDelta == Vector2.zero && rt.anchorMin == Vector2.zero && rt.anchorMax == Vector2.zero && rt.pivot == Vector2.zero) + return; // Use as root. + } + } GameObject canvasGameObject = GetOrCreateCanvasGameObject(instanceRoot); instanceRoot.transform.SetParent(canvasGameObject.transform, false); diff --git a/Editor/Mono/SceneManagement/StageManager/StageNavigationManager.cs b/Editor/Mono/SceneManagement/StageManager/StageNavigationManager.cs index 0d8f811a4d..baa7f435bf 100644 --- a/Editor/Mono/SceneManagement/StageManager/StageNavigationManager.cs +++ b/Editor/Mono/SceneManagement/StageManager/StageNavigationManager.cs @@ -151,9 +151,28 @@ void Update() if (time > m_NextUpdate) { m_NextUpdate = time + 0.2; + ValidateAndUpdatePrefabStages(true); + } + } + + // internal for testing + internal void ValidateAndUpdatePrefabStages(bool showDialogIfInvalid) + { + foreach (var prefabStage in m_PrefabStages) + { + if (!prefabStage.isValid) + { + var errorMsg = prefabStage.GetErrorMessage(); + Assert.IsNotNull(errorMsg); + if (showDialogIfInvalid) + EditorUtility.DisplayDialog("Exiting Prefab Mode", errorMsg, "OK"); + + Assert.IsTrue(m_NavigationHistory.CanGoBackward()); + NavigateBack(Analytics.ChangeType.EnterViaUnknown); + return; + } - foreach (var prefabStage in m_PrefabStages) - prefabStage.Update(); + prefabStage.Update(); } } @@ -206,7 +225,10 @@ internal bool AskUserToSaveModifiedPrefabStageBeforeDestroyingStage(PrefabStage bool CleanupCurrentStageBeforeSwitchingStage() { var prefabStage = currentItem.prefabStage; - if (prefabStage != null) + + // Allow user to save any unsaved changes only after recompiling have finished so any new scripts can be + // saved properly to the Prefab file (but only if the stage is valid) + if (prefabStage != null && prefabStage.isValid) { if (EditorApplication.isCompiling && prefabStage.HasSceneBeenModified()) { @@ -502,7 +524,7 @@ public void PlaceGameObjectInCurrentStage(GameObject go) // the PrefabStage is not fully initialized as it does not have a reference to the prefabContentsRoot yet. In this case // the go is not auto parented and the parenting must be handled by the client. var prefabStage = GetCurrentPrefabStage(); - if (prefabStage != null && prefabStage.initialized && go != null && go.transform.parent == null) + if (prefabStage != null && prefabStage.isValid && go != null && go.transform.parent == null) { go.transform.SetParent(prefabStage.prefabContentsRoot.transform, true); } @@ -590,7 +612,7 @@ public void ChangingStageStarted(StageNavigationItem previousStageItem) m_EventData = new EventData(); m_EventData.existingStage = GetStageType(previousStageItem); m_EventData.existingBreadcrumbCount = StageNavigationManager.instance.stageHistory.Length; - if (previousStageItem.isPrefabStage) + if (previousStageItem.prefabStage != null) { m_EventData.didUserModify = previousStageItem.prefabStage.analyticsDidUserModify; m_EventData.didUserSave = previousStageItem.prefabStage.analyticsDidUserSave; diff --git a/Editor/Mono/SceneManagement/StageManager/StageUtility.cs b/Editor/Mono/SceneManagement/StageManager/StageUtility.cs index a2c518362d..f6b1f3de1f 100644 --- a/Editor/Mono/SceneManagement/StageManager/StageUtility.cs +++ b/Editor/Mono/SceneManagement/StageManager/StageUtility.cs @@ -13,7 +13,7 @@ namespace UnityEditor.SceneManagement { public static partial class StageUtility { - [Shortcut("Stage/Go Back", KeyCode.O)] + [Shortcut("Stage/Go Back")] static void GoBackShortcut() { StageUtility.GoBackToPreviousStage(); diff --git a/Editor/Mono/SceneModeWindows/LightingWindowBakeSettings.cs b/Editor/Mono/SceneModeWindows/LightingWindowBakeSettings.cs index b5fe0296b0..686707c7b1 100644 --- a/Editor/Mono/SceneModeWindows/LightingWindowBakeSettings.cs +++ b/Editor/Mono/SceneModeWindows/LightingWindowBakeSettings.cs @@ -836,15 +836,15 @@ static class Styles public static readonly GUIContent UseRealtimeGI = EditorGUIUtility.TrTextContent("Realtime Global Illumination", "Controls whether Realtime lights in the Scene contribute indirect light. If enabled, Realtime lights contribute both direct and indirect light. If disabled, Realtime lights only contribute direct light. This can be disabled on a per-light basis in the light component Inspector by setting Indirect Multiplier to 0."); public static readonly GUIContent BakedGIDisabledInfo = EditorGUIUtility.TrTextContent("All Baked and Mixed lights in the Scene are currently being overridden to Realtime light modes. Enable Baked Global Illumination to allow the use of Baked and Mixed light modes."); public static readonly GUIContent BakeBackend = EditorGUIUtility.TrTextContent("Lightmapper", "Specifies which baking system will be used to generate baked lightmaps."); - //public static readonly GUIContent PVRSampling = EditorGUIUtility.TrTextContent("Sampling", "How to sample the lightmaps. Auto and adaptive automatically tests for convergence. Auto uses a maximum of 16K samples. Adaptive uses a configurable maximum number of samples. Fixed always uses the set number of samples and does not test for convergence."); + //public static readonly GUIContent PVRSampling = EditorGUIUtility.TrTextContent("Sampling", "How to sample the lightmaps. Auto and adaptive automatically test for convergence. Auto uses a maximum of 16K samples. Adaptive uses a configurable maximum number of samples. Fixed always uses the set number of samples and does not test for convergence."); //public static readonly GUIContent PVRDirectSampleCountAdaptive = EditorGUIUtility.TrTextContent("Max Direct Samples", "Maximum number of samples to use for direct lighting."); public static readonly GUIContent PVRDirectSampleCount = EditorGUIUtility.TrTextContent("Direct Samples", "Controls the number of samples the lightmapper will use for direct lighting calculations. Increasing this value may improve the quality of lightmaps but increases the time required for baking to complete."); //public static readonly GUIContent PVRSampleCountAdaptive = EditorGUIUtility.TrTextContent("Max Indirect Samples", "Maximum number of samples to use for indirect lighting."); public static readonly GUIContent PVRIndirectSampleCount = EditorGUIUtility.TrTextContent("Indirect Samples", "Controls the number of samples the lightmapper will use for indirect lighting calculations. Increasing this value may improve the quality of lightmaps but increases the time required for baking to complete."); public static readonly GUIContent PVRBounces = EditorGUIUtility.TrTextContent("Bounces", "Controls the maximum number of bounces the lightmapper will compute for indirect light."); - public static readonly GUIContent OptixFilteringWarningDirect = EditorGUIUtility.TrTextContent("Direct Denoiser", "Your hardware doesn’t support denoising. To see minimum requirements, read the documentation."); - public static readonly GUIContent OptixFilteringWarningIndirect = EditorGUIUtility.TrTextContent("Indirect Denoiser", "Your hardware doesn’t support denoising. To see minimum requirements, read the documentation."); - public static readonly GUIContent OptixFilteringWarningAO = EditorGUIUtility.TrTextContent("Ambient Occlusion Denoiser", "Your hardware doesn’t support denoising. To see minimum requirements, read the documentation."); + public static readonly GUIContent OptixFilteringWarningDirect = EditorGUIUtility.TrTextContent("Direct Denoiser", "Your hardware doesn't support denoising. To see minimum requirements, read the documentation."); + public static readonly GUIContent OptixFilteringWarningIndirect = EditorGUIUtility.TrTextContent("Indirect Denoiser", "Your hardware doesn't support denoising. To see minimum requirements, read the documentation."); + public static readonly GUIContent OptixFilteringWarningAO = EditorGUIUtility.TrTextContent("Ambient Occlusion Denoiser", "Your hardware doesn't support denoising. To see minimum requirements, read the documentation."); public static readonly GUIContent PVRDenoiserTypeDirect = EditorGUIUtility.TrTextContent("Direct Denoiser", "Specifies the type of denoiser used to reduce noise for direct lights."); public static readonly GUIContent PVRDenoiserTypeIndirect = EditorGUIUtility.TrTextContent("Indirect Denoiser", "Specifies the type of denoiser used to reduce noise for indirect lights."); public static readonly GUIContent PVRDenoiserTypeAO = EditorGUIUtility.TrTextContent("Ambient Occlusion Denoiser", "Specifies the type of denoiser used to reduce noise for ambient occlusion."); @@ -859,7 +859,7 @@ static class Styles public static readonly GUIContent PVRFilteringAtrousPositionSigmaIndirect = EditorGUIUtility.TrTextContent("Sigma", "Controls the threshold of the filter for indirect light stored in the lightmap. A higher value increases the threshold, which reduces noise in the direct layer of the lightmap. Too high of a value can cause a loss of detail in the lightmap."); public static readonly GUIContent PVRFilteringAtrousPositionSigmaAO = EditorGUIUtility.TrTextContent("Sigma", "Controls the threshold of the filter for ambient occlusion stored in the lightmap. A higher value increases the threshold, which reduces noise in the direct layer of the lightmap. Too high of a value can cause a loss of detail in the lightmap."); public static readonly GUIContent PVRCulling = EditorGUIUtility.TrTextContent("Prioritize View", "Specifies whether the lightmapper should prioritize baking texels within the scene view. When disabled, objects outside the scene view will have the same priority as those in the scene view."); - public static readonly GUIContent PVREnvironmentMIS = EditorGUIUtility.TrTextContent("Multiple Importance Sampling", "Specifies whether to use multiple importance sampling for sampling the environment. This will generally lead to faster convergence when generating lightmaps, but can lead to noisier results in certain low frequency environments."); + public static readonly GUIContent PVREnvironmentMIS = EditorGUIUtility.TrTextContent("Multiple Importance Sampling", "Specifies whether to use multiple importance sampling for sampling the environment. This will generally lead to faster convergence when generating lightmaps but can lead to noisier results in certain low frequency environments."); public static readonly GUIContent PVREnvironmentDisableIndirect = EditorGUIUtility.TrTextContent("Disable indirect environment", "Specifies whether the environment should be sampled during GI passes."); public static readonly GUIContent PVREnvironmentDisableDirect = EditorGUIUtility.TrTextContent("Disable direct environment", "Specifies whether the environment should be sampled during direct passes."); public static readonly GUIContent PVREnvironmentSampleCount = EditorGUIUtility.TrTextContent("Environment Samples", "Controls the number of samples the lightmapper will use for environment lighting calculations. Increasing this value may improve the quality of lightmaps but increases the time required for baking to complete."); diff --git a/Editor/Mono/SceneModeWindows/LightmapPreviewWindow.cs b/Editor/Mono/SceneModeWindows/LightmapPreviewWindow.cs index 01b5b90503..5ed3eef210 100644 --- a/Editor/Mono/SceneModeWindows/LightmapPreviewWindow.cs +++ b/Editor/Mono/SceneModeWindows/LightmapPreviewWindow.cs @@ -95,7 +95,7 @@ static class Styles public static readonly GUIContent TextureNotAvailableRealtime = EditorGUIUtility.TrTextContent("The texture is not available at the moment."); public static readonly GUIContent TextureNotAvailableBaked = EditorGUIUtility.TrTextContent("The texture is not available at the moment.\nPlease try to rebake the current scene or turn on Auto, and make sure that this object is set to Lightmap Static if it's meant to be baked."); public static readonly GUIContent TextureNotAvailableBakedShadowmask = EditorGUIUtility.TrTextContent("The texture is not available at the moment.\nPlease make sure that Mixed Lights affect this GameObject and that it is set to Lightmap Static."); - public static readonly GUIContent TextureNotAvailableBakedAlbedoEmissive = EditorGUIUtility.TrTextContent("The texture is not an index based texture and is not available when using Progressive.\nPlease go to the instance you wish to debug, and select the lightmap on the Mesh Renderer."); + public static readonly GUIContent TextureNotAvailableBakedAlbedoEmissive = EditorGUIUtility.TrTextContent("The texture is not an index-based texture and is not available when using Progressive.\nPlease go to the instance you wish to debug, and select the lightmap on the Mesh Renderer."); public static readonly GUIContent TextureLoading = EditorGUIUtility.TrTextContent("Loading..."); public static readonly GUIContent UVOverlayIcon = EditorGUIUtility.TrIconContent("ToggleUVOverlay", "Toggles the UV Overlay for all the objects in the lightmap. The currently selected object will be highlighted. "); public static readonly GUIContent ExposureIcon = EditorGUIUtility.TrIconContent("SceneViewLighting", "Controls the number of stops to over or under expose the lightmap."); diff --git a/Editor/Mono/SceneModeWindows/NavigationWindow.cs b/Editor/Mono/SceneModeWindows/NavigationWindow.cs index 0478f66928..183bd82917 100644 --- a/Editor/Mono/SceneModeWindows/NavigationWindow.cs +++ b/Editor/Mono/SceneModeWindows/NavigationWindow.cs @@ -588,7 +588,7 @@ static void DisplayAgentControls(Object target, SceneView sceneView) } var showAgentNeighbours = NavMeshVisualizationSettings.showAgentNeighbours; - if (showAgentNeighbours != EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Show Neighbours", "Show the agent neighbours cosidered during simulation."), showAgentNeighbours)) + if (showAgentNeighbours != EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Show Neighbours", "Show the agent neighbours considered during simulation."), showAgentNeighbours)) { NavMeshVisualizationSettings.showAgentNeighbours = !showAgentNeighbours; bRepaint = true; diff --git a/Editor/Mono/SceneModeWindows/OcclusionCullingWindow.cs b/Editor/Mono/SceneModeWindows/OcclusionCullingWindow.cs index 1726a789cf..51ed489cc1 100644 --- a/Editor/Mono/SceneModeWindows/OcclusionCullingWindow.cs +++ b/Editor/Mono/SceneModeWindows/OcclusionCullingWindow.cs @@ -42,7 +42,7 @@ class Styles public GUIContent seeVisualizationInScene = EditorGUIUtility.TrTextContent("See the occlusion culling visualization in the Scene View based on the selected Camera."); public GUIContent noOcclusionData = EditorGUIUtility.TrTextContent("No occlusion data has been baked."); public GUIContent smallestHole = EditorGUIUtility.TrTextContent("Smallest Hole", "Smallest hole in the geometry through which the camera is supposed to see. The single float value of the parameter represents the diameter of the imaginary smallest hole, i.e. the maximum extent of a 3D object that fits through the hole."); - public GUIContent backfaceThreshold = EditorGUIUtility.TrTextContent("Backface Threshold", "The backface threshold is a size optimization that reduces unnecessary details by testing backfaces. A value of 100 is robust and never removes any backfaces. A value of 5 aggressively reduces the data based on locations with visible backfaces. The idea is that typically valid camera positions cannot see many backfaces. For example geometry under terrain and inside solid objects can be removed."); + public GUIContent backfaceThreshold = EditorGUIUtility.TrTextContent("Backface Threshold", "The backface threshold is a size optimization that reduces unnecessary details by testing backfaces. A value of 100 is robust and never removes any backfaces. A value of 5 aggressively reduces the data based on locations with visible backfaces. The idea is that typically valid camera positions cannot see many backfaces. For example, geometry under terrain and inside solid objects can be removed."); public GUIContent farClipPlane = EditorGUIUtility.TrTextContent("Far Clip Plane", "Far Clip Plane used during baking. This should match the largest far clip plane used by any camera in the scene. A value of 0.0 sets the far plane to Infinity."); public GUIContent smallestOccluder = EditorGUIUtility.TrTextContent("Smallest Occluder", "The size of the smallest object that will be used to hide other objects when doing occlusion culling. For example, if a value of 4 is chosen, then all the objects that are higher or wider than 4 meters will block visibility and the objects that are smaller than that will not. This value is a tradeoff between occlusion accuracy and storage size."); public GUIContent defaultParameterText = EditorGUIUtility.TrTextContent("Default Parameters", "The default parameters guarantee that any given scene computes fast and the occlusion culling results are good. As the parameters are always scene specific, better results will be achieved when fine tuning the parameters on a scene to scene basis. All the parameters are dependent on the unit scale of the scene and it is imperative that the unit scale parameter is set correctly before setting the default values."); diff --git a/Editor/Mono/SceneModeWindows/PhysicsDebugWindow.cs b/Editor/Mono/SceneModeWindows/PhysicsDebugWindow.cs index ba6b6eb4f7..59ae581bd0 100644 --- a/Editor/Mono/SceneModeWindows/PhysicsDebugWindow.cs +++ b/Editor/Mono/SceneModeWindows/PhysicsDebugWindow.cs @@ -24,6 +24,7 @@ public class PhysicsDebugWindow : EditorWindow bool m_PickAdded = false; bool m_MouseLeaveListenerAdded = false; + bool m_SceneViewListenerAdded = false; private static class Style { @@ -49,7 +50,7 @@ private static class Style public static readonly GUIContent showLayers = EditorGUIUtility.TrTextContent("Show Layers", "Show selected layers"); public static readonly GUIContent showPhysicsScenes = EditorGUIUtility.TrTextContent("Show Physics Scene", "Show selected physics scenes"); public static readonly GUIContent showStaticCollider = EditorGUIUtility.TrTextContent("Show Static Colliders", "Show collision geometry from Colliders that do not have a Rigidbody"); - public static readonly GUIContent showTriggers = EditorGUIUtility.TrTextContent("Show Triggers", "Show collision geometry from Colliders that have 'isTrigge' enabled"); + public static readonly GUIContent showTriggers = EditorGUIUtility.TrTextContent("Show Triggers", "Show collision geometry from Colliders that have 'isTrigger' enabled"); public static readonly GUIContent showRigibodies = EditorGUIUtility.TrTextContent("Show Rigidbodies", "Show collision geometry from Rigidbodies"); public static readonly GUIContent showKinematicBodies = EditorGUIUtility.TrTextContent("Show Kinematic Bodies", "Show collision geometry from Kinematic Rigidbodies"); public static readonly GUIContent showSleepingBodies = EditorGUIUtility.TrTextContent("Show Sleeping Bodies", "Show collision geometry from Sleeping Rigidbodies"); @@ -106,16 +107,27 @@ void RemovePicker() void OnBecameVisible() { - PhysicsVisualizationSettings.InitDebugDraw(); - SceneView.duringSceneGui += OnSceneViewGUI; + if (!m_SceneViewListenerAdded) + { + PhysicsVisualizationSettings.InitDebugDraw(); + SceneView.duringSceneGui += OnSceneViewGUI; + m_SceneViewListenerAdded = true; + } + RepaintSceneAndGameViews(); } void OnBecameInvisible() { RemovePicker(); - SceneView.duringSceneGui -= OnSceneViewGUI; - PhysicsVisualizationSettings.DeinitDebugDraw(); + + if (m_SceneViewListenerAdded) + { + SceneView.duringSceneGui -= OnSceneViewGUI; + PhysicsVisualizationSettings.DeinitDebugDraw(); + m_SceneViewListenerAdded = false; + } + RepaintSceneAndGameViews(); } @@ -171,7 +183,7 @@ void OnGUI() { EditorGUILayout.Space(); m_ShowInfoFoldout.value = EditorGUILayout.Foldout(m_ShowInfoFoldout.value, Style.selectedObjectInfo); - if (m_ShowColliderTypeFoldout.value) + if (m_ShowInfoFoldout.value) { EditorGUI.indentLevel++; EditorGUILayout.Space(); diff --git a/Editor/Mono/SceneView/SceneView.cs b/Editor/Mono/SceneView/SceneView.cs index 494a6d5dab..ea42aeed73 100644 --- a/Editor/Mono/SceneView/SceneView.cs +++ b/Editor/Mono/SceneView/SceneView.cs @@ -106,24 +106,57 @@ public static SceneView lastActiveSceneView [SerializeField] bool m_ShowContextualTools; - bool displayToolModes + internal bool displayToolModes + { + get { return m_ShowContextualTools; } + set { m_ShowContextualTools = value; } + } + + static void OnSelectedObjectWasDestroyed(int unused) + { + s_ActiveEditorsDirty = true; + } + + static void OnEditorTrackerRebuilt() + { + s_ActiveEditorsDirty = true; + } + + static List s_ActiveEditors = new List(); + + static bool s_ActiveEditorsDirty; + + internal static IEnumerable activeEditors { get { - return m_ShowContextualTools; + CollectActiveEditors(); + return s_ActiveEditors; } - set - { - if (m_ShowContextualTools == value) - return; + } + + static void CollectActiveEditors() + { + if (!s_ActiveEditorsDirty) + return; + + s_ActiveEditorsDirty = false; - if (m_ShowContextualTools) - duringSceneGui -= EditorToolGUI.DrawSceneViewTools; + s_ActiveEditors.Clear(); - m_ShowContextualTools = value; + if (s_SharedTracker == null) + s_SharedTracker = ActiveEditorTracker.sharedTracker; - if (m_ShowContextualTools) - duringSceneGui += EditorToolGUI.DrawSceneViewTools; + foreach (var editor in s_SharedTracker.activeEditors) + s_ActiveEditors.Add(editor); + + foreach (var inspector in InspectorWindow.GetInspectors()) + { + if (inspector.isLocked) + { + foreach (var editor in inspector.tracker.activeEditors) + s_ActiveEditors.Add(editor); + } } } @@ -188,7 +221,7 @@ protected internal Transform customParentForDraggedObjects const float k_MaxCameraFarClip = 1.844674E+19f; [NonSerialized] - ActiveEditorTracker m_Tracker; + static ActiveEditorTracker s_SharedTracker; [SerializeField] bool m_SceneIsLit = true; @@ -430,10 +463,12 @@ public SceneViewState sceneViewState Camera m_Camera; [Serializable] - public class SceneViewCameraSettings + public class CameraSettings { const float kAbsoluteSpeedMin = .01f; const float kAbsoluteSpeedMax = 99f; + const float kAbsoluteEasingDurationMin = .1f; + const float kAbsoluteEasingDurationMax = 2f; [SerializeField] float m_Speed; @@ -443,6 +478,10 @@ public class SceneViewCameraSettings float m_SpeedMin; [SerializeField] float m_SpeedMax; + [SerializeField] + bool m_EasingEnabled; + [SerializeField] + float m_EasingDuration; [SerializeField] float m_FieldOfView; @@ -455,12 +494,14 @@ public class SceneViewCameraSettings [SerializeField] bool m_OcclusionCulling; - public SceneViewCameraSettings() + public CameraSettings() { m_Speed = 1f; m_SpeedNormalized = .5f; m_SpeedMin = .01f; m_SpeedMax = 2f; + m_EasingEnabled = true; + m_EasingDuration = .4f; fieldOfView = kPerspectiveFov; m_DynamicClip = true; m_OcclusionCulling = false; @@ -522,6 +563,27 @@ public float speedMax } } + public bool easingEnabled + { + get { return m_EasingEnabled; } + set { m_EasingEnabled = value; } + } + + // How many seconds should the camera take to go from stand-still to initial full speed. When setting an animated value + // speed, use `1 / duration`. + public float easingDuration + { + get + { + return m_EasingDuration; + } + set + { + // Clamp and round to 1 decimal point + m_EasingDuration = (float)(Math.Round((double)Mathf.Clamp(value, kAbsoluteEasingDurationMin, kAbsoluteEasingDurationMax), 1)); + } + } + internal void SetSpeedMinMax(float[] floatValues) { // Round to nearest decimal: 2 decimal points when between [0.01, 0.1]; 1 decimal point when between [0.1, 10]; integral between [10, 99] @@ -577,17 +639,17 @@ public bool occlusionCulling } [SerializeField] - private SceneViewCameraSettings m_SceneViewCameraSettings; + private CameraSettings m_CameraSettings; - public SceneViewCameraSettings sceneViewCameraSettings + public CameraSettings cameraSettings { - get { return m_SceneViewCameraSettings; } - set { m_SceneViewCameraSettings = value; } + get { return m_CameraSettings; } + set { m_CameraSettings = value; } } - public void ResetSceneViewCameraSettings() + public void ResetCameraSettings() { - m_SceneViewCameraSettings = new SceneViewCameraSettings(); + m_CameraSettings = new CameraSettings(); } [SerializeField] @@ -687,7 +749,7 @@ internal static class Styles public static GUIContent isolationModeOverlayContent = EditorGUIUtility.TrTextContent("Isolation View", ""); public static GUIContent isolationModeExitButton = EditorGUIUtility.TrTextContent("Exit", "Exit isolation mode"); public static GUIContent renderDocContent; - public static GUIContent sceneVisToolbarButtonContent = EditorGUIUtility.TrIconContent("SceneViewVisibility", "Number of hidden objects, click to toggle scene visibility"); + public static GUIContent sceneVisToolbarButtonContent = EditorGUIUtility.TrIconContent("scenevis_hidden", "Number of hidden objects, click to toggle scene visibility"); public static GUIStyle gizmoButtonStyle; public static GUIStyle fxDropDownStyle; public static GUIContent sceneViewCameraContent = EditorGUIUtility.TrIconContent("SceneViewCamera", "Settings for the Scene view camera."); @@ -773,13 +835,6 @@ public static bool FrameLastActiveSceneViewWithLock() return lastActiveSceneView.SendEvent(EditorGUIUtility.CommandEvent(EventCommandNames.FrameSelectedWithLock)); } - internal Editor[] GetActiveEditors() - { - if (m_Tracker == null) - m_Tracker = ActiveEditorTracker.sharedTracker; - return m_Tracker.activeEditors; - } - private static List GetAllSceneCamerasAsList() { s_AllSceneCameraList.Clear(); @@ -876,6 +931,8 @@ public override void OnEnable() EditorApplication.modifierKeysChanged += RepaintAll; // Because we show handles on shift SceneVisibilityManager.hiddenContentChanged += HiddenContentChanged; SceneVisibilityManager.currentStageIsolated += CurrentStageIsolated; + ActiveEditorTracker.editorTrackerRebuilt += OnEditorTrackerRebuilt; + Selection.selectedObjectWasDestroyed += OnSelectedObjectWasDestroyed; m_DraggingLockedState = DraggingLockedState.NotDragging; @@ -887,9 +944,6 @@ public override void OnEnable() if (m_CameraMode.drawMode == DrawCameraMode.UserDefined && !s_UserDefinedModes.Contains(m_CameraMode)) AddCameraMode(m_CameraMode.name, m_CameraMode.section); - if (m_ShowContextualTools) - duringSceneGui += EditorToolGUI.DrawSceneViewTools; - base.OnEnable(); if (SupportsStageHandling()) @@ -897,6 +951,8 @@ public override void OnEnable() m_StageHandling = new SceneViewStageHandling(this); m_StageHandling.OnEnable(); } + + s_ActiveEditorsDirty = true; } protected virtual bool SupportsStageHandling() @@ -938,8 +994,8 @@ internal void Awake() if (sceneViewState == null) m_SceneViewState = new SceneViewState(); - if (m_SceneViewCameraSettings == null) - m_SceneViewCameraSettings = new SceneViewCameraSettings(); + if (m_CameraSettings == null) + m_CameraSettings = new CameraSettings(); if (m_2DMode || EditorSettings.defaultBehaviorMode == EditorBehaviorMode.Mode2D) { @@ -979,6 +1035,8 @@ public override void OnDisable() EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; SceneVisibilityManager.hiddenContentChanged -= HiddenContentChanged; SceneVisibilityManager.currentStageIsolated -= CurrentStageIsolated; + ActiveEditorTracker.editorTrackerRebuilt -= OnEditorTrackerRebuilt; + Selection.selectedObjectWasDestroyed -= OnSelectedObjectWasDestroyed; if (m_Camera) DestroyImmediate(m_Camera.gameObject, true); @@ -1644,6 +1702,9 @@ private void DoDrawCamera(Rect windowSpaceCameraRect, Rect groupSpaceCameraRect, if (!m_Camera.gameObject.activeInHierarchy) return; + bool oldAsync = ShaderUtil.allowAsyncCompilation; + ShaderUtil.allowAsyncCompilation = EditorSettings.asyncShaderCompilation; + DrawGridParameters gridParam = grid.PrepareGridRender(camera, pivot, m_Rotation.target, size, m_Ortho.target, drawGlobalGrid); Event evt = Event.current; @@ -1675,6 +1736,7 @@ private void DoDrawCamera(Rect windowSpaceCameraRect, Rect groupSpaceCameraRect, Handles.DrawCameraStep1(groupSpaceCameraRect, m_Camera, m_CameraMode.drawMode, gridParam, drawGizmos); DrawRenderModeOverlay(groupSpaceCameraRect); } + ShaderUtil.allowAsyncCompilation = oldAsync; } void RenderFilteredScene(Rect groupSpaceCameraRect) @@ -1767,7 +1829,7 @@ void DoClearCamera(Rect cameraRect) // Clear (color/skybox) // We do funky FOV interpolation when switching between ortho and perspective. However, // for the skybox we always want to use the same FOV. - float skyboxFOV = GetVerticalFOV(m_SceneViewCameraSettings.fieldOfView); + float skyboxFOV = GetVerticalFOV(m_CameraSettings.fieldOfView); float realFOV = m_Camera.fieldOfView; var clearFlags = m_Camera.clearFlags; @@ -2163,7 +2225,10 @@ void DrawValidateAlbedoSwatches(SceneView sceneView) void RepaintGizmosThatAreRenderedOnTopOfSceneView() { - svRot.OnGUI(this); + if (Event.current.type == EventType.Repaint) + { + svRot.OnGUI(this); + } } void InputForGizmosThatAreRenderedOnTopOfSceneView() @@ -2179,9 +2244,11 @@ protected virtual void OnGUI() s_CurrentDrawingSceneView = this; Event evt = Event.current; + if (evt.type == EventType.Repaint) { s_MouseRects.Clear(); + Tools.InvalidateHandlePosition(); // Some cases that should invalidate the cached position are not handled correctly yet so we refresh it once per frame Profiler.BeginSample("SceneView.Repaint"); } @@ -2214,7 +2281,7 @@ protected virtual void OnGUI() // Use custom scene RenderSettings (if currently showing a custom scene) bool restoreOverrideRenderSettings = false; if (m_CustomScene.IsValid()) - restoreOverrideRenderSettings = Unsupported.SetOverrideRenderSettings(m_CustomScene); + restoreOverrideRenderSettings = Unsupported.SetOverrideLightingSettings(m_CustomScene); SetupCustomSceneLighting(); @@ -2250,12 +2317,12 @@ protected virtual void OnGUI() CleanupCustomSceneLighting(); if (restoreOverrideRenderSettings) - Unsupported.RestoreOverrideRenderSettings(); + Unsupported.RestoreOverrideLightingSettings(); //Ensure that the target texture is clamped [0-1] //This is needed because otherwise gizmo rendering gets all //messed up (think HDR target with value of 50 + alpha blend gizmo... gonna be white!) - if (!UseSceneFiltering() && evt.type == EventType.Repaint && RenderTextureEditor.IsHDRFormat(m_SceneTargetTexture.format)) + if (!UseSceneFiltering() && evt.type == EventType.Repaint && GraphicsFormatUtility.IsIEEE754Format(m_SceneTargetTexture.graphicsFormat)) { var currentDepthBuffer = Graphics.activeDepthBuffer; var rtDesc = m_SceneTargetTexture.descriptor; @@ -2280,7 +2347,6 @@ protected virtual void OnGUI() m_Camera.renderingPath = oldRenderingPath; - if (!UseSceneFiltering()) { if (evt.type == EventType.Repaint) @@ -2309,6 +2375,9 @@ protected virtual void OnGUI() GL.Clear(false, true, new Color(0, 0, 0, 0)); // Only clear color. Keep depth intact. } + if (displayToolModes) + EditorToolGUI.DrawSceneViewTools(this); + // Calling OnSceneGUI before DefaultHandles, so users can use events before the Default Handles HandleSelectionAndOnSceneGUI(); @@ -2478,14 +2547,14 @@ public float size internal float targetSize { get { return m_Size.target; } - set { m_Size.SetTarget(ValidateSceneSize(value), 1f / SceneViewMotion.movementEasingDuration); } + set { m_Size.target = ValidateSceneSize(value); } } float perspectiveFov { get { - return m_SceneViewCameraSettings.fieldOfView; + return m_CameraSettings.fieldOfView; } } @@ -2656,7 +2725,7 @@ void SetupCamera() m_Camera.orthographicSize = GetVerticalOrthoSize(); } - if (m_SceneViewCameraSettings.dynamicClip) + if (m_CameraSettings.dynamicClip) { float farClip = Mathf.Min(Mathf.Max(1000f, 2000f * size), k_MaxCameraFarClip); m_Camera.nearClipPlane = farClip * 0.000005f; @@ -2664,11 +2733,11 @@ void SetupCamera() } else { - m_Camera.nearClipPlane = m_SceneViewCameraSettings.nearClip; - m_Camera.farClipPlane = m_SceneViewCameraSettings.farClip; + m_Camera.nearClipPlane = m_CameraSettings.nearClip; + m_Camera.farClipPlane = m_CameraSettings.farClip; } - m_Camera.useOcclusionCulling = m_SceneViewCameraSettings.occlusionCulling; + m_Camera.useOcclusionCulling = m_CameraSettings.occlusionCulling; m_Camera.transform.position = m_Position.value + m_Camera.transform.rotation * new Vector3(0, 0, -cameraDistance); @@ -3099,10 +3168,10 @@ public virtual bool FrameSelected(bool lockView, bool instant) viewIsLockedToObject = lockView; FixNegativeSize(); - Bounds bounds = InternalEditorUtility.CalculateSelectionBounds(false, Tools.pivotMode == PivotMode.Pivot); + Bounds bounds = InternalEditorUtility.CalculateSelectionBounds(false, Tools.pivotMode == PivotMode.Pivot, true); // Check active editor for OnGetFrameBounds - foreach (Editor editor in GetActiveEditors()) + foreach (Editor editor in activeEditors) { MethodInfo hasBoundsMethod = editor.GetType().GetMethod("HasFrameBounds", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy); @@ -3183,7 +3252,7 @@ void CreateSceneCameraAndLights() void CallOnSceneGUI() { - foreach (Editor editor in GetActiveEditors()) + foreach (Editor editor in activeEditors) { if (!EditorGUIUtility.IsGizmosAllowedForObject(editor.target)) continue; @@ -3239,7 +3308,7 @@ void ResetOnSceneGUIState() void CallOnPreSceneGUI() { - foreach (Editor editor in GetActiveEditors()) + foreach (Editor editor in activeEditors) { // reset the handles matrix, OnPreSceneGUI calls may change it. Handles.ClearHandles(); diff --git a/Editor/Mono/SceneView/SceneViewMotion.cs b/Editor/Mono/SceneView/SceneViewMotion.cs index fa96dc63b5..e884b6a403 100644 --- a/Editor/Mono/SceneView/SceneViewMotion.cs +++ b/Editor/Mono/SceneView/SceneViewMotion.cs @@ -17,34 +17,13 @@ internal static class SceneViewMotion static SceneView s_SceneView; static Vector3 s_Motion; static float k_FlySpeed = 9f; - const float k_DefaultFpsEaseDuration = .4f; + static float s_FlySpeedTarget = 0f; + const float k_FlySpeedAcceleration = 1.8f; static float s_StartZoom = 0f, s_ZoomSpeed = 0f; static float s_TotalMotion = 0f; static float s_FPSScrollWheelMultiplier = .01f; static bool s_Moving; - static AnimVector3 s_FlySpeed = new AnimVector3(Vector3.zero) { speed = 1f / k_DefaultFpsEaseDuration }; - - static SavedFloat s_EasingDuration = new SavedFloat("SceneViewMotion.easeDuration", k_DefaultFpsEaseDuration); - static SavedBool s_MovementEasing = new SavedBool("SceneViewMotion.movementEasing", true); - - // how many seconds should the camera take to go from stand-still to full speed. when setting an animated value - // speed, use `1 / duration`. - internal static float movementEasingDuration - { - get { return s_EasingDuration.value; } - set - { - // Clamp and round to 1 decimal point - s_EasingDuration.value = (float)(Math.Round((double)Mathf.Clamp(value, .1f, 3f), 1)); - s_FlySpeed.speed = 1f / s_EasingDuration.value; - } - } - - internal static bool movementEasingEnabled - { - get { return s_MovementEasing.value; } - set { s_MovementEasing.value = value; } - } + static AnimVector3 s_FlySpeed = new AnimVector3(Vector3.zero); enum MotionState { @@ -64,7 +43,6 @@ static void Init() if (s_Initialized) return; s_Initialized = true; - movementEasingDuration = movementEasingDuration; } public static void DoViewTool(SceneView view) @@ -91,6 +69,9 @@ public static void DoViewTool(SceneView view) if (inputSamplingScope.currentlyMoving) view.viewIsLockedToObject = false; + if (inputSamplingScope.inputVectorChanged) + s_FlySpeedTarget = 0f; + s_Motion = inputSamplingScope.currentInputVector; } @@ -125,25 +106,28 @@ public static void DoViewTool(SceneView view) static Vector3 GetMovementDirection() { s_Moving = s_Motion.sqrMagnitude > 0f; - - var speedModifier = s_SceneView.sceneViewCameraSettings.speed; + var deltaTime = CameraFlyModeContext.deltaTime; + var speedModifier = s_SceneView.cameraSettings.speed; if (Event.current.shift) speedModifier *= 5f; - if (movementEasingEnabled) + if (s_Moving) + s_FlySpeedTarget = s_FlySpeedTarget < Mathf.Epsilon ? k_FlySpeed : s_FlySpeedTarget * Mathf.Pow(k_FlySpeedAcceleration, deltaTime); + else + s_FlySpeedTarget = 0f; + + if (s_SceneView.cameraSettings.easingEnabled) { - s_FlySpeed.target = s_Moving ? s_Motion.normalized * k_FlySpeed * speedModifier : Vector3.zero; + s_FlySpeed.speed = 1f / s_SceneView.cameraSettings.easingDuration; + s_FlySpeed.target = s_Motion.normalized * s_FlySpeedTarget * speedModifier; } else { - if (!s_Moving) - return s_FlySpeed.value = Vector3.zero; - - s_FlySpeed.value = s_Motion.normalized * speedModifier * k_FlySpeed; + s_FlySpeed.value = s_Motion.normalized * s_FlySpeedTarget * speedModifier; } - return s_FlySpeed.value * CameraFlyModeContext.deltaTime; + return s_FlySpeed.value * deltaTime; } private static void HandleMouseDown(SceneView view, int id, int button) @@ -396,9 +380,9 @@ private static void HandleScrollWheel(SceneView view, bool zoomTowardsCenter) if (Tools.s_LockedViewTool == ViewTool.FPS && s_Moving) { float scrollWheelDelta = Event.current.delta.y * s_FPSScrollWheelMultiplier; - view.sceneViewCameraSettings.speedNormalized -= scrollWheelDelta; + view.cameraSettings.speedNormalized -= scrollWheelDelta; - float cameraSpeed = view.sceneViewCameraSettings.speed; + float cameraSpeed = view.cameraSettings.speed; string cameraSpeedDisplayValue = cameraSpeed.ToString(cameraSpeed < 0.1f ? "F2" : cameraSpeed < 10f ? "F1" : "F0"); if (cameraSpeed < 0.1f) cameraSpeedDisplayValue = cameraSpeedDisplayValue.TrimStart(new Char[] {'0'}); @@ -420,13 +404,11 @@ private static void HandleScrollWheel(SceneView view, bool zoomTowardsCenter) else if (relativeDelta < 0 && relativeDelta > -deltaCutoff) relativeDelta = -deltaCutoff; - targetSize = movementEasingEnabled - ? view.targetSize + relativeDelta - : view.size + relativeDelta; + targetSize = view.size + relativeDelta; } else { - targetSize = Mathf.Abs(movementEasingEnabled ? view.targetSize : view.size) * (zoomDelta * .015f + 1.0f); + targetSize = Mathf.Abs(view.size) * (zoomDelta * .015f + 1.0f); } var initialDistance = view.cameraDistance; @@ -434,11 +416,7 @@ private static void HandleScrollWheel(SceneView view, bool zoomTowardsCenter) if (!(float.IsNaN(targetSize) || float.IsInfinity(targetSize))) { targetSize = Mathf.Min(SceneView.k_MaxSceneViewSize, targetSize); - - if (movementEasingEnabled) - view.targetSize = targetSize; - else - view.size = targetSize; + view.size = targetSize; } if (!zoomTowardsCenter && Mathf.Abs(view.cameraDistance) < 1.0e7f) @@ -495,6 +473,8 @@ internal class SceneViewRotation private int[] m_ViewDirectionControlIDs; private int m_CenterButtonControlID; + private int m_RotationLockControlID; + private int m_PerspectiveIsoControlID; int currentDir = 7; @@ -572,6 +552,8 @@ public void Register(SceneView view) } m_CenterButtonControlID = GUIUtility.GetPermanentControlID(); + m_RotationLockControlID = GUIUtility.GetPermanentControlID(); + m_PerspectiveIsoControlID = GUIUtility.GetPermanentControlID(); } } @@ -749,7 +731,7 @@ void DrawRotationLock(SceneView view) var prevColor = GUI.color; GUI.color = c; var content = (view.isRotationLocked) ? styles.lockedRotationIcon : styles.unlockedRotationIcon; - if (GUI.Button(lockRect, content, styles.lockStyle) && !view.in2DMode) + if (GUI.Button(lockRect, m_RotationLockControlID, content, styles.lockStyle) && !view.in2DMode) { view.isRotationLocked = !view.isRotationLocked; m_RotationLocked.target = !view.isRotationLocked; @@ -766,7 +748,7 @@ void DrawLabels(SceneView view) // Button (overlayed over the labels) to toggle between iso and perspective if (!view.in2DMode && !view.isRotationLocked) { - if (GUI.Button(labelRect, string.Empty, styles.viewLabelStyleLeftAligned)) + if (GUI.Button(labelRect, m_PerspectiveIsoControlID, GUIContent.none, styles.viewLabelStyleLeftAligned)) { if (Event.current.button == 1) DisplayContextMenu(labelRect, view); diff --git a/Editor/Mono/SceneView/SceneViewOverlay.cs b/Editor/Mono/SceneView/SceneViewOverlay.cs index 2ddf43acfb..305bec7ece 100644 --- a/Editor/Mono/SceneView/SceneViewOverlay.cs +++ b/Editor/Mono/SceneView/SceneViewOverlay.cs @@ -42,6 +42,7 @@ private class OverlayWindow : IComparable public int m_PrimaryOrder; // lower order is below high order public int m_SecondaryOrder; // used for primary order that are equal (should be unique) public Object m_Target; + public EditorWindow m_EditorWindow; public int CompareTo(OverlayWindow other) { @@ -67,9 +68,6 @@ public SceneViewOverlay(SceneView sceneView) public void Begin() { - if (!m_SceneView.m_ShowSceneViewWindows) - return; - if (Event.current.type == EventType.Layout) m_Windows.Clear(); @@ -83,9 +81,6 @@ static class Styles public void End() { - if (!m_SceneView.m_ShowSceneViewWindows) - return; - m_Windows.Sort(); if (m_Windows.Count > 0) @@ -108,6 +103,9 @@ private void WindowTrampoline(int id) float paddingOffset = -k_WindowPadding; foreach (OverlayWindow win in m_Windows) { + if (!m_SceneView.m_ShowSceneViewWindows && win.m_EditorWindow != m_SceneView) + continue; + GUILayout.Space(k_WindowPadding + paddingOffset); paddingOffset = 0f; EditorGUIUtility.ResetGUIState(); @@ -162,7 +160,8 @@ public static void Window(GUIContent title, WindowFunction sceneViewFunc, int or Window(title, sceneViewFunc, order, null, option); } - public static void Window(GUIContent title, WindowFunction sceneViewFunc, int order, Object target, WindowDisplayOption option) + // pass window parameter to render in sceneviews that are not the active view. + public static void Window(GUIContent title, WindowFunction sceneViewFunc, int order, Object target, WindowDisplayOption option, EditorWindow window = null) { if (Event.current.type != EventType.Layout) return; @@ -182,6 +181,7 @@ public static void Window(GUIContent title, WindowFunction sceneViewFunc, int or newWindow.m_PrimaryOrder = order; newWindow.m_SecondaryOrder = m_Windows.Count; // just use a value that is unique across overlays newWindow.m_Target = target; + newWindow.m_EditorWindow = window; m_Windows.Add(newWindow); } diff --git a/Editor/Mono/SceneView/SceneViewStageHandling.cs b/Editor/Mono/SceneView/SceneViewStageHandling.cs index e73661f5a2..5299d99614 100644 --- a/Editor/Mono/SceneView/SceneViewStageHandling.cs +++ b/Editor/Mono/SceneView/SceneViewStageHandling.cs @@ -160,6 +160,10 @@ void HandleFirstTimePrefabStageIsOpened(StageNavigationItem stage) if (!HasAnyActiveLights(stage.prefabStage.scene)) m_SceneView.sceneLighting = false; + // Default to not showing skybox if user did not specify a custom environment scene. + if (string.IsNullOrEmpty(stage.prefabStage.scene.path)) + m_SceneView.sceneViewState.showSkybox = false; + // For UI to frame properly we need to delay one full Update for the layouting to have been processed EditorApplication.update += DelayedFraming; } diff --git a/Editor/Mono/SceneView/SceneVisibilityState.bindings.cs b/Editor/Mono/SceneView/SceneVisibilityState.bindings.cs index f930b57605..fede197336 100644 --- a/Editor/Mono/SceneView/SceneVisibilityState.bindings.cs +++ b/Editor/Mono/SceneView/SceneVisibilityState.bindings.cs @@ -2,10 +2,13 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using System; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.Bindings; using UnityEngine.SceneManagement; +using UnityEngine.Scripting; +using Object = UnityEngine.Object; namespace UnityEditor { @@ -53,6 +56,15 @@ internal class SceneVisibilityState : Object public static extern int GetHiddenObjectCount(); public static extern void SetPrefabStageScene(Scene scene); + + public static Action internalStructureChanged; + + [RequiredByNativeCode] + private static void Internal_InternalStructureChanged() + { + internalStructureChanged?.Invoke(); + } + public static extern bool active { get; set; } public static extern bool prefabStageIsolated { get; set; } public static extern bool mainStageIsolated { get; set; } diff --git a/Editor/Mono/SceneVisibilityHierarchyGUI.cs b/Editor/Mono/SceneVisibilityHierarchyGUI.cs index f670d05520..9f185affe9 100644 --- a/Editor/Mono/SceneVisibilityHierarchyGUI.cs +++ b/Editor/Mono/SceneVisibilityHierarchyGUI.cs @@ -70,7 +70,7 @@ public static Color GetItemBackgroundColor(bool isHovered, bool isSelected, bool } } - private const int k_VisibilityIconPadding = 4; + private const int k_VisibilityIconPadding = 0; private const int k_IconWidth = 16; private static readonly float k_sceneHeaderOverflow = GameObjectTreeViewGUI.GameObjectStyles.sceneHeaderBg.fixedHeight - EditorGUIUtility.singleLineHeight; private static bool m_PrevItemWasScene; @@ -87,13 +87,13 @@ public static void DrawBackground(Rect rect) } } - public static void DoItemGUI(Rect rect, GameObjectTreeViewItem goItem, bool isSelected, bool isHovered, bool isFocused) + public static void DoItemGUI(Rect rect, GameObjectTreeViewItem goItem, bool isSelected, bool isHovered, bool isFocused, bool isDragging) { Rect iconRect = rect; iconRect.xMin += k_VisibilityIconPadding; iconRect.width = k_IconWidth; - - bool isIconHovered = iconRect.Contains(Event.current.mousePosition); + isHovered = isHovered && !isDragging; + bool isIconHovered = !isDragging && iconRect.Contains(Event.current.mousePosition); if (isHovered) { @@ -108,7 +108,7 @@ public static void DoItemGUI(Rect rect, GameObjectTreeViewItem goItem, bool isSe if (m_PrevItemWasScene && !isSelected && !isHovered) rect.yMin += k_sceneHeaderOverflow; - DrawItemBackground(rect, isSelected, isHovered, isFocused); + DrawItemBackground(rect, false, isSelected, isHovered, isFocused); DrawGameObjectItem(iconRect, gameObject, isHovered, isIconHovered); m_PrevItemWasScene = false; } @@ -117,21 +117,41 @@ public static void DoItemGUI(Rect rect, GameObjectTreeViewItem goItem, bool isSe Scene scene = goItem.scene; if (scene.IsValid()) { + DrawItemBackground(rect, true, isSelected, isHovered, isFocused); DrawSceneItem(iconRect, scene, isHovered, isIconHovered); m_PrevItemWasScene = true; } } } - private static void DrawItemBackground(Rect rect, bool isSelected, bool isHovered, bool isFocused) + private static void DrawItemBackground(Rect rect, bool isScene, bool isSelected, bool isHovered, bool isFocused) { if (Event.current.type == EventType.Repaint) { rect.width = utilityBarWidth; - using (new GUI.BackgroundColorScope(Styles.GetItemBackgroundColor(isHovered, isSelected, isFocused))) + if (isScene) + { + if (isSelected) + { + TreeViewGUI.Styles.selectionStyle.Draw(rect, false, false, true, isFocused); + } + else if (isHovered) + { + using (new GUI.BackgroundColorScope(GameObjectTreeViewGUI.GameObjectStyles.hoveredBackgroundColor)) + { + GUI.Label(rect, GUIContent.none, GameObjectTreeViewGUI.GameObjectStyles.hoveredItemBackgroundStyle); + } + } + } + else { - GUI.Label(rect, GUIContent.none, GameObjectTreeViewGUI.GameObjectStyles.hoveredItemBackgroundStyle); + using (new GUI.BackgroundColorScope(Styles.GetItemBackgroundColor(isHovered, isSelected, isFocused)) + ) + { + GUI.Label(rect, GUIContent.none, + GameObjectTreeViewGUI.GameObjectStyles.hoveredItemBackgroundStyle); + } } } } @@ -161,49 +181,37 @@ private static void DrawGameObjectItem(Rect rect, GameObject gameObject, bool is if (shouldDisplayIcon && GUI.Button(rect, icon, Styles.sceneVisibilityStyle)) { if (Event.current.alt) - SceneVisibilityManager.ToggleHierarchyVisibility(gameObject); - else SceneVisibilityManager.ToggleGameObjectVisibility(gameObject); + else + SceneVisibilityManager.ToggleHierarchyVisibility(gameObject); } } private static void DrawSceneItem(Rect rect, Scene scene, bool isItemHovered, bool isIconHovered) { - var isHidden = SceneVisibilityManager.IsEntireSceneHidden(scene); + var state = SceneVisibilityManager.instance.GetSceneState(scene); bool shouldDisplayIcon = true; + Styles.IconState iconState = isIconHovered ? Styles.iconHovered : Styles.iconNormal; GUIContent icon; - if (!isIconHovered) + if (state == SceneVisibilityManager.SceneState.AllHidden) { - if (isHidden) - { - icon = Styles.iconNormal.hiddenAll; - } - else if (SceneVisibilityManager.HasHiddenGameObjects(scene)) - { - icon = Styles.iconNormal.hiddenMixed; - } - else - { - icon = Styles.iconNormal.visibleAll; - shouldDisplayIcon = isItemHovered; - } + icon = iconState.hiddenAll; + } + else if (state == SceneVisibilityManager.SceneState.Mixed) + { + icon = iconState.visibleMixed; } else { - icon = Styles.iconSceneHovered; + icon = iconState.visibleAll; + shouldDisplayIcon = isItemHovered; } + if (shouldDisplayIcon && GUI.Button(rect, icon, Styles.sceneVisibilityStyle)) { - if (isHidden) - { - SceneVisibilityManager.ShowScene(scene); - } - else - { - SceneVisibilityManager.HideScene(scene); - } + SceneVisibilityManager.instance.ToggleScene(scene, state); } } } diff --git a/Editor/Mono/SceneVisibilityManager.cs b/Editor/Mono/SceneVisibilityManager.cs index cb2f79dc2c..3971750d47 100644 --- a/Editor/Mono/SceneVisibilityManager.cs +++ b/Editor/Mono/SceneVisibilityManager.cs @@ -15,6 +15,26 @@ namespace UnityEditor { internal class SceneVisibilityManager : ScriptableSingleton { + internal class ShortcutContext : IShortcutToolContext + { + public bool active + { + get + { + var focusedWindow = EditorWindow.focusedWindow; + if (focusedWindow != null) + { + return (focusedWindow.GetType() == typeof(SceneView) || + focusedWindow.GetType() == typeof(SceneHierarchyWindow)); + } + + return false; + } + } + } + + private static ShortcutContext s_ShortcutContext; + internal static event Action hiddenContentChanged; internal static event Action currentStageIsolated; @@ -34,12 +54,20 @@ private static void Initialize() EditorSceneManager.sceneSaving += EditorSceneManagerOnSceneSaving; EditorSceneManager.sceneSaved += EditorSceneManagerOnSceneSaved; EditorSceneManager.sceneOpening += EditorSceneManagerOnSceneOpening; + EditorSceneManager.sceneOpened += EditorSceneManagerOnSceneOpened; EditorSceneManager.sceneClosing += EditorSceneManagerOnSceneClosing; EditorApplication.playModeStateChanged += EditorApplicationPlayModeStateChanged; StageNavigationManager.instance.stageChanged += StageNavigationManagerOnStageChanging; - + SceneVisibilityState.internalStructureChanged += InternalStructureChanged; PrefabStage stage = StageNavigationManager.instance.GetCurrentPrefabStage(); SceneVisibilityState.SetPrefabStageScene(stage == null ? default(Scene) : stage.scene); + s_ShortcutContext = new ShortcutContext(); + ShortcutIntegration.instance.contextManager.RegisterToolContext(s_ShortcutContext); + } + + private static void InternalStructureChanged() + { + HiddenContentChanged(); } private static void EditorSceneManagerOnSceneOpened(Scene scene, OpenSceneMode mode) @@ -59,6 +87,7 @@ private static void EditorSceneManagerOnSceneOpened(Scene scene, OpenSceneMode m SceneVisibilityState.SetSceneIsolation(scene, true); } } + HiddenContentChanged(); } private static void StageNavigationManagerOnStageChanging(StageNavigationItem oldItem, StageNavigationItem newItem) @@ -116,6 +145,7 @@ private static void EditorSceneManagerOnNewSceneCreated(Scene scene, NewSceneSet } //need to clear scene on new scene since all new scenes use the same GUID SceneVisibilityState.ClearScene(scene); + HiddenContentChanged(); } private static void UndoRedoPerformed() @@ -154,6 +184,7 @@ internal static void SetGameObjectHidden(GameObject gameObject, bool isHidden, b HiddenContentChanged(); } + [Shortcut("Scene Visibility/Show All")] internal static void ShowAll() { Undo.RecordObject(SceneVisibilityState.GetInstance(), "Show All"); @@ -229,7 +260,10 @@ internal static bool IsEntireSceneHidden(Scene scene) scene.GetRootGameObjects(m_RootBuffer); foreach (GameObject root in m_RootBuffer) { - if (!IsGameObjectHidden(root) || !AreAllChildrenHidden(root)) + if (IsIgnoredBySceneVisibility(root)) + continue; + + if (!SceneVisibilityState.IsHierarchyHidden(root)) return false; } @@ -241,6 +275,29 @@ internal static bool IsHierarchyHidden(GameObject gameObject) return SceneVisibilityState.IsHierarchyHidden(gameObject); } + static bool IsIgnoredBySceneVisibility(GameObject go) + { + var hideFlags = HideFlags.HideInHierarchy | HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor; + + return (go.hideFlags & hideFlags) != 0; + } + + internal enum SceneState + { + AllHidden, + AllVisible, + Mixed + } + + internal SceneState GetSceneState(Scene scene) + { + if (IsEntireSceneHidden(scene)) + return SceneState.AllHidden; + if (HasHiddenGameObjects(scene)) + return SceneState.Mixed; + return SceneState.AllVisible; + } + internal static bool HasHiddenGameObjects(Scene scene) { return SceneVisibilityState.HasHiddenGameObjects(scene); @@ -267,13 +324,10 @@ internal static void IsolateGameObjects(GameObject[] gameObjects, bool includeCh { Undo.RecordObject(SceneVisibilityState.GetInstance(), "Isolate GameObjects"); - if (gameObjects.Length > 0) - { - IsolateCurrentStage(); - HideAllNoUndo(); - SceneVisibilityState.SetGameObjectsHidden(gameObjects, false, includeChildren); - HiddenContentChanged(); - } + IsolateCurrentStage(); + HideAllNoUndo(); + SceneVisibilityState.SetGameObjectsHidden(gameObjects, false, includeChildren); + HiddenContentChanged(); } private static void ToggleSelectionVisibility() @@ -330,7 +384,7 @@ internal static bool AreAllChildrenVisible(GameObject gameObject) } //SHORTCUTS - [Shortcut("Scene Visibility/Toggle Visibility")] + [Shortcut("Scene Visibility/Toggle Visibility for Selection")] internal static void ToggleSelectionGameObjectVisibility() { if (Selection.gameObjects.Length > 0) @@ -345,13 +399,13 @@ internal static void ToggleSelectionGameObjectVisibility() shouldHide = false; } - Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Visibility"); + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Visibility for Selection"); SceneVisibilityState.SetGameObjectsHidden(Selection.gameObjects, shouldHide, false); HiddenContentChanged(); } } - [Shortcut("Scene Visibility/Toggle Visibility And Children")] + [Shortcut("Scene Visibility/Toggle Visibility for Selection and Children", typeof(ShortcutContext), KeyCode.H)] internal static void ToggleSelectionHierarchyVisibility() { if (Selection.gameObjects.Length > 0) @@ -366,7 +420,7 @@ internal static void ToggleSelectionHierarchyVisibility() shouldHide = false; } - Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Visibility And Children"); + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Visibility for Selection and Children"); SceneVisibilityState.SetGameObjectsHidden(Selection.gameObjects, shouldHide, true); HiddenContentChanged(); } @@ -440,10 +494,10 @@ internal static void ExitIsolation() } } - [Shortcut("Scene Visibility/Isolate Selection And Children")] - internal static void SelectionHierarchyIsolation() + [Shortcut("Scene Visibility/Toggle Isolation for Selection and Children", typeof(ShortcutContext), KeyCode.H, ShortcutModifiers.Shift)] + internal static void ToggleSelectionHierarchyIsolation() { - Undo.RecordObject(SceneVisibilityState.GetInstance(), "Isolate Selection And Children"); + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Isolation for Selection and Children"); if (!IsCurrentStageIsolated()) { @@ -459,24 +513,15 @@ internal static void SelectionHierarchyIsolation() } else { - if (Selection.gameObjects.Length > 0) - { - HideAllNoUndo(); - SceneVisibilityState.SetGameObjectsHidden(Selection.gameObjects, false, true); - HiddenContentChanged(); - } - else - { - RevertIsolationCurrentStage(); - HiddenContentChanged(); - } + RevertIsolationCurrentStage(); + HiddenContentChanged(); } } - [Shortcut("Scene Visibility/Isolate Selection")] - internal static void SelectionGameObjectIsolation() + [Shortcut("Scene Visibility/Toggle Isolation for Selection")] + internal static void ToggleSelectionGameObjectIsolation() { - Undo.RecordObject(SceneVisibilityState.GetInstance(), "Isolate Selection"); + Undo.RecordObject(SceneVisibilityState.GetInstance(), "Toggle Isolation for Selection"); if (!IsCurrentStageIsolated()) { @@ -492,17 +537,20 @@ internal static void SelectionGameObjectIsolation() } else { - if (Selection.gameObjects.Length > 0) - { - HideAllNoUndo(); - SceneVisibilityState.SetGameObjectsHidden(Selection.gameObjects, false, false); - HiddenContentChanged(); - } - else - { - RevertIsolationCurrentStage(); - HiddenContentChanged(); - } + RevertIsolationCurrentStage(); + HiddenContentChanged(); + } + } + + internal void ToggleScene(Scene scene, SceneState state) + { + if (state == SceneState.AllVisible || state == SceneState.Mixed) + { + HideScene(scene); + } + else + { + ShowScene(scene); } } } diff --git a/Editor/Mono/ScriptAttributeGUI/Implementations/ExposedReferenceDrawer.cs b/Editor/Mono/ScriptAttributeGUI/Implementations/ExposedReferenceDrawer.cs index f0f15fdd38..c84785b4f2 100644 --- a/Editor/Mono/ScriptAttributeGUI/Implementations/ExposedReferenceDrawer.cs +++ b/Editor/Mono/ScriptAttributeGUI/Implementations/ExposedReferenceDrawer.cs @@ -16,7 +16,7 @@ abstract class BaseExposedPropertyDrawer : UnityEditor.PropertyDrawer protected readonly GUIContent ExposePropertyContent = EditorGUIUtility.TrTextContent("Expose Property"); protected readonly GUIContent UnexposePropertyContent = EditorGUIUtility.TrTextContent("Unexpose Property"); protected readonly GUIContent NotFoundOn = EditorGUIUtility.TrTextContent("not found on"); - protected readonly GUIContent OverridenByContent = EditorGUIUtility.TrTextContent("Overriden by "); + protected readonly GUIContent OverridenByContent = EditorGUIUtility.TrTextContent("Overridden by "); private GUIContent m_ModifiedLabel = new GUIContent(); diff --git a/Editor/Mono/ScriptGeneratorAsset.bindings.cs b/Editor/Mono/ScriptGeneratorAsset.bindings.cs deleted file mode 100644 index 89872f8a6b..0000000000 --- a/Editor/Mono/ScriptGeneratorAsset.bindings.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections; -using UnityEngine.Bindings; -using UnityEngine.Scripting; -using UnityEngineInternal; -using UnityEngine; -using uei = UnityEngine.Internal; - -namespace UnityEditor -{ - [NativeClass(null)] - [RequiredByNativeCode] - [NativeType(Header = "Runtime/Mono/MonoBehaviour.h")] - public abstract class ScriptGeneratorAsset : ScriptableObject - { - // Returns the ScriptGeneratorAsset object containing specified MonoBehaviour - public static ScriptGeneratorAsset FromMonoBehaviour(MonoBehaviour behaviour) - { - return ScriptGeneratorAsset.Internal_FromMonoBehaviour(behaviour) as ScriptGeneratorAsset; - } - - public static void SetGeneratorAsset(MonoBehaviour behaviour, ScriptGeneratorAsset asset) - { - ScriptGeneratorAsset.Internal_SetGeneratorAsset(behaviour, asset); - } - - public abstract string label { get; } - - [RequiredByNativeCode] - private string GetLabel() - { - return label; - } - - public abstract MonoScript defaultScript { get; } - - [RequiredByNativeCode] - private MonoScript GetDefaultScript() - { - return defaultScript; - } - - // Returns the ScriptGeneratorAsset object used by the given scripted object - [FreeFunction("MonoBehaviour::Internal_FromMonoBehaviour")] - internal static extern UnityEngine.Object Internal_FromMonoBehaviour(MonoBehaviour behaviour); - - // Sets the ScriptGenerator asset in the MonoBehaviour - [FreeFunction("MonoBehaviour::Internal_SetGeneratorAsset")] - internal static extern void Internal_SetGeneratorAsset([NotNull] MonoBehaviour behaviour, UnityEngine.Object asset); - } -} diff --git a/Editor/Mono/Scripting/APIUpdater/APIUpdaterAssemblyHelper.cs b/Editor/Mono/Scripting/APIUpdater/APIUpdaterAssemblyHelper.cs index c655f1cf54..4a72c252f2 100644 --- a/Editor/Mono/Scripting/APIUpdater/APIUpdaterAssemblyHelper.cs +++ b/Editor/Mono/Scripting/APIUpdater/APIUpdaterAssemblyHelper.cs @@ -20,12 +20,15 @@ internal class APIUpdaterAssemblyHelper { // See AssemblyUpdater/Program.cs internal const byte Success = 0x00; + internal const byte FirstSuccessStatus = (1 << 3); + internal const byte FirstErrorStatus = (1 << 7); + + internal const byte ContainsUpdaterConfigurations = (1 << 3) + 2; internal const byte UpdatesApplied = (1 << 3) + 3; internal static int Run(string arguments, string workingDir, out string stdOut, out string stdErr) { - var assemblyUpdaterPath = EditorApplication.applicationContentsPath + "/Tools/ScriptUpdater/AssemblyUpdater.exe"; var monodistribution = MonoInstallationFinder.GetMonoInstallation("MonoBleedingEdge"); var monoexe = Path.Combine(monodistribution, "bin/mono"); @@ -38,7 +41,7 @@ internal static int Run(string arguments, string workingDir, out string stdOut, var startInfo = new ProcessStartInfo { - Arguments = assemblyUpdaterPath + " " + arguments, + Arguments = AssemblyUpdaterPath() + " " + arguments, CreateNoWindow = true, FileName = monoexe, RedirectStandardError = true, @@ -59,6 +62,14 @@ internal static int Run(string arguments, string workingDir, out string stdOut, return assemblyUpdaterProcess.ExitCode; } + static string AssemblyUpdaterPath() + { + var unescapedAssemblyUpdaterPath = EditorApplication.applicationContentsPath + "/Tools/ScriptUpdater/AssemblyUpdater.exe"; + return Application.platform == RuntimePlatform.WindowsEditor + ? CommandLineFormatter.EscapeCharsWindows(unescapedAssemblyUpdaterPath) + : CommandLineFormatter.EscapeCharsQuote(unescapedAssemblyUpdaterPath); + } + internal static string ArgumentsForUpdateAssembly(string assemblyPath, string tempOutputPath, IEnumerable updateConfigSourcePaths) { var assemblyFullPath = ResolveAssemblyPath(assemblyPath); @@ -84,6 +95,14 @@ internal static bool IsError(int exitCode) return (exitCode & (1 << 7)) != 0; } + internal static bool IsUnknown(int exitCode) + { + // See AssemblyUpdater/Program.cs + return exitCode != 0 + && (exitCode & FirstErrorStatus) == 0 // It is not an error code returned from AssemblyUpdater.exe + && (exitCode & FirstSuccessStatus) == 0; // It is not an success code returned from AssemblyUpdater.exe + } + private static string ResolveAssemblyPath(string assemblyPath) { return CommandLineFormatter.PrepareFileName(assemblyPath); diff --git a/Editor/Mono/Scripting/APIUpdater/APIUpdaterManager.bindings.cs b/Editor/Mono/Scripting/APIUpdater/APIUpdaterManager.bindings.cs index 8f6da209dc..12997385c3 100644 --- a/Editor/Mono/Scripting/APIUpdater/APIUpdaterManager.bindings.cs +++ b/Editor/Mono/Scripting/APIUpdater/APIUpdaterManager.bindings.cs @@ -213,16 +213,14 @@ private static void LogTimeoutError(AssemblyUpdaterUpdateTask[] tasks) private static bool HandleAssemblyUpdaterErrors(IEnumerable allTasks) { - var tasksWithErrors = allTasks.Where(t => APIUpdaterAssemblyHelper.IsError(t.Result) || t.Exception != null); + var tasksWithErrors = allTasks.Where(t => APIUpdaterAssemblyHelper.IsError(t.Result) || APIUpdaterAssemblyHelper.IsUnknown(t.Result) || t.Exception != null); if (!tasksWithErrors.Any()) return false; var sb = new StringBuilder(L10n.Tr("Unable to update following assemblies:")); foreach (var updaterTask in tasksWithErrors) { - sb.AppendFormat("{1} (Name = {2}, Error = {3}) (Output: {4}){0}{5}{0}{6}{0}", Environment.NewLine, updaterTask.Candidate.Path, updaterTask.Candidate.Name, updaterTask.Result, updaterTask.OutputPath, updaterTask.StdOut, updaterTask.StdErr); - if (updaterTask.Exception != null) - sb.AppendFormat("\tException: {0}{1}", updaterTask.Exception, Environment.NewLine); + sb.Append(FormatErrorFromTask(updaterTask)); } ReportIgnoredAssembliesDueToPreviousErrors(sb, allTasks.Except(tasksWithErrors)); @@ -231,9 +229,33 @@ private static bool HandleAssemblyUpdaterErrors(IEnumerable completedSuccessfully) { - sb.AppendFormat(L10n.Tr("Following assemblies were successfully updated but due to the failled ones above they were ignored (not copied to the destination folder).")); + sb.AppendFormat(L10n.Tr("Following assemblies were successfully updated but due to the failed ones above they were ignored (not copied to the destination folder).")); foreach (var updaterTask in completedSuccessfully) { sb.AppendFormat("{1} (Result = {2}) (Output: {3}){0}{4}{0}", Environment.NewLine, updaterTask.Candidate.Path, updaterTask.Result, updaterTask.OutputPath, updaterTask.StdOut); diff --git a/Editor/Mono/Scripting/Compilers/CSharpLanguage.cs b/Editor/Mono/Scripting/Compilers/CSharpLanguage.cs index ae8f4c9041..625b4cb7b2 100644 --- a/Editor/Mono/Scripting/Compilers/CSharpLanguage.cs +++ b/Editor/Mono/Scripting/Compilers/CSharpLanguage.cs @@ -132,7 +132,7 @@ public override string GetNamespace(string filePath, string definedSymbols) { var responseFileData = ScriptCompilerBase.ParseResponseFileFromFile( responseFilePath, - Application.dataPath, + Directory.GetParent(Application.dataPath).FullName, GetSystemReferenceDirectories(ApiCompatibilityLevel.NET_4_6)); return GetNamespaceNewRuntime(filePath, definedSymbols, responseFileData.Defines); } @@ -140,7 +140,7 @@ public override string GetNamespace(string filePath, string definedSymbols) { var responseFileData = ScriptCompilerBase.ParseResponseFileFromFile( responseFilePath, - Application.dataPath, + Directory.GetParent(Application.dataPath).FullName, GetSystemReferenceDirectories(ApiCompatibilityLevel.NET_2_0)); return GetNamespaceOldRuntime(filePath, definedSymbols, responseFileData.Defines); } diff --git a/Editor/Mono/Scripting/Compilers/MicrosoftCSharpCompiler.cs b/Editor/Mono/Scripting/Compilers/MicrosoftCSharpCompiler.cs index 6cb59d4192..3a55b67714 100644 --- a/Editor/Mono/Scripting/Compilers/MicrosoftCSharpCompiler.cs +++ b/Editor/Mono/Scripting/Compilers/MicrosoftCSharpCompiler.cs @@ -37,7 +37,7 @@ private void FillCompilerOptions(List arguments, out string argsPrefix) arguments.Add("/langversion:latest"); var platformSupportModule = ModuleManager.FindPlatformSupportModule(ModuleManager.GetTargetStringFromBuildTarget(BuildTarget)); - if (platformSupportModule != null && !m_Island._editor) + if (platformSupportModule != null && !m_Island._buildingForEditor) { var compilationExtension = platformSupportModule.CreateCompilationExtension(); @@ -130,7 +130,7 @@ protected override Program StartCompiler() arguments.Add("/debug:portable"); - var disableOptimizations = m_Island._development_player || (m_Island._editor && EditorPrefs.GetBool("AllowAttachedDebuggingOfEditor", true)); + var disableOptimizations = m_Island._development_player || (m_Island._buildingForEditor && EditorPrefs.GetBool("AllowAttachedDebuggingOfEditor", true)); if (!disableOptimizations) { arguments.Add("/optimize+"); diff --git a/Editor/Mono/Scripting/Compilers/MonoCSharpCompiler.cs b/Editor/Mono/Scripting/Compilers/MonoCSharpCompiler.cs index 3e0c5207fe..7372fbc656 100644 --- a/Editor/Mono/Scripting/Compilers/MonoCSharpCompiler.cs +++ b/Editor/Mono/Scripting/Compilers/MonoCSharpCompiler.cs @@ -35,7 +35,7 @@ protected override Program StartCompiler() if (m_Island._allowUnsafeCode) arguments.Add("-unsafe"); - if (!m_Island._development_player && !m_Island._editor) + if (!m_Island._development_player && !m_Island._buildingForEditor) arguments.Add("-optimize"); foreach (string dll in m_Island._references) diff --git a/Editor/Mono/Scripting/Compilers/ScriptCompilerBase.cs b/Editor/Mono/Scripting/Compilers/ScriptCompilerBase.cs index 4f8aefa6b6..31d1f066d4 100644 --- a/Editor/Mono/Scripting/Compilers/ScriptCompilerBase.cs +++ b/Editor/Mono/Scripting/Compilers/ScriptCompilerBase.cs @@ -115,7 +115,7 @@ protected void AddResponseFileToArguments(List arguments, string respons { var responseFileData = ParseResponseFileFromFile( responseFileName, - Application.dataPath, + Directory.GetParent(Application.dataPath).FullName, GetSystemReferenceDirectories()); foreach (var error in responseFileData.Errors) { @@ -137,6 +137,9 @@ public static ResponseFileData ParseResponseFileFromFile( string projectDirectory, string[] systemReferenceDirectories) { + responseFilePath = Paths.ConvertSeparatorsToUnity(responseFilePath); + projectDirectory = Paths.ConvertSeparatorsToUnity(projectDirectory); + var relativeResponseFilePath = GetRelativePath(responseFilePath, projectDirectory); var responseFile = AssetDatabase.LoadAssetAtPath(relativeResponseFilePath); @@ -175,7 +178,7 @@ static string GetRelativePath(string responseFilePath, string projectDirectory) { if (Path.IsPathRooted(responseFilePath) && responseFilePath.Contains(projectDirectory)) { - responseFilePath = responseFilePath.Substring(Directory.GetParent(Application.dataPath).FullName.Length + 1); + responseFilePath = responseFilePath.Substring(projectDirectory.Length + 1); } return responseFilePath; } @@ -339,7 +342,8 @@ static ResponseFileData ParseResponseFileText( } var fullPathReference = responseReference; - if (!Path.IsPathRooted(responseReference)) + bool isRooted = Path.IsPathRooted(responseReference); + if (!isRooted) { foreach (var directory in systemReferenceDirectories) { @@ -347,6 +351,7 @@ static ResponseFileData ParseResponseFileText( if (File.Exists(systemReferencePath)) { fullPathReference = systemReferencePath; + isRooted = true; break; } } @@ -355,10 +360,11 @@ static ResponseFileData ParseResponseFileText( if (File.Exists(userPath)) { fullPathReference = userPath; + isRooted = true; } } - if (fullPathReference == "") + if (!isRooted) { errors.Add($"{fileName}: not parsed correctly: {responseReference} could not be found as a system library.\n" + "If this was meant as a user reference please provide the relative path from project root (parent of the Assets folder) in the response file."); @@ -426,7 +432,7 @@ public virtual CompilerMessage[] GetCompilerMessages() ).ToArray(); } - protected bool CompilationHadFailure() + internal bool CompilationHadFailure() { return (process.ExitCode != 0); } diff --git a/Editor/Mono/Scripting/ScriptCompilation/AssemblyBuilder.cs b/Editor/Mono/Scripting/ScriptCompilation/AssemblyBuilder.cs index d2273ecb81..060e9b77ea 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/AssemblyBuilder.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/AssemblyBuilder.cs @@ -23,6 +23,13 @@ public enum AssemblyBuilderFlags DevelopmentBuild = 2, }; + [Flags] + public enum ReferencesOptions + { + None = 0, + UseEngineModules = 1 + } + public class AssemblyBuilder { public event Action buildStarted; @@ -34,6 +41,7 @@ public class AssemblyBuilder public string[] additionalReferences { get; set; } public string[] excludeReferences { get; set; } public ScriptCompilerOptions compilerOptions { get; set; } + public ReferencesOptions referencesOptions { get; set; } public AssemblyBuilderFlags flags { get; set; } public BuildTargetGroup buildTargetGroup { get; set; } @@ -71,6 +79,7 @@ public AssemblyBuilder(string assemblyPath, params string[] scriptPaths) compilerOptions = new ScriptCompilerOptions(); flags = AssemblyBuilderFlags.None; + referencesOptions = ReferencesOptions.None; buildTargetGroup = EditorUserBuildSettings.activeBuildTargetGroup; buildTarget = EditorUserBuildSettings.activeBuildTarget; } diff --git a/Editor/Mono/Scripting/ScriptCompilation/CSharpNamespaceParser.cs b/Editor/Mono/Scripting/ScriptCompilation/CSharpNamespaceParser.cs index 408611723a..97bdc44ea6 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/CSharpNamespaceParser.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/CSharpNamespaceParser.cs @@ -41,11 +41,11 @@ public static string GetNamespace(string sourceCode, string className, params st s_ClassName = className; sourceCode = k_NewlineRegex.Replace(sourceCode, "\n"); + sourceCode = k_SingleQuote.Replace(sourceCode, ""); sourceCode = k_Strings.Replace(sourceCode, ""); sourceCode = k_BlockComments.Replace(sourceCode, ""); sourceCode = k_LineComments.Replace(sourceCode, "\n"); sourceCode = k_VerbatimStrings.Replace(sourceCode, ""); - sourceCode = k_SingleQuote.Replace(sourceCode, ""); try { sourceCode = RemoveUnusedDefines(sourceCode, defines.ToList()); @@ -66,26 +66,29 @@ static string FindNamespaceForMono(string className, string source) var builder = new StringBuilder(source.Length); var buildingNode = false; var buildingClass = false; - var currentNode = parent; var level = 0; var resNamespace = ""; foreach (var token in split) + { switch (token) { case "{": if (buildingNode) { - currentNode = AddCurrent(level, builder.ToString(), parent); + parent = AddCurrent(level, builder.ToString(), parent); builder = new StringBuilder(); buildingNode = false; } level++; - parent = currentNode; break; case "}": - if (parent.Level > --level) parent = parent.Parent; + if (parent.Level > --level) + { + parent = parent.Parent; + builder.Clear(); + } break; case "class": buildingClass = true; @@ -100,7 +103,7 @@ static string FindNamespaceForMono(string className, string source) var strippedClassname = StripClassName(token); if (buildingClass && strippedClassname.Equals(className)) { - buildingNode = false; + buildingClass = false; resNamespace = CollectNamespace(parent); } else @@ -111,6 +114,7 @@ static string FindNamespaceForMono(string className, string source) break; } + } return resNamespace; } diff --git a/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs b/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs index 941d5e7170..28511ffea6 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs @@ -64,21 +64,34 @@ class CustomScriptAssemblyData public static CustomScriptAssemblyData FromJson(string json) { - CustomScriptAssemblyData assemblyData = new CustomScriptAssemblyData(); + var assemblyData = FromJsonNoFieldValidation(json); + + assemblyData.ValidateFields(); + + return assemblyData; + } + + public static CustomScriptAssemblyData FromJsonNoFieldValidation(string json) + { + var assemblyData = new CustomScriptAssemblyData(); + assemblyData.autoReferenced = true; UnityEngine.JsonUtility.FromJsonOverwrite(json, assemblyData); if (assemblyData == null) throw new System.Exception("Json file does not contain an assembly definition"); - if (string.IsNullOrEmpty(assemblyData.name)) + return assemblyData; + } + + public void ValidateFields() + { + if (string.IsNullOrEmpty(name)) throw new System.Exception("Required property 'name' not set"); - if ((assemblyData.excludePlatforms != null && assemblyData.excludePlatforms.Length > 0) && - (assemblyData.includePlatforms != null && assemblyData.includePlatforms.Length > 0)) + if ((excludePlatforms != null && excludePlatforms.Length > 0) && + (includePlatforms != null && includePlatforms.Length > 0)) throw new System.Exception("Both 'excludePlatforms' and 'includePlatforms' are set."); - - return assemblyData; } public static string ToJson(CustomScriptAssemblyData data) @@ -213,7 +226,7 @@ public bool IsCompatibleWithEditor() return true; } - public bool IsCompatibleWith(BuildTarget buildTarget, EditorScriptCompilationOptions options, string[] defines = null) + public bool IsCompatibleWith(BuildTarget buildTarget, EditorScriptCompilationOptions options, string[] defines) { bool buildingForEditor = (options & EditorScriptCompilationOptions.BuildingForEditor) == EditorScriptCompilationOptions.BuildingForEditor; @@ -224,6 +237,9 @@ public bool IsCompatibleWith(BuildTarget buildTarget, EditorScriptCompilationOpt return false; } + if (defines != null && defines.Length == 0) + throw new ArgumentException("defines cannot be empty", "defines"); + if (!DefineConstraintsHelper.IsDefineConstraintsCompatible(defines, DefineConstraints)) { return false; diff --git a/Editor/Mono/Scripting/ScriptCompilation/EditorBuildRules.cs b/Editor/Mono/Scripting/ScriptCompilation/EditorBuildRules.cs index 4a74a69a16..a0315d3fc5 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/EditorBuildRules.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/EditorBuildRules.cs @@ -59,7 +59,7 @@ internal class TargetAssembly public TargetAssembly() { References = new List(); - Defines = new string[0]; + Defines = null; } public TargetAssembly(string name, @@ -222,10 +222,10 @@ public static TargetAssembly[] CreateTargetAssemblies(IEnumerable 1) { + var pathsString = string.Join(", ", groupedPrecompiledAssemblies.Select(x => x.Path).ToArray()); + throw new PrecompiledAssemblyException( - $"Multiple precompiled assemblies with the same name {groupedPrecompiledAssemblies.Key} included for the current platform. Only one assembly with the same name is allowed per platform. Assembly path: {{0}}", - groupedPrecompiledAssemblies.Select(x => x.Path).ToArray() - ); + $"Multiple precompiled assemblies with the same name {groupedPrecompiledAssemblies.Key} included for the current platform. Only one assembly with the same name is allowed per platform. Assembly paths: {pathsString}"); } nameToPrecompiledAssemblies.Add(groupedPrecompiledAssemblies.Key, groupedPrecompiledAssemblies.Single()); } @@ -393,12 +393,22 @@ public static ScriptAssembly[] GenerateChangedScriptAssemblies(GenerateChangedSc assemblySourceFiles.Add(AssetPath.Combine(args.ProjectDirectory, dirtySourceFile)); + if (targetAssembly.Language == null && targetAssembly.Type == TargetAssemblyType.Custom) + targetAssembly.Language = scriptLanguage; + // If there are mixed languages in a custom script folder, mark the assembly to not be compiled. if (scriptLanguage != targetAssembly.Language) args.NotCompiledTargetAssemblies.Add(targetAssembly); } - bool isAnyCustomScriptAssemblyDirty = dirtyTargetAssemblies.Any(entry => entry.Key.Type == TargetAssemblyType.Custom); + bool isAnyCustomScriptAssemblyDirty = dirtyTargetAssemblies.Any(entry => + { + var targetAssembly = entry.Key; + bool isCustomScriptAssembly = targetAssembly.Type == TargetAssemblyType.Custom; + bool isExplicitlyReferenced = (targetAssembly.Flags & AssemblyFlags.ExplicitlyReferenced) == AssemblyFlags.ExplicitlyReferenced; + bool isTestAssembly = (targetAssembly.OptionalUnityReferences & OptionalUnityReferences.TestAssemblies) == OptionalUnityReferences.TestAssemblies; + return isCustomScriptAssembly && !isExplicitlyReferenced && !isTestAssembly; + }); // If we have any dirty custom target assemblies, then the predefined target assemblies are marked as dirty, // as the predefined assemblies always reference the custom script assemblies. @@ -542,7 +552,7 @@ internal static ScriptAssembly[] ToScriptAssemblies(IDictionary allScripts, + internal static TargetAssembly[] GetTargetAssembliesWithScripts( + IEnumerable allScripts, + string projectDirectory, + TargetAssembly[] customTargetAssemblies, + ScriptAssemblySettings settings) + { + return GetTargetAssembliesWithScriptsHashSet(allScripts, projectDirectory, customTargetAssemblies, settings).ToArray(); + } + + internal static HashSet GetTargetAssembliesWithScriptsHashSet( + IEnumerable allScripts, string projectDirectory, TargetAssembly[] customTargetAssemblies, ScriptAssemblySettings settings) @@ -884,7 +904,7 @@ internal static TargetAssembly[] GetTargetAssembliesWithScripts(IEnumerable(); + var assembliesWithScripts = GetTargetAssembliesWithScriptsHashSet(options); do { @@ -457,6 +461,11 @@ public TargetAssemblyInfo[] GetAllCompiledAndResolvedCustomTargetAssemblies(Edit if (!EditorBuildRules.IsCompatibleWithPlatformAndDefines(reference, buildTarget, options)) continue; + if (!assembliesWithScripts.Contains(reference)) + { + continue; + } + if (!customTargetAssemblyCompiledPaths.ContainsKey(reference)) { customTargetAssemblyCompiledPaths.Remove(assembly); @@ -755,6 +764,9 @@ public Exception[] SetAllCustomScriptAssemblyJsonContents(string[] paths, string loadedCustomScriptAssembly = LoadCustomScriptAssemblyFromJsonPath(fullPath, guid); } + if (loadedCustomScriptAssembly.References == null) + loadedCustomScriptAssembly.References = new string[0]; + guidsToAssemblies[Utility.FastToLower(guid)] = loadedCustomScriptAssembly; if (!skipCustomScriptAssemblyGraphValidation) @@ -801,9 +813,6 @@ public Exception[] SetAllCustomScriptAssemblyJsonContents(string[] paths, string loadedCustomScriptAssembly.PathPrefix), filePaths.ToArray()); } } - - if (loadedCustomScriptAssembly.References == null) - loadedCustomScriptAssembly.References = new string[0]; } catch (Exception e) { @@ -864,7 +873,7 @@ public Exception[] SetAllCustomScriptAssemblyJsonContents(string[] paths, string if (references.Count() != references.Distinct().Count()) { - var duplicateRefs = references.GroupBy(r => r).Where(g => g.Count() > 0).Select(g => g.Key) + var duplicateRefs = references.GroupBy(r => r).Where(g => g.Count() > 1).Select(g => g.Key) .ToArray(); var duplicateRefsString = string.Join(",", duplicateRefs); @@ -897,19 +906,30 @@ public bool IsPathInPackageDirectory(string path) return m_AssetPathsMetaData.Any(p => path.StartsWith(p.DirectoryPath, StringComparison.OrdinalIgnoreCase)); } - // Delete all .dll's that aren't used anymore public void DeleteUnusedAssemblies() + { + ScriptAssemblySettings settings = CreateEditorScriptAssemblySettings(EditorScriptCompilationOptions.BuildingForEditor); + DeleteUnusedAssemblies(settings); + } + + // Delete all .dll's that aren't used anymore + public void DeleteUnusedAssemblies(ScriptAssemblySettings settings) { string fullEditorAssemblyPath = AssetPath.Combine(projectDirectory, GetCompileScriptsOutputDirectory()); if (!Directory.Exists(fullEditorAssemblyPath)) + { + // This is called in GetTargetAssembliesWithScripts and is required for compilation to + // be set up correctly. Since we early out here, we need to call this here. + UpdateAllTargetAssemblyDefines(customTargetAssemblies, EditorBuildRules.GetPredefinedTargetAssemblies(), m_AllDistinctVersionMetaDatas, settings); return; + } var deleteFiles = Directory.GetFiles(fullEditorAssemblyPath).Select(f => AssetPath.ReplaceSeparators(f)).ToList(); string timestampPath = GetAssemblyTimestampPath(GetCompileScriptsOutputDirectory()); deleteFiles.Remove(AssetPath.Combine(projectDirectory, timestampPath)); - var targetAssemblies = GetTargetAssembliesWithScripts(EditorScriptCompilationOptions.BuildingForEditor); + var targetAssemblies = GetTargetAssembliesWithScripts(settings); foreach (var assembly in targetAssemblies) { @@ -1124,15 +1144,13 @@ private static EditorBuildRules.TargetAssembly[] GetPredefinedAssemblyReferences internal CompileStatus CompileScripts(ScriptAssemblySettings scriptAssemblySettings, string tempBuildDirectory, EditorScriptCompilationOptions options, ref EditorBuildRules.TargetAssembly[] notCompiledTargetAssemblies, ref string[] notCompiledScripts) { - DeleteUnusedAssemblies(); + DeleteUnusedAssemblies(scriptAssemblySettings); if (!DoesProjectFolderHaveAnyDirtyScripts() && !ArePrecompiledAssembliesDirty() && runScriptUpdaterAssemblies.Count == 0) return CompileStatus.Idle; - UpdateAllTargetAssemblyDefines(customTargetAssemblies, EditorBuildRules.GetPredefinedTargetAssemblies(), m_AllDistinctVersionMetaDatas, scriptAssemblySettings); - var assemblies = new EditorBuildRules.CompilationAssemblies { UnityAssemblies = unityAssemblies, @@ -1185,7 +1203,7 @@ internal CompileStatus CompileScripts(ScriptAssemblySettings scriptAssemblySetti if (returnCompilationComplete) { - DeleteUnusedAssemblies(); + DeleteUnusedAssemblies(scriptAssemblySettings); compilationTask = null; return CompileStatus.CompilationComplete; } @@ -1576,8 +1594,13 @@ public TargetAssemblyInfo[] GetTargetAssemblies() public TargetAssemblyInfo[] GetTargetAssembliesWithScripts(EditorScriptCompilationOptions options) { ScriptAssemblySettings settings = CreateEditorScriptAssemblySettings(EditorScriptCompilationOptions.BuildingForEditor | options); - var targetAssemblies = EditorBuildRules.GetTargetAssembliesWithScripts(allScripts, projectDirectory, customTargetAssemblies, settings); + return GetTargetAssembliesWithScripts(settings); + } + public TargetAssemblyInfo[] GetTargetAssembliesWithScripts(ScriptAssemblySettings settings) + { + UpdateAllTargetAssemblyDefines(customTargetAssemblies, EditorBuildRules.GetPredefinedTargetAssemblies(), m_AllDistinctVersionMetaDatas, settings); + var targetAssemblies = EditorBuildRules.GetTargetAssembliesWithScripts(allScripts, projectDirectory, customTargetAssemblies, settings); var targetAssemblyInfos = new TargetAssemblyInfo[targetAssemblies.Length]; for (int i = 0; i < targetAssemblies.Length; ++i) @@ -1586,6 +1609,14 @@ public TargetAssemblyInfo[] GetTargetAssembliesWithScripts(EditorScriptCompilati return targetAssemblyInfos; } + private HashSet GetTargetAssembliesWithScriptsHashSet(EditorScriptCompilationOptions options) + { + ScriptAssemblySettings settings = CreateEditorScriptAssemblySettings(EditorScriptCompilationOptions.BuildingForEditor | options); + var targetAssemblies = EditorBuildRules.GetTargetAssembliesWithScriptsHashSet(allScripts, projectDirectory, customTargetAssemblies, settings); + + return targetAssemblies; + } + public ScriptAssembly[] GetAllScriptAssembliesForLanguage(EditorScriptCompilationOptions additionalOptions) where T : SupportedLanguage { var assemblies = GetAllScriptAssemblies(EditorScriptCompilationOptions.BuildingForEditor).Where(a => a.Language.GetType() == typeof(T)).ToArray(); @@ -1661,6 +1692,7 @@ public ScriptAssembly[] GetAllScriptAssemblies(EditorScriptCompilationOptions op return EditorBuildRules.GetAllScriptAssemblies(allScripts, projectDirectory, settings, assemblies, runScriptUpdaterAssemblies); } + // TODO: Get rid of calls to this method and ensure that the defines are always setup correctly at all times. private static void UpdateAllTargetAssemblyDefines(EditorBuildRules.TargetAssembly[] customScriptAssemblies, EditorBuildRules.TargetAssembly[] predefinedTargetAssemblies, Dictionary assetPathVersionMetaDatas, ScriptAssemblySettings settings) { var allTargetAssemblies = (customScriptAssemblies ?? new EditorBuildRules.TargetAssembly[0]) @@ -1727,6 +1759,17 @@ private static void SetTargetAssemblyDefines(EditorBuildRules.TargetAssembly tar continue; } + if (string.IsNullOrEmpty(targetAssemblyVersionDefines[i].expression)) + { + var define = targetAssemblyVersionDefines[i].define; + if (!string.IsNullOrEmpty(define)) + { + defines[populatedVersionDefinesCount] = define; + populatedVersionDefinesCount++; + } + continue; + } + var versionDefineExpression = semVersionRangesFactory.GetExpression(targetAssemblyVersionDefines[i].expression); var assetPathVersionMetaData = assetPathVersionMetaDatas[targetAssemblyVersionDefines[i].name]; var semVersion = SemVersionParser.Parse(assetPathVersionMetaData); @@ -1837,6 +1880,18 @@ static AssemblyFlags ToAssemblyFlags(Compilation.AssemblyBuilderFlags assemblyBu return assemblyFlags; } + static EditorBuildRules.UnityReferencesOptions ToUnityReferencesOptions(ReferencesOptions options) + { + var result = EditorBuildRules.UnityReferencesOptions.ExcludeModules; + + if ((options & ReferencesOptions.UseEngineModules) == ReferencesOptions.UseEngineModules) + { + result = EditorBuildRules.UnityReferencesOptions.None; + } + + return result; + } + ScriptAssembly InitializeScriptAssemblyWithoutReferencesAndDefines(Compilation.AssemblyBuilder assemblyBuilder) { var scriptFiles = assemblyBuilder.scriptPaths.Select(p => AssetPath.Combine(projectDirectory, p)).ToArray(); @@ -1861,8 +1916,9 @@ public ScriptAssembly CreateScriptAssembly(Compilation.AssemblyBuilder assemblyB var scriptAssembly = InitializeScriptAssemblyWithoutReferencesAndDefines(assemblyBuilder); var options = ToEditorScriptCompilationOptions(assemblyBuilder.flags); + var referencesOptions = ToUnityReferencesOptions(assemblyBuilder.referencesOptions); - var references = GetAssemblyBuilderDefaultReferences(scriptAssembly, options); + var references = GetAssemblyBuilderDefaultReferences(scriptAssembly, options, referencesOptions); if (assemblyBuilder.additionalReferences != null && assemblyBuilder.additionalReferences.Length > 0) references = references.Concat(assemblyBuilder.additionalReferences).ToArray(); @@ -1881,12 +1937,13 @@ public ScriptAssembly CreateScriptAssembly(Compilation.AssemblyBuilder assemblyB return scriptAssembly; } - string[] GetAssemblyBuilderDefaultReferences(ScriptAssembly scriptAssembly, EditorScriptCompilationOptions options) + string[] GetAssemblyBuilderDefaultReferences(ScriptAssembly scriptAssembly, EditorScriptCompilationOptions options, EditorBuildRules.UnityReferencesOptions unityReferencesOptions) { bool buildingForEditor = (scriptAssembly.Flags & AssemblyFlags.EditorOnly) == AssemblyFlags.EditorOnly; var monolithicEngineAssemblyPath = InternalEditorUtility.GetMonolithicEngineAssemblyPath(); - var unityReferences = EditorBuildRules.GetUnityReferences(scriptAssembly, unityAssemblies, options, EditorBuildRules.UnityReferencesOptions.ExcludeModules); + + var unityReferences = EditorBuildRules.GetUnityReferences(scriptAssembly, unityAssemblies, options, unityReferencesOptions); var customReferences = EditorBuildRules.GetCompiledCustomAssembliesReferences(scriptAssembly, customTargetAssemblies, GetCompileScriptsOutputDirectory()); var precompiledReferences = EditorBuildRules.GetPrecompiledReferences(scriptAssembly, EditorBuildRules.TargetAssemblyType.Custom, options, EditorBuildRules.EditorCompatibility.CompatibleWithEditor, precompiledAssemblies); @@ -1894,7 +1951,10 @@ string[] GetAssemblyBuilderDefaultReferences(ScriptAssembly scriptAssembly, Edit string[] editorReferences = buildingForEditor ? ModuleUtils.GetAdditionalReferencesForUserScripts() : new string[0]; var references = new List(); - references.Add(monolithicEngineAssemblyPath); + + if (unityReferencesOptions == EditorBuildRules.UnityReferencesOptions.ExcludeModules) + references.Add(monolithicEngineAssemblyPath); + references.AddRange(unityReferences.Concat(customReferences).Concat(precompiledReferences).Concat(editorReferences).Concat(additionalReferences)); return references.ToArray(); @@ -1904,8 +1964,10 @@ public string[] GetAssemblyBuilderDefaultReferences(AssemblyBuilder assemblyBuil { var scriptAssembly = InitializeScriptAssemblyWithoutReferencesAndDefines(assemblyBuilder); var options = ToEditorScriptCompilationOptions(assemblyBuilder.flags); + var referencesOptions = ToUnityReferencesOptions(assemblyBuilder.referencesOptions); + - var references = GetAssemblyBuilderDefaultReferences(scriptAssembly, options); + var references = GetAssemblyBuilderDefaultReferences(scriptAssembly, options, referencesOptions); return references; } diff --git a/Editor/Mono/Scripting/ScriptCompilation/ScriptAssembly.cs b/Editor/Mono/Scripting/ScriptCompilation/ScriptAssembly.cs index 443abf9dd9..ae6e41cb79 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/ScriptAssembly.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/ScriptAssembly.cs @@ -79,6 +79,8 @@ public MonoIsland ToMonoIsland(EditorScriptCompilationOptions options, string bu bool buildingForEditor = (options & EditorScriptCompilationOptions.BuildingForEditor) == EditorScriptCompilationOptions.BuildingForEditor; bool developmentBuild = (options & EditorScriptCompilationOptions.BuildingDevelopmentBuild) == EditorScriptCompilationOptions.BuildingDevelopmentBuild; + bool isEditorAssembly = (Flags & AssemblyFlags.EditorOnly) == AssemblyFlags.EditorOnly; + var references = ScriptAssemblyReferences.Select(a => AssetPath.Combine(a.OutputDirectory, a.Filename)); var referencesArray = references.Concat(References).ToArray(); @@ -95,6 +97,7 @@ public MonoIsland ToMonoIsland(EditorScriptCompilationOptions options, string bu return new MonoIsland(BuildTarget, buildingForEditor, + isEditorAssembly, developmentBuild, CompilerOptions.AllowUnsafeCode, ApiCompatibilityLevel, diff --git a/Editor/Mono/Scripting/ScriptCompilation/Utility.cs b/Editor/Mono/Scripting/ScriptCompilation/Utility.cs index 9c136cee25..3c05731af4 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/Utility.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/Utility.cs @@ -100,5 +100,36 @@ public static string ReadTextAsset(string path) // Support out of project reading of files for tests. return System.IO.File.ReadAllText(path); } + + public static string FileNameWithoutExtension(string path) + { + if (string.IsNullOrEmpty(path)) + { + return ""; + } + + var indexOfDot = -1; + var indexOfSlash = 0; + for (var i = path.Length - 1; i >= 0; i--) + { + if (indexOfDot == -1 && path[i] == '.') + { + indexOfDot = i; + } + + if (indexOfSlash == 0 && path[i] == '/' || path[i] == '\\') + { + indexOfSlash = i + 1; + break; + } + } + + if (indexOfDot == -1) + { + indexOfDot = path.Length - 1; + } + + return path.Substring(indexOfSlash, indexOfDot - indexOfSlash); + } } } diff --git a/Editor/Mono/Scripting/ScriptCompilers.cs b/Editor/Mono/Scripting/ScriptCompilers.cs index d47baaac90..7e87f02589 100644 --- a/Editor/Mono/Scripting/ScriptCompilers.cs +++ b/Editor/Mono/Scripting/ScriptCompilers.cs @@ -23,7 +23,8 @@ internal struct MonoIsland { public readonly BuildTarget _target; public readonly bool _development_player; - public readonly bool _editor; + public readonly bool _buildingForEditor; + public readonly bool _isEditorAssembly; public readonly bool _allowUnsafeCode; public readonly ApiCompatibilityLevel _api_compatibility_level; public readonly string[] _files; @@ -36,7 +37,8 @@ public MonoIsland(BuildTarget target, ApiCompatibilityLevel api_compatibility_le { _target = target; _development_player = false; - _editor = false; + _buildingForEditor = false; + _isEditorAssembly = false; _allowUnsafeCode = allowUnsafeCode; _api_compatibility_level = api_compatibility_level; _files = files; @@ -46,11 +48,12 @@ public MonoIsland(BuildTarget target, ApiCompatibilityLevel api_compatibility_le _responseFiles = null; } - public MonoIsland(BuildTarget target, bool editor, bool development_player, bool allowUnsafeCode, ApiCompatibilityLevel api_compatibility_level, string[] files, string[] references, string[] defines, string output) + public MonoIsland(BuildTarget target, bool buildingForEditor, bool isEditorAssembly, bool development_player, bool allowUnsafeCode, ApiCompatibilityLevel api_compatibility_level, string[] files, string[] references, string[] defines, string output) { _target = target; _development_player = development_player; - _editor = editor; + _buildingForEditor = buildingForEditor; + _isEditorAssembly = isEditorAssembly; _allowUnsafeCode = allowUnsafeCode; _api_compatibility_level = api_compatibility_level; _files = files; @@ -60,8 +63,8 @@ public MonoIsland(BuildTarget target, bool editor, bool development_player, bool _responseFiles = null; } - public MonoIsland(BuildTarget target, bool editor, bool development_player, bool allowUnsafeCode, ApiCompatibilityLevel api_compatibility_level, string[] files, string[] references, string[] defines, string output, string[] responseFiles) - : this(target, editor, development_player, allowUnsafeCode, api_compatibility_level, files, references, defines, output) + public MonoIsland(BuildTarget target, bool buildingForEditor, bool isEditorAssembly, bool development_player, bool allowUnsafeCode, ApiCompatibilityLevel api_compatibility_level, string[] files, string[] references, string[] defines, string output, string[] responseFiles) + : this(target, buildingForEditor, isEditorAssembly, development_player, allowUnsafeCode, api_compatibility_level, files, references, defines, output) { _responseFiles = responseFiles; } diff --git a/Editor/Mono/Selection.bindings.cs b/Editor/Mono/Selection.bindings.cs index ef5daa3a2a..f266c13aed 100644 --- a/Editor/Mono/Selection.bindings.cs +++ b/Editor/Mono/Selection.bindings.cs @@ -125,5 +125,9 @@ extern public static string[] assetGUIDs [NativeMethod("GetSelectedAssetGUIDStrings")] get; } + + [StaticAccessor("Selection", StaticAccessorType.DoubleColon)] + [NativeName("SelectionCount")] + internal extern static int count { get; } } } diff --git a/Editor/Mono/SerializedProperty.bindings.cs b/Editor/Mono/SerializedProperty.bindings.cs index b83c44b330..cef97214bb 100644 --- a/Editor/Mono/SerializedProperty.bindings.cs +++ b/Editor/Mono/SerializedProperty.bindings.cs @@ -653,6 +653,19 @@ public bool isDefaultOverride [NativeName("IsDefaultOverride")] private extern bool GetIsDefaultOverrideInternal(); + // Is property a driven property (using RectTransform driven properties)? (RO) + internal bool isDrivenRectTransformProperty + { + get + { + Verify(VerifyFlags.IteratorNotAtEnd); + return GetIsDrivenRectTransformPropertyInternal(); + } + } + + [NativeName("IsDrivenRectTransformProperty")] + private extern bool GetIsDrivenRectTransformPropertyInternal(); + // Type of this property (RO). public SerializedPropertyType propertyType { @@ -868,8 +881,7 @@ public int objectReferenceInstanceIDValue { get { - UnityObject obj = objectReferenceValue; - return obj ? obj.GetInstanceID() : 0; + return GetPPtrValueFromInstanceIDInternal(); } set { @@ -878,6 +890,9 @@ public int objectReferenceInstanceIDValue } } + [NativeName("GetPPtrInstanceID")] + private extern int GetPPtrValueFromInstanceIDInternal(); + [FreeFunction(Name = "SerializedPropertyBindings::SetPPtrValueFromInstanceIDInternal", HasExplicitThis = true)] private extern void SetPPtrValueFromInstanceIDInternal(int instanceID); diff --git a/Editor/Mono/Settings/Providers/AssetSettingsProvider.cs b/Editor/Mono/Settings/Providers/AssetSettingsProvider.cs index 01641a520a..2fa6d5a7a5 100644 --- a/Editor/Mono/Settings/Providers/AssetSettingsProvider.cs +++ b/Editor/Mono/Settings/Providers/AssetSettingsProvider.cs @@ -68,6 +68,10 @@ public static AssetSettingsProvider CreateProviderFromResourcePath(string settin public override void OnActivate(string searchContext, VisualElement rootElement) { + if (settingsEditor != null) + { + UnityEngine.Object.DestroyImmediate(settingsEditor); + } settingsEditor = m_EditorCreator?.Invoke(); base.OnActivate(searchContext, rootElement); } @@ -78,8 +82,8 @@ public override void OnDeactivate() { var info = settingsEditor.GetType().GetMethod("OnDisable"); info?.Invoke(settingsEditor, null); + UnityEngine.Object.DestroyImmediate(settingsEditor); } - settingsEditor = null; base.OnDeactivate(); } diff --git a/Editor/Mono/Settings/SettingsWindow.cs b/Editor/Mono/Settings/SettingsWindow.cs index 3b4521f886..bff9f6ddc1 100644 --- a/Editor/Mono/Settings/SettingsWindow.cs +++ b/Editor/Mono/Settings/SettingsWindow.cs @@ -29,7 +29,6 @@ internal class SettingsWindow : EditorWindow, IHasCustomMenu private string m_SearchText; private bool m_SearchFieldGiveFocus; - private static class ImguiStyles { public static readonly GUIStyle header = "SettingsHeader"; @@ -46,6 +45,11 @@ private static class Styles public static float s_DefaultLabelWidth => Styles.window.GetFloat("-unity-label-width"); public static float s_DefaultLayoutMaxWidth => Styles.window.GetFloat("-unity-max-layout-width"); + public SettingsWindow() + : this(SettingsScope.Project) + { + } + public SettingsWindow(SettingsScope scope) { m_Scope = scope; @@ -107,10 +111,15 @@ internal void OnEnable() Undo.undoRedoPerformed -= OnUndoRedoPerformed; Undo.undoRedoPerformed += OnUndoRedoPerformed; + + EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; + EditorApplication.playModeStateChanged += OnPlayModeStateChanged; } internal void OnDisable() { + m_TreeView.currentProvider?.OnDeactivate(); + if (m_Splitter != null && m_Splitter.childCount >= 1) { var splitLeft = m_Splitter.Children().First(); @@ -123,6 +132,7 @@ internal void OnDisable() SettingsService.settingsProviderChanged -= OnSettingsProviderChanged; Undo.undoRedoPerformed -= OnUndoRedoPerformed; + EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; } internal void OnInspectorUpdate() @@ -130,11 +140,26 @@ internal void OnInspectorUpdate() m_TreeView.currentProvider?.OnInspectorUpdate(); } - void OnUndoRedoPerformed() + private void OnUndoRedoPerformed() { Repaint(); } + private void OnPlayModeStateChanged(PlayModeStateChange state) + { + if (m_TreeView.currentProvider != null) + { + if (state == PlayModeStateChange.ExitingPlayMode) + { + ProviderChanged(m_TreeView.currentProvider, null); + } + else if (state == PlayModeStateChange.EnteredEditMode) + { + RestoreSelection(); + } + } + } + private void PrintProviderKeywords() { var sb = new StringBuilder(); @@ -303,7 +328,7 @@ private void DrawControls() private void DrawTitleBar() { - GUILayout.BeginHorizontal(GUILayout.MaxWidth(s_DefaultLayoutMaxWidth)); + GUILayout.BeginHorizontal(); GUILayout.Space(Styles.settingsPanel.GetFloat(StyleCatalogKeyword.marginLeft)); var headerContent = new GUIContent(m_TreeView.currentProvider.label, Styles.header.GetBool("-unity-show-icon") ? m_TreeView.currentProvider.icon : null); GUILayout.Label(headerContent, ImguiStyles.header, GUILayout.MaxHeight(Styles.header.GetFloat("max-height"))); @@ -362,6 +387,7 @@ internal static SettingsWindow Show(SettingsScope scopes, string settingsPath = { var settingsWindow = FindWindowByScope(scopes) ?? Create(scopes); settingsWindow.Show(); + settingsWindow.Focus(); if (settingsPath != null) { @@ -384,7 +410,7 @@ public GUIScope(float layoutMaxWidth) { m_LabelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = s_DefaultLabelWidth; - GUILayout.BeginHorizontal(GUILayout.MaxWidth(layoutMaxWidth)); + GUILayout.BeginHorizontal(); GUILayout.Space(Styles.settingsPanel.GetFloat(StyleCatalogKeyword.marginLeft)); GUILayout.BeginVertical(); GUILayout.Space(Styles.settingsPanel.GetFloat(StyleCatalogKeyword.marginTop)); diff --git a/Editor/Mono/SettingsWindow/FogEditor.cs b/Editor/Mono/SettingsWindow/FogEditor.cs index 9efc2275e1..4c8d788b9f 100644 --- a/Editor/Mono/SettingsWindow/FogEditor.cs +++ b/Editor/Mono/SettingsWindow/FogEditor.cs @@ -16,7 +16,7 @@ internal class Styles public static readonly GUIContent FogLinearStart = EditorGUIUtility.TrTextContent("Start", "Controls the distance from the camera where the fog will start in the Scene."); public static readonly GUIContent FogLinearEnd = EditorGUIUtility.TrTextContent("End", "Controls the distance from the camera where the fog will completely obscure objects in the Scene."); public static readonly GUIContent FogEnable = EditorGUIUtility.TrTextContent("Fog", "Specifies whether fog is used in the Scene or not."); - public static readonly GUIContent FogColor = EditorGUIUtility.TrTextContent("Color", "Controls the color of that fog drawn in the Scene."); + public static readonly GUIContent FogColor = EditorGUIUtility.TrTextContent("Color", "Controls the color of the fog drawn in the Scene."); public static readonly GUIContent FogMode = EditorGUIUtility.TrTextContent("Mode", "Controls the mathematical function determining the way fog accumulates with distance from the camera. Options are Linear, Exponential, and Exponential Squared."); } diff --git a/Editor/Mono/SettingsWindow/GraphicsSettingsEditors.cs b/Editor/Mono/SettingsWindow/GraphicsSettingsEditors.cs index de9d885c51..db41b4dd2b 100644 --- a/Editor/Mono/SettingsWindow/GraphicsSettingsEditors.cs +++ b/Editor/Mono/SettingsWindow/GraphicsSettingsEditors.cs @@ -248,7 +248,7 @@ internal partial class Styles public static readonly GUIContent lightmapPlain = EditorGUIUtility.TrTextContent("Baked Non-Directional", "Include support for baked non-directional lightmaps."); public static readonly GUIContent lightmapDirCombined = EditorGUIUtility.TrTextContent("Baked Directional", "Include support for baked directional lightmaps."); public static readonly GUIContent lightmapKeepShadowMask = EditorGUIUtility.TrTextContent("Baked Shadowmask", "Include support for baked shadow occlusion."); - public static readonly GUIContent lightmapKeepSubtractive = EditorGUIUtility.TrTextContent("Baked Subtractive", "Include support for baked substractive lightmaps."); + public static readonly GUIContent lightmapKeepSubtractive = EditorGUIUtility.TrTextContent("Baked Subtractive", "Include support for baked subtractive lightmaps."); public static readonly GUIContent lightmapDynamicPlain = EditorGUIUtility.TrTextContent("Realtime Non-Directional", "Include support for realtime non-directional lightmaps."); public static readonly GUIContent lightmapDynamicDirCombined = EditorGUIUtility.TrTextContent("Realtime Directional", "Include support for realtime directional lightmaps."); public static readonly GUIContent lightmapFromScene = EditorGUIUtility.TrTextContent("Import From Current Scene", "Calculate lightmap modes used by the current scene."); @@ -584,7 +584,7 @@ internal partial class Styles public static readonly GUIContent reflectionProbeBlending = EditorGUIUtility.TrTextContent("Reflection Probes Blending"); public static readonly GUIContent detailNormalMap = EditorGUIUtility.TrTextContent("Detail Normal Map"); public static readonly GUIContent cascadedShadowMaps = EditorGUIUtility.TrTextContent("Cascaded Shadows"); - public static readonly GUIContent prefer32BitShadowMaps = EditorGUIUtility.TrTextContent("Prefer 32 bit shadow maps"); + public static readonly GUIContent prefer32BitShadowMaps = EditorGUIUtility.TrTextContent("Prefer 32-bit shadow maps"); public static readonly GUIContent semitransparentShadows = EditorGUIUtility.TrTextContent("Enable Semitransparent Shadows"); public static readonly GUIContent enableLPPV = EditorGUIUtility.TrTextContent("Enable Light Probe Proxy Volume"); public static readonly GUIContent renderingPath = EditorGUIUtility.TrTextContent("Rendering Path"); diff --git a/Editor/Mono/ShaderUtil.bindings.cs b/Editor/Mono/ShaderUtil.bindings.cs index db83b07c49..8b7baeebf8 100644 --- a/Editor/Mono/ShaderUtil.bindings.cs +++ b/Editor/Mono/ShaderUtil.bindings.cs @@ -7,6 +7,7 @@ using UnityEditor.Rendering; using UnityEngine; using UnityEngine.Bindings; +using UnityEngine.Rendering; using UnityEngine.Scripting; using ShaderPlatform = UnityEngine.Rendering.GraphicsDeviceType; using TextureDimension = UnityEngine.Rendering.TextureDimension; @@ -89,9 +90,17 @@ public override int GetHashCode() } } + internal struct ShaderVariantEntriesData + { + public int[] passTypes; + public string[] keywordLists; + public string[] remainingKeywords; + } + [NativeHeader("Editor/Mono/ShaderUtil.bindings.h")] [NativeHeader("Editor/Src/ShaderData.h")] [NativeHeader("Editor/Src/ShaderMenu.h")] + [NativeHeader("Runtime/Shaders/GpuPrograms/GpuProgramManager.h")] public partial class ShaderUtil { public enum ShaderPropertyType @@ -251,6 +260,19 @@ public static void UpdateShaderAsset(Shader shader, string source) extern internal static int GetCurrentShaderVariantCollectionVariantCount(); extern internal static bool AddNewShaderToCollection(Shader shader, ShaderVariantCollection collection); + private static extern ShaderVariantEntriesData GetShaderVariantEntriesFilteredInternal([NotNull] Shader shader, int maxEntries, string[] filterKeywords, ShaderVariantCollection excludeCollection); + + internal static void GetShaderVariantEntriesFiltered(Shader shader, int maxEntries, string[] filterKeywords, ShaderVariantCollection excludeCollection, out int[] passTypes, out string[] keywordLists, out string[] remainingKeywords) + { + ShaderVariantEntriesData data = GetShaderVariantEntriesFilteredInternal(shader, maxEntries, filterKeywords, excludeCollection); + passTypes = data.passTypes; + keywordLists = data.keywordLists; + remainingKeywords = data.remainingKeywords; + } + + extern internal static string[] GetAllGlobalKeywords(); + extern internal static string[] GetShaderGlobalKeywords([NotNull] Shader shader); + extern internal static string[] GetShaderLocalKeywords([NotNull] Shader shader); [FreeFunction] public static extern ShaderInfo[] GetAllShaderInfo(); @@ -260,6 +282,13 @@ public static void UpdateShaderAsset(Shader shader, string source) [FreeFunction] extern internal static int GetShaderActiveSubshaderIndex([NotNull] Shader shader); [FreeFunction] extern internal static int GetShaderSubshaderCount([NotNull] Shader shader); [FreeFunction] extern internal static int GetShaderTotalPassCount([NotNull] Shader shader, int subShaderIndex); + + extern public static bool anythingCompiling { get; } + extern public static bool allowAsyncCompilation { get; set; } + extern public static void SetAsyncCompilation([NotNull] CommandBuffer cmd, bool allow); + extern public static void RestoreAsyncCompilation([NotNull] CommandBuffer cmd); + extern public static bool IsPassCompiled([NotNull] Material material, int pass); + extern public static void CompilePass([NotNull] Material material, int pass, bool forceSync = false); } } diff --git a/Editor/Mono/SpriteEditor/SpriteEditorWindow.cs b/Editor/Mono/SpriteEditor/SpriteEditorWindow.cs index a196a4f862..455adbae01 100644 --- a/Editor/Mono/SpriteEditor/SpriteEditorWindow.cs +++ b/Editor/Mono/SpriteEditor/SpriteEditorWindow.cs @@ -47,7 +47,6 @@ private class SpriteEditorWindowStyles private const float k_WarningMessageHeight = 40f; private const float k_ModuleListWidth = 90f; - public static SpriteEditorWindow s_Instance; public bool m_ResetOnNextRepaint; private List m_RectsCache; @@ -74,6 +73,7 @@ private class SpriteEditorWindowStyles [SerializeField] private string m_SelectedSpriteRectGUID; + internal Func onHandleApplyRevertDialog = ShowHandleApplyRevertDialog; public static void GetWindow() { EditorWindow.GetWindow(); @@ -236,7 +236,6 @@ void OnEnable() { minSize = new Vector2(360, 200); titleContent = SpriteEditorWindowStyles.spriteEditorWindowTitle; - s_Instance = this; m_UndoSystem.RegisterUndoCallback(UndoRedoPerformed); EditorApplication.modifierKeysChanged += ModifierKeysChanged; @@ -318,7 +317,6 @@ private void OnDisable() EditorApplication.modifierKeysChanged -= ModifierKeysChanged; EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; EditorApplication.quitting -= OnEditorApplicationQuit; - s_Instance = null; if (m_OutlineTexture != null) { @@ -350,12 +348,17 @@ void OnEditorApplicationQuit() String.Format(SpriteEditorWindowStyles.applyRevertDialogContent.text, m_SelectedAssetPath)); } + static bool ShowHandleApplyRevertDialog(string dialogTitle, string dialogContent) + { + return EditorUtility.DisplayDialog(dialogTitle, dialogContent, + SpriteEditorWindowStyles.applyButtonLabel.text, SpriteEditorWindowStyles.revertButtonLabel.text); + } + void HandleApplyRevertDialog(string dialogTitle, string dialogContent) { if (textureIsDirty && IsSpriteDataProviderValid()) { - if (EditorUtility.DisplayDialog(dialogTitle, dialogContent, - SpriteEditorWindowStyles.applyButtonLabel.text, SpriteEditorWindowStyles.revertButtonLabel.text)) + if (onHandleApplyRevertDialog(dialogTitle, dialogContent)) DoApply(); else DoRevert(); @@ -380,7 +383,7 @@ void RefreshRects() InitSelectedSpriteRect(); } - private void Update() + private void UpdateAssetSelectionChange() { if (m_ResetOnNextRepaint || selectedProviderChanged) { @@ -403,6 +406,7 @@ private void RebuildCache() private void DoTextureAndModulesGUI() { InitStyles(); + UpdateAssetSelectionChange(); if (!activeDataProviderSelected) { using (new EditorGUI.DisabledScope(true)) @@ -636,7 +640,7 @@ private void HandleFrameSelected() void UpdateSelectedSpriteRect(Sprite sprite) { - if (m_RectsCache == null) + if (m_RectsCache == null || sprite == null || sprite.Equals(null)) return; var spriteGUID = sprite.GetSpriteID(); @@ -706,9 +710,6 @@ public void DoTextureReimport(string path) internal void SetupModule(int newModuleIndex) { - if (s_Instance == null) - return; - m_ModuleViewElement.Clear(); if (m_RegisteredModules.Count > newModuleIndex) { @@ -975,10 +976,12 @@ public VisualElement GetMainVisualContainer() static internal void OnTextureReimport(string path) { - if (s_Instance != null && s_Instance.m_SelectedAssetPath == path) + UnityEngine.Object[] wins = Resources.FindObjectsOfTypeAll(typeof(SpriteEditorWindow)); + SpriteEditorWindow win = wins.Length > 0 ? (EditorWindow)(wins[0]) as SpriteEditorWindow : null; + if (win != null && win.m_SelectedAssetPath == path) { - s_Instance.m_ResetOnNextRepaint = true; - s_Instance.Repaint(); + win.m_ResetOnNextRepaint = true; + win.Repaint(); } } diff --git a/Editor/Mono/SyncRiderProject.cs b/Editor/Mono/SyncRiderProject.cs index d65f4f125d..2d41deb3ab 100644 --- a/Editor/Mono/SyncRiderProject.cs +++ b/Editor/Mono/SyncRiderProject.cs @@ -44,13 +44,13 @@ static RiderInfo[] CollectAllRiderPathsLinux() if (string.IsNullOrEmpty(home)) return new RiderInfo[0]; const string pathToBuildTxt = "../../build.txt"; + //$Home/.local/share/JetBrains/Toolbox/apps/Rider/ch-0/173.3994.1125/bin/rider.sh //$Home/.local/share/JetBrains/Toolbox/apps/Rider/ch-0/.channel.settings.json var toolboxRiderRootPath = Path.Combine(home, @".local/share/JetBrains/Toolbox/apps/Rider"); var paths = CollectPathsFromToolbox(toolboxRiderRootPath, "bin", "rider.sh", false) .Select(a => new RiderInfo(GetBuildNumber(Path.Combine(a, pathToBuildTxt)), a, true)).ToList(); - // $Home/.local/share/applications/jetbrains-rider.desktop var shortcut = new FileInfo(Path.Combine(home, @".local/share/applications/jetbrains-rider.desktop")); @@ -89,8 +89,7 @@ static RiderInfo[] CollectRiderInfosMac() var home = Environment.GetEnvironmentVariable("HOME"); if (!string.IsNullOrEmpty(home)) { - var toolboxRiderRootPath = - Path.Combine(home, @"Library/Application Support/JetBrains/Toolbox/apps/Rider"); + var toolboxRiderRootPath = Path.Combine(home, @"Library/Application Support/JetBrains/Toolbox/apps/Rider"); var paths = CollectPathsFromToolbox(toolboxRiderRootPath, "", "Rider*.app", true) .Select(a => new RiderInfo(GetBuildNumber(Path.Combine(a, pathToBuildTxt)), a, true)); results.AddRange(paths); @@ -113,10 +112,8 @@ static RiderInfo[] CollectRiderInfosWindows() var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); var toolboxRiderRootPath = Path.Combine(localAppData, @"JetBrains\Toolbox\apps\Rider"); - var installPathsToolbox = - CollectPathsFromToolbox(toolboxRiderRootPath, "bin", "rider64.exe", false).ToList(); - var installInfosToolbox = installPathsToolbox - .Select(a => new RiderInfo(GetBuildNumber(Path.Combine(a, pathToBuildTxt)), a, true)).ToList(); + var installPathsToolbox = CollectPathsFromToolbox(toolboxRiderRootPath, "bin", "rider64.exe", false).ToList(); + var installInfosToolbox = installPathsToolbox.Select(a => new RiderInfo(GetBuildNumber(Path.Combine(a, pathToBuildTxt)), a, true)).ToList(); var installPaths = new List(); const string registryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"; @@ -124,8 +121,7 @@ static RiderInfo[] CollectRiderInfosWindows() const string wowRegistryKey = @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"; CollectPathsFromRegistry(wowRegistryKey, installPaths); - var installInfos = installPaths - .Select(a => new RiderInfo(GetBuildNumber(Path.Combine(a, pathToBuildTxt)), a, false)).ToList(); + var installInfos = installPaths.Select(a => new RiderInfo(GetBuildNumber(Path.Combine(a, pathToBuildTxt)), a, false)).ToList(); installInfos.AddRange(installInfosToolbox); return installInfos.ToArray(); @@ -176,7 +172,6 @@ public static RiderInfo[] GetAllRiderPaths() Debug.LogException(e); } - return new RiderInfo[0]; } @@ -189,29 +184,49 @@ static string[] CollectPathsFromToolbox( if (!Directory.Exists(toolboxRiderRootPath)) return new string[0]; - var channelFiles = Directory.GetDirectories(toolboxRiderRootPath) - .Select(b => Path.Combine(b, ".channel.settings.json")).Where(File.Exists).ToArray(); - - var paths = channelFiles.SelectMany(a => { + var channelDirs = Directory.GetDirectories(toolboxRiderRootPath); + var paths = channelDirs.SelectMany(channelDir => + { try { - var channelDir = Path.GetDirectoryName(a); - var json = File.ReadAllText(a).Replace("active-application", "active_application"); - var toolbox = ToolboxInstallData.FromJson(json); - var builds = toolbox.active_application.builds; - if (builds.Any()) + // use history.json - last entry stands for the active build https://jetbrains.slack.com/archives/C07KNP99D/p1547807024066500?thread_ts=1547731708.057700&cid=C07KNP99D + var historyFile = Path.Combine(channelDir, ".history.json"); + if (File.Exists(historyFile)) + { + var json = File.ReadAllText(historyFile); + var build = ToolboxHistory.GetLatestBuildFromJson(json); + if (build != null) + { + var buildDir = Path.Combine(channelDir, build); + var executablePaths = GetExecutablePaths(dirName, searchPattern, isMac, buildDir); + if (executablePaths.Any()) + return executablePaths; + } + } + + var channelFile = Path.Combine(channelDir, ".channel.settings.json"); + if (File.Exists(channelFile)) { - var build = builds.First(); - var folder = Path.Combine(Path.Combine(channelDir, build), dirName); - if (!isMac) - return new[] {Path.Combine(folder, searchPattern)}; - return new DirectoryInfo(folder).GetDirectories(searchPattern).Select(f => f.FullName); + var json = File.ReadAllText(channelFile).Replace("active-application", "active_application"); + var build = ToolboxInstallData.GetLatestBuildFromJson(json); + if (build != null) + { + var buildDir = Path.Combine(channelDir, build); + var executablePaths = GetExecutablePaths(dirName, searchPattern, isMac, buildDir); + if (executablePaths.Any()) + return executablePaths; + } } + + // changes in toolbox json files format may brake the logic above, so return all found Rider installations + return Directory.GetDirectories(channelDir) + .SelectMany(buildDir => GetExecutablePaths(dirName, searchPattern, isMac, buildDir)); } catch (Exception e) { - Debug.LogException(e); - Debug.LogWarning("Failed to get RiderPath via .channel.settings.json"); + // do not write to Debug.Log, just log it. + Console.WriteLine(e.Message); + Console.WriteLine($"Failed to get RiderPath from {channelDir}"); } return new string[0]; @@ -221,14 +236,65 @@ static string[] CollectPathsFromToolbox( return paths; } + static string[] GetExecutablePaths(string dirName, string searchPattern, bool isMac, string buildDir) + { + var folder = Path.Combine(buildDir, dirName); + if (!isMac) + return new[] { Path.Combine(folder, searchPattern) }.Where(File.Exists).ToArray(); + return new DirectoryInfo(folder).GetDirectories(searchPattern).Select(f => f.FullName) + .Where(Directory.Exists).ToArray(); + } + + [Serializable] + class ToolboxHistory + { + public List history = null; + + public static string GetLatestBuildFromJson(string json) + { + try + { + return JsonUtility.FromJson(json).history.LastOrDefault()?.item.build; + } + catch (Exception) + { + Console.WriteLine($"Failed to get latest build from json {json}"); + } + return null; + } + } + + [Serializable] + class ItemNode + { + public BuildNode item = null; + } + + [Serializable] + class BuildNode + { + public string build = null; + } + [Serializable] class ToolboxInstallData { public ActiveApplication active_application = null; - public static ToolboxInstallData FromJson(string json) + public static string GetLatestBuildFromJson(string json) { - return JsonUtility.FromJson(json); + try + { + var toolbox = JsonUtility.FromJson(json); + var builds = toolbox.active_application.builds; + if (builds != null && builds.Any()) + return builds.First(); + } + catch (Exception) + { + Console.WriteLine($"Failed to get latest build from json {json}"); + } + return null; } } diff --git a/Editor/Mono/UIElements/Controls/BindingExtensions.cs b/Editor/Mono/UIElements/Controls/BindingExtensions.cs index 9f048f14ad..52aaa02c51 100644 --- a/Editor/Mono/UIElements/Controls/BindingExtensions.cs +++ b/Editor/Mono/UIElements/Controls/BindingExtensions.cs @@ -676,8 +676,22 @@ internal static void UpdateElementStyle(VisualElement element, SerializedPropert if (element == null) return; + bool handlePrefabState = false; + + try + { + // This can throw if the serialized object changes type under our feet + handlePrefabState = prop.serializedObject.targetObjects.Length == 1 && + prop.isInstantiatedPrefab && + prop.prefabOverride; + } + catch (Exception) + { + return; + } + // Handle prefab state. - if (prop.serializedObject.targetObjects.Length == 1 && prop.isInstantiatedPrefab && prop.prefabOverride) + if (handlePrefabState) { if (!element.ClassListContains(prefabOverrideUssClassName)) { diff --git a/Editor/Mono/UIElements/Controls/CurveField.cs b/Editor/Mono/UIElements/Controls/CurveField.cs index 35e959fe01..6e4a24cc9a 100644 --- a/Editor/Mono/UIElements/Controls/CurveField.cs +++ b/Editor/Mono/UIElements/Controls/CurveField.cs @@ -56,14 +56,27 @@ public RenderMode renderMode if (renderMode == RenderMode.Mesh) { + m_ContentParent = new VisualElement(); + m_ContentParent.AddToClassList(contentUssClassName); + visualInput.Insert(0, m_ContentParent); + m_Content = new CurveFieldContent(); - m_Content.AddToClassList(contentUssClassName); - visualInput.Insert(0, m_Content); + m_ZeroIndicator = new VisualElement() {style = {height = 1, backgroundColor = Color.black}}; + m_ContentParent.Add(m_ZeroIndicator); + m_ContentParent.Add(m_Content); + m_Content.StretchToParentSize(); + m_ZeroIndicator.StretchToParentWidth(); } else { + m_ZeroIndicator.RemoveFromHierarchy(); + m_ZeroIndicator = null; + m_Content.RemoveFromHierarchy(); m_Content = null; + + m_ContentParent.RemoveFromHierarchy(); + m_ContentParent = null; } m_TextureDirty = true; @@ -110,6 +123,8 @@ public override AnimationCurve value } } CurveFieldContent m_Content; + VisualElement m_ZeroIndicator; + VisualElement m_ContentParent; public CurveField() : this(null) {} @@ -334,9 +349,10 @@ void FillCurveData() Vector3 scale = new Vector3(m_Content.layout.width, m_Content.layout.height); - vertices[0] = vertices[1] = Vector3.Scale(new Vector3(0, 1 - Mathf.InverseLerp(minValue, maxValue, valueCache[0]), 0), scale); + var yStartValue = (!Mathf.Approximately(minValue, maxValue)) ? 1.0f : 0.5f; + vertices[0] = vertices[1] = Vector3.Scale(new Vector3(0, yStartValue - Mathf.InverseLerp(minValue, maxValue, valueCache[0]), 0), scale); - Vector3 secondPoint = Vector3.Scale(new Vector3(1.0f / k_HorizontalCurveResolution, 1 - Mathf.InverseLerp(minValue, maxValue, valueCache[1]), 0), scale); + Vector3 secondPoint = Vector3.Scale(new Vector3(1.0f / k_HorizontalCurveResolution, yStartValue - Mathf.InverseLerp(minValue, maxValue, valueCache[1]), 0), scale); Vector3 prevDir = (secondPoint - vertices[0]).normalized; Vector3 norm = new Vector3(prevDir.y, -prevDir.x, 1); @@ -350,7 +366,7 @@ void FillCurveData() { vertices[i * 2] = vertices[i * 2 + 1] = currentPoint; - Vector3 nextPoint = Vector3.Scale(new Vector3(Mathf.InverseLerp(startTime, endTime, timeCache[i + 1]), 1 - Mathf.InverseLerp(minValue, maxValue, valueCache[i + 1]), 0), scale); + Vector3 nextPoint = Vector3.Scale(new Vector3(Mathf.InverseLerp(startTime, endTime, timeCache[i + 1]), yStartValue - Mathf.InverseLerp(minValue, maxValue, valueCache[i + 1]), 0), scale); Vector3 nextDir = (nextPoint - currentPoint).normalized; Vector3 dir = (prevDir + nextDir).normalized; @@ -391,6 +407,15 @@ void FillCurveData() } m_Mesh.triangles = indices; + + if (Mathf.Approximately(minValue, maxValue)) + { + m_ZeroIndicator.style.top = m_Content.layout.height * Mathf.InverseLerp(-1, 1, minValue); + } + else + { + m_ZeroIndicator.style.top = m_Content.layout.height * (yStartValue - Mathf.InverseLerp(minValue, maxValue, 0)); + } } void SetupMeshRepaint() @@ -414,52 +439,15 @@ void SetupStandardRepaint() int previewWidth = (int)visualInput.layout.width; int previewHeight = (int)visualInput.layout.height; - Rect rangeRect = new Rect(0, 0, 1, 1); + // The default range is (0,0,-1,-1), see AnimationCurvePreviewCache.cpp + // This will mimic the IMGUI curve since the range will be calculated by the CurvePreview if the range is at the default value... + Rect rangeRect = new Rect(0, 0, -1, -1); + // We assign the ranges if different than the Rect() default value if (ranges.width > 0 && ranges.height > 0) { rangeRect = ranges; } - else if (!m_ValueNull && rawValue.keys.Length > 1) - { - float xMin = Mathf.Infinity; - float yMin = Mathf.Infinity; - float xMax = -Mathf.Infinity; - float yMax = -Mathf.Infinity; - - for (int i = 0; i < rawValue.keys.Length; ++i) - { - float y = rawValue.keys[i].value; - float x = rawValue.keys[i].time; - if (xMin > x) - { - xMin = x; - } - if (xMax < x) - { - xMax = x; - } - if (yMin > y) - { - yMin = y; - } - if (yMax < y) - { - yMax = y; - } - } - - if (yMin == yMax) - { - yMax = yMin + 1; - } - if (xMin == xMax) - { - xMax = xMin + 1; - } - - rangeRect = Rect.MinMaxRect(xMin, yMin, xMax, yMax); - } if (previewHeight > 1 && previewWidth > 1) { diff --git a/Editor/Mono/UIElements/Controls/DoubleField.cs b/Editor/Mono/UIElements/Controls/DoubleField.cs index 15d3cfe29b..cb47b7e08d 100644 --- a/Editor/Mono/UIElements/Controls/DoubleField.cs +++ b/Editor/Mono/UIElements/Controls/DoubleField.cs @@ -70,10 +70,17 @@ public override void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, doub { double sensitivity = NumericFieldDraggerUtility.CalculateFloatDragSensitivity(startValue); float acceleration = NumericFieldDraggerUtility.Acceleration(speed == DeltaSpeed.Fast, speed == DeltaSpeed.Slow); - double v = parentDoubleField.value; + double v = StringToValue(text); v += NumericFieldDraggerUtility.NiceDelta(delta, acceleration) * sensitivity; v = MathUtils.RoundBasedOnMinimumDifference(v, sensitivity); - parentDoubleField.value = v; + if (parentDoubleField.isDelayed) + { + text = ValueToString(v); + } + else + { + parentDoubleField.value = v; + } } protected override string ValueToString(double v) diff --git a/Editor/Mono/UIElements/Controls/FloatField.cs b/Editor/Mono/UIElements/Controls/FloatField.cs index 534df1960f..9da4507103 100644 --- a/Editor/Mono/UIElements/Controls/FloatField.cs +++ b/Editor/Mono/UIElements/Controls/FloatField.cs @@ -66,10 +66,17 @@ public override void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, floa { double sensitivity = NumericFieldDraggerUtility.CalculateFloatDragSensitivity(startValue); float acceleration = NumericFieldDraggerUtility.Acceleration(speed == DeltaSpeed.Fast, speed == DeltaSpeed.Slow); - double v = parentFloatField.value; + double v = StringToValue(text); v += NumericFieldDraggerUtility.NiceDelta(delta, acceleration) * sensitivity; v = MathUtils.RoundBasedOnMinimumDifference(v, sensitivity); - parentFloatField.value = MathUtils.ClampToFloat(v); + if (parentFloatField.isDelayed) + { + text = ValueToString(MathUtils.ClampToFloat(v)); + } + else + { + parentFloatField.value = MathUtils.ClampToFloat(v); + } } protected override string ValueToString(float v) diff --git a/Editor/Mono/UIElements/Controls/GradientField.cs b/Editor/Mono/UIElements/Controls/GradientField.cs index 0ef68e6428..09e25884de 100644 --- a/Editor/Mono/UIElements/Controls/GradientField.cs +++ b/Editor/Mono/UIElements/Controls/GradientField.cs @@ -55,9 +55,12 @@ internal static Gradient GradientCopy(Gradient other) public new static readonly string ussClassName = "unity-gradient-field"; public new static readonly string labelUssClassName = ussClassName + "__label"; public new static readonly string inputUssClassName = ussClassName + "__input"; + public static readonly string contentUssClassName = ussClassName + "__content"; public static readonly string borderUssClassName = ussClassName + "__border"; + VisualElement m_GradientTextureImage; + public GradientField() : this(null) {} @@ -68,6 +71,11 @@ public GradientField(string label) labelElement.AddToClassList(labelUssClassName); visualInput.AddToClassList(inputUssClassName); + m_GradientTextureImage = new VisualElement() { pickingMode = PickingMode.Ignore }; + m_GradientTextureImage.AddToClassList(contentUssClassName); + visualInput.Add(m_GradientTextureImage); + + VisualElement borderElement = new VisualElement() { name = "unity-border", pickingMode = PickingMode.Ignore }; borderElement.AddToClassList(borderUssClassName); visualInput.Add(borderElement); @@ -124,7 +132,8 @@ void OnDetach() void OnAttach() { - UpdateGradientTexture(); + if (panel != null) + UpdateGradientTexture(); } void ShowGradientPicker() @@ -147,8 +156,7 @@ void UpdateGradientTexture() else { Texture2D gradientTexture = UnityEditorInternal.GradientPreviewCache.GenerateGradientPreview(value, computedStyle.backgroundImage.value.texture); - - visualInput.style.backgroundImage = gradientTexture; + m_GradientTextureImage.style.backgroundImage = gradientTexture; IncrementVersion(VersionChangeType.Repaint); // since the Texture2D object can be reused, force dirty because the backgroundImage change will only trigger the Dirty if the Texture2D objects are different. } diff --git a/Editor/Mono/UIElements/Controls/IntegerField.cs b/Editor/Mono/UIElements/Controls/IntegerField.cs index b8991784b1..e533d62b99 100644 --- a/Editor/Mono/UIElements/Controls/IntegerField.cs +++ b/Editor/Mono/UIElements/Controls/IntegerField.cs @@ -68,9 +68,16 @@ public override void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, int { double sensitivity = NumericFieldDraggerUtility.CalculateIntDragSensitivity(startValue); float acceleration = NumericFieldDraggerUtility.Acceleration(speed == DeltaSpeed.Fast, speed == DeltaSpeed.Slow); - long v = parentIntegerField.value; + long v = StringToValue(text); v += (long)Math.Round(NumericFieldDraggerUtility.NiceDelta(delta, acceleration) * sensitivity); - parentIntegerField.value = MathUtils.ClampToInt(v); + if (parentIntegerField.isDelayed) + { + text = ValueToString(MathUtils.ClampToInt(v)); + } + else + { + parentIntegerField.value = MathUtils.ClampToInt(v); + } } protected override string ValueToString(int v) diff --git a/Editor/Mono/UIElements/Controls/LongField.cs b/Editor/Mono/UIElements/Controls/LongField.cs index 3dcb3632ce..17e51a818f 100644 --- a/Editor/Mono/UIElements/Controls/LongField.cs +++ b/Editor/Mono/UIElements/Controls/LongField.cs @@ -71,9 +71,16 @@ public override void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, long { double sensitivity = NumericFieldDraggerUtility.CalculateIntDragSensitivity(startValue); float acceleration = NumericFieldDraggerUtility.Acceleration(speed == DeltaSpeed.Fast, speed == DeltaSpeed.Slow); - long v = parentLongField.value; + long v = StringToValue(text); v += (long)Math.Round(NumericFieldDraggerUtility.NiceDelta(delta, acceleration) * sensitivity); - parentLongField.value = v; + if (parentLongField.isDelayed) + { + text = ValueToString(v); + } + else + { + parentLongField.value = v; + } } protected override string ValueToString(long v) diff --git a/Editor/Mono/UIElements/Controls/MaskField.cs b/Editor/Mono/UIElements/Controls/MaskField.cs index 08719ccc63..ef5ace4d16 100644 --- a/Editor/Mono/UIElements/Controls/MaskField.cs +++ b/Editor/Mono/UIElements/Controls/MaskField.cs @@ -247,7 +247,7 @@ internal string GetDisplayedValue(int itemIndex) } else { - newValueToShowUser = L10n.Tr("Mixed ..."); + newValueToShowUser = L10n.Tr("Mixed..."); } break; } diff --git a/Editor/Mono/UIElements/Controls/ObjectField.cs b/Editor/Mono/UIElements/Controls/ObjectField.cs index 52c26904f6..6a7f3db5e6 100644 --- a/Editor/Mono/UIElements/Controls/ObjectField.cs +++ b/Editor/Mono/UIElements/Controls/ObjectField.cs @@ -272,7 +272,9 @@ private void OnObjectChanged(Object obj) internal void ShowObjectSelector() { - ObjectSelector.get.Show(value, objectType, null, allowSceneObjects, null, OnObjectChanged, OnObjectChanged); + // Since we have nothing useful to do on the object selector closing action, we just do not assign any callback + // All the object changes will be notified through the OnObjectChanged and a "cancellation" (Escape key) on the ObjectSelector is calling the closing callback without any good object + ObjectSelector.get.Show(value, objectType, null, allowSceneObjects, null, null, OnObjectChanged); } } } diff --git a/Editor/Mono/UIElements/Controls/PropertyField.cs b/Editor/Mono/UIElements/Controls/PropertyField.cs index d0d529c723..50cd60889c 100644 --- a/Editor/Mono/UIElements/Controls/PropertyField.cs +++ b/Editor/Mono/UIElements/Controls/PropertyField.cs @@ -53,9 +53,6 @@ public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext public static readonly string labelUssClassName = ussClassName + "__label"; public static readonly string inputUssClassName = ussClassName + "__input"; - internal static readonly string ussFoldoutDepthClassName = "unity-foldout--depth-"; - internal static readonly int ussFoldoutMaxDepth = 4; - public PropertyField() : this(null, string.Empty) {} public PropertyField(SerializedProperty property) : this(property, string.Empty) {} @@ -103,13 +100,22 @@ private void Reset(SerializedPropertyBindEvent evt) { customPropertyGUI = new IMGUIContainer(() => { - EditorGUI.BeginChangeCheck(); - m_SerializedProperty.serializedObject.Update(); - - EditorGUILayout.PropertyField(m_SerializedProperty, true); - - m_SerializedProperty.serializedObject.ApplyModifiedProperties(); - EditorGUI.EndChangeCheck(); + var originalWideMode = InspectorElement.SetWideModeForWidth(this); + + try + { + EditorGUI.BeginChangeCheck(); + m_SerializedProperty.serializedObject.Update(); + + EditorGUILayout.PropertyField(m_SerializedProperty, true); + + m_SerializedProperty.serializedObject.ApplyModifiedProperties(); + EditorGUI.EndChangeCheck(); + } + finally + { + EditorGUIUtility.wideMode = originalWideMode; + } }); } hierarchy.Add(customPropertyGUI); @@ -172,9 +178,6 @@ private VisualElement CreateFoldout(SerializedProperty property) foldout.bindingPath = property.propertyPath; foldout.name = "unity-foldout-" + property.propertyPath; - var depthStr = property.depth <= ussFoldoutMaxDepth ? property.depth.ToString() : "max"; - foldout.AddToClassList(ussFoldoutDepthClassName + depthStr); - var endProperty = property.GetEndProperty(); property.NextVisible(true); // Expand the first child. do diff --git a/Editor/Mono/UIElements/Controls/TextValueField.cs b/Editor/Mono/UIElements/Controls/TextValueField.cs index c5f1ff9a98..99fa6e1dad 100644 --- a/Editor/Mono/UIElements/Controls/TextValueField.cs +++ b/Editor/Mono/UIElements/Controls/TextValueField.cs @@ -109,7 +109,7 @@ void UpdateValueFromText() internal override bool AcceptCharacter(char c) { - return c != 0 && allowedCharacters.IndexOf(c) != -1; + return base.AcceptCharacter(c) && c != 0 && allowedCharacters.IndexOf(c) != -1; } protected abstract string allowedCharacters { get; } @@ -127,6 +127,10 @@ public void StartDragging() public void StopDragging() { + if (textValueFieldParent.isDelayed) + { + UpdateValueFromText(); + } isDragging = false; SelectAll(); MarkDirtyRepaint(); @@ -145,8 +149,8 @@ protected internal override void ExecuteDefaultActionAtTarget(EventBase evt) { KeyDownEvent kde = evt as KeyDownEvent; - if ((kde?.keyCode == KeyCode.KeypadEnter) || - (kde?.keyCode == KeyCode.Return)) + if ((kde?.character == 3) || // KeyCode.KeypadEnter + (kde?.character == '\n')) // KeyCode.Return { // Here we should update the value, but it will be done when the blur event will be handled... parent.Focus(); diff --git a/Editor/Mono/UIElements/EditorWindowPersistentViewData.cs b/Editor/Mono/UIElements/EditorWindowPersistentViewData.cs index 5075d19ec7..1dfbf7b7f6 100644 --- a/Editor/Mono/UIElements/EditorWindowPersistentViewData.cs +++ b/Editor/Mono/UIElements/EditorWindowPersistentViewData.cs @@ -7,9 +7,9 @@ namespace UnityEditor.UIElements [LibraryFolderPath("UIElements/EditorWindows")] internal class EditorWindowViewData : ScriptableSingletonDictionary< EditorWindowViewData, - UnityEditor.Experimental.UIElements.SerializableJsonDictionary> + UnityEditor.UIElements.SerializableJsonDictionary> { - public static UnityEditor.Experimental.UIElements.SerializableJsonDictionary GetEditorData(EditorWindow window) + public static UnityEditor.UIElements.SerializableJsonDictionary GetEditorData(EditorWindow window) { string editorPrefFileName = window.GetType().ToString(); return instance[editorPrefFileName]; diff --git a/Editor/Mono/UIElements/Experimental/Controls/BaseCompositeField.cs b/Editor/Mono/UIElements/Experimental/Controls/BaseCompositeField.cs deleted file mode 100644 index 657683069a..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/BaseCompositeField.cs +++ /dev/null @@ -1,136 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - /// - /// This is the base class for the compound fields of type TMain. - /// - /// The type of the object to be represented by the fields (example: Vector3) - /// The type of a single field in the compound field. (example: for a Vector3, this is FloatField) - /// The basic type of an individual object contained in the TField. (example: for a FloatField, this is a float) - public abstract class BaseCompositeField : BaseField - where TField : TextValueField, new() - { - public new class UxmlTraits : BaseField.UxmlTraits {} - - internal struct FieldDescription - { - public delegate void WriteDelegate(ref TValue val, TFieldValue fieldValue); - - internal readonly string name; - internal readonly Func read; - internal readonly WriteDelegate write; - - public FieldDescription(string name, Func read, WriteDelegate write) - { - this.name = name; - this.read = read; - this.write = write; - } - } - - public override int focusIndex - { - get { return base.focusIndex; } - set - { - base.focusIndex = value; - if ((m_Fields != null) && (m_Fields.Count > 0)) - { - foreach (var field in m_Fields) - { - field.focusIndex = value; - } - } - } - } - protected List m_Fields; - internal abstract FieldDescription[] DescribeFields(); - - bool m_ShouldUpdateDisplay; - protected BaseCompositeField() - { - AddToClassList("compositeField"); - m_ShouldUpdateDisplay = true; - m_Fields = new List(); - FieldDescription[] fieldDescriptions = DescribeFields(); - foreach (var desc in fieldDescriptions) - { - var fieldContainer = new VisualElement(); - fieldContainer.AddToClassList("field"); - fieldContainer.Add(new Label(desc.name)); - var field = new TField(); - fieldContainer.Add(field); - field.OnValueChanged(e => - { - TValue cur = value; - desc.write(ref cur, e.newValue); - - // Here, just check and make sure the text is updated in the basic field and is the same as the value... - // For example, backspace done on a selected value will empty the field (text == "") but the value will be 0. - // Or : a text of "2+3" is valid until enter is pressed, so not equal to a value of "5". - if (e.newValue.ToString() != ((TField)e.currentTarget).text) - { - m_ShouldUpdateDisplay = false; - } - - value = cur; - m_ShouldUpdateDisplay = true; - }); - m_Fields.Add(field); - shadow.Add(fieldContainer); - } - - UpdateDisplay(); - } - - public override VisualElement contentContainer - { - get { return null; } - } - - private void UpdateDisplay() - { - if (m_Fields.Count != 0) - { - var i = 0; - FieldDescription[] fieldDescriptions = DescribeFields(); - foreach (var fd in fieldDescriptions) - { - m_Fields[i].value = (fd.read(m_Value)); - i++; - } - } - } - - public override void SetValueWithoutNotify(TValue newValue) - { - var displayNeedsUpdate = m_ShouldUpdateDisplay && !EqualityComparer.Default.Equals(m_Value, newValue); - - // Make sure to call the base class to set the value... - base.SetValueWithoutNotify(newValue); - - // Before Updating the display, just check if the value changed... - if (displayNeedsUpdate) - { - UpdateDisplay(); - } - } - - protected internal override void ExecuteDefaultAction(EventBase evt) - { - base.ExecuteDefaultAction(evt); - - // Focus first field if any - if (evt.GetEventTypeId() == FocusEvent.TypeId() && m_Fields.Count > 0) - m_Fields[0].Focus(); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/BasePopupField.cs b/Editor/Mono/UIElements/Experimental/Controls/BasePopupField.cs deleted file mode 100644 index b825eae0eb..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/BasePopupField.cs +++ /dev/null @@ -1,90 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - /// - /// This is the base class for all the popup field elements. - /// TValue and TChoice can be different, see MaskField, - /// or the same, see PopupField - /// - /// Used for the BaseField - /// Used for the choices list - public abstract class BasePopupField : BaseField - { - internal List m_Choices; - protected TextElement m_TextElement; - - internal Func m_FormatSelectedValueCallback; - internal Func m_FormatListItemCallback; - - // This is the value to display to the user - internal abstract string GetValueToDisplay(); - - internal abstract string GetListItemToDisplay(TValue item); - - // This method is used when the menu is built to fill up all the choices. - internal abstract void AddMenuItems(GenericMenu menu); - - internal virtual List choices - { - get { return m_Choices; } - set - { - if (value == null) - throw new ArgumentNullException("choices", "choices can't be null"); - - m_Choices = value; - } - } - - public override void SetValueWithoutNotify(TValue newValue) - { - base.SetValueWithoutNotify(newValue); - m_TextElement.text = GetValueToDisplay(); - } - - public string text - { - get { return m_TextElement.text; } - } - - protected BasePopupField() - { - m_TextElement = new TextElement(); - m_TextElement.pickingMode = PickingMode.Ignore; - Add(m_TextElement); - AddToClassList("popupField"); - - choices = new List(); - } - - protected internal override void ExecuteDefaultActionAtTarget(EventBase evt) - { - base.ExecuteDefaultActionAtTarget(evt); - - if (((evt as MouseDownEvent)?.button == (int)MouseButton.LeftMouse) || - ((evt.GetEventTypeId() == KeyDownEvent.TypeId()) && ((evt as KeyDownEvent)?.character == '\n') || ((evt as KeyDownEvent)?.character == ' '))) - { - ShowMenu(); - evt.StopPropagation(); - } - } - - private void ShowMenu() - { - var menu = new GenericMenu(); - AddMenuItems(menu); - var menuPosition = new Vector2(0.0f, layout.height); - menuPosition = this.LocalToWorld(menuPosition); - var menuRect = new Rect(menuPosition, Vector2.zero); - menu.DropDown(menuRect); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/BindingExtensions.cs b/Editor/Mono/UIElements/Experimental/Controls/BindingExtensions.cs deleted file mode 100644 index b6a89bd967..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/BindingExtensions.cs +++ /dev/null @@ -1,913 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Linq; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - internal class SerializedObjectBindEvent : EventBase - { - private SerializedObject m_BindObject; - public SerializedObject bindObject - { - get - { - return m_BindObject; - } - } - - protected override void Init() - { - base.Init(); - this.flags = EventFlags.Cancellable; // Also makes it not propagatable. - m_BindObject = null; - } - - public static SerializedObjectBindEvent GetPooled(SerializedObject obj) - { - SerializedObjectBindEvent e = GetPooled(); - e.m_BindObject = obj; - return e; - } - } - - internal class SerializedPropertyBindEvent : EventBase - { - private SerializedProperty m_BindProperty; - public SerializedProperty bindProperty - { - get - { - return m_BindProperty; - } - } - - protected override void Init() - { - base.Init(); - this.flags = EventFlags.Cancellable; // Also makes it not propagatable. - m_BindProperty = null; - } - - public static SerializedPropertyBindEvent GetPooled(SerializedProperty obj) - { - SerializedPropertyBindEvent e = GetPooled(); - e.m_BindProperty = obj; - return e; - } - } - - public static class BindingExtensions - { - // visual element style changes wrt its property state - internal static readonly string k_PrefabOverrideClassName = "unity-prefab-override"; - - public static void Bind(this VisualElement element, SerializedObject obj) - { - Bind(element, new SerializedObjectUpdateWrapper(obj), null); - } - - public static void Unbind(this VisualElement element) - { - RemoveBinding(element); - - for (int i = 0; i < element.shadow.childCount; ++i) - { - Unbind(element.shadow[i]); - } - } - - public static SerializedProperty BindProperty(this IBindable field, SerializedObject obj) - { - return BindPropertyWithParent(field, new SerializedObjectUpdateWrapper(obj), null); - } - - public static void BindProperty(this IBindable field, SerializedProperty property) - { - DoBindProperty(field, new SerializedObjectUpdateWrapper(property.serializedObject), property); - } - - private static void DoBindProperty(IBindable field, SerializedObjectUpdateWrapper obj, SerializedProperty property) - { - var fieldElement = field as VisualElement; - if (property == null || fieldElement == null) - { - // Object is null or property was not found, we have to make sure we delete any previous binding - RemoveBinding(fieldElement); - return; - } - - // This covers the case where a field is being manually bound to a property - field.bindingPath = property.propertyPath; - - if (property != null && fieldElement != null) - { - using (var evt = SerializedPropertyBindEvent.GetPooled(property)) - { - if (SendBindingEvent(evt, fieldElement)) - { - return; - } - } - } - - CreateBindingObjectForProperty(fieldElement, obj, property); - } - - private static void Bind(VisualElement element, SerializedObjectUpdateWrapper objWrapper, SerializedProperty parentProperty) - { - IBindable field = element as IBindable; - - using (var evt = SerializedObjectBindEvent.GetPooled(objWrapper.obj)) - { - if (SendBindingEvent(evt, element)) - { - return; - } - } - - if (field != null) - { - if (!string.IsNullOrEmpty(field.bindingPath)) - { - var foundProperty = BindPropertyWithParent(field, objWrapper, parentProperty); - if (foundProperty != null) - { - parentProperty = foundProperty; - } - } - } - - for (int i = 0; i < element.shadow.childCount; ++i) - { - Bind(element.shadow[i], objWrapper, parentProperty); - } - } - - private static SerializedProperty BindPropertyWithParent(IBindable field, SerializedObjectUpdateWrapper objWrapper, SerializedProperty parentProperty) - { - var property = parentProperty?.FindPropertyRelative(field.bindingPath); - - if (property == null) - { - property = objWrapper.obj?.FindProperty(field.bindingPath); - } - - DoBindProperty(field, objWrapper, property); - - return property; - } - - private static bool SendBindingEvent(TEventType evt, VisualElement target) where TEventType : EventBase, new() - { - evt.target = target; - evt.propagationPhase = PropagationPhase.AtTarget; - target.HandleEvent(evt); - return evt.isPropagationStopped; - } - - private static void RemoveBinding(VisualElement element) - { - IBindable field = element as IBindable; - if (element == null || !field.IsBound()) - { - return; - } - if (field != null) - { - field.binding?.Release(); - field.binding = null; - } - } - - /// Property getters - private static int GetIntPropertyValue(SerializedProperty p) { return p.intValue; } - private static bool GetBoolPropertyValue(SerializedProperty p) { return p.boolValue; } - private static float GetFloatPropertyValue(SerializedProperty p) { return p.floatValue; } - private static double GetDoublePropertyValue(SerializedProperty p) { return p.doubleValue; } - private static string GetStringPropertyValue(SerializedProperty p) { return p.stringValue; } - private static Color GetColorPropertyValue(SerializedProperty p) { return p.colorValue; } - private static UnityEngine.Object GetObjectRefPropertyValue(SerializedProperty p) {return p.objectReferenceValue; } - private static int GetLayerMaskPropertyValue(SerializedProperty p) {return p.intValue; } - private static Vector2 GetVector2PropertyValue(SerializedProperty p) { return p.vector2Value; } - private static Vector3 GetVector3PropertyValue(SerializedProperty p) { return p.vector3Value; } - private static Vector4 GetVector4PropertyValue(SerializedProperty p) { return p.vector4Value; } - private static Vector2Int GetVector2IntPropertyValue(SerializedProperty p) { return p.vector2IntValue; } - private static Vector3Int GetVector3IntPropertyValue(SerializedProperty p) { return p.vector3IntValue; } - private static Rect GetRectPropertyValue(SerializedProperty p) { return p.rectValue; } - private static RectInt GetRectIntPropertyValue(SerializedProperty p) { return p.rectIntValue; } - private static AnimationCurve GetAnimationCurvePropertyValue(SerializedProperty p) { return p.animationCurveValue; } - private static Bounds GetBoundsPropertyValue(SerializedProperty p) { return p.boundsValue; } - private static BoundsInt GetBoundsIntPropertyValue(SerializedProperty p) { return p.boundsIntValue; } - private static Gradient GetGradientPropertyValue(SerializedProperty p) { return p.gradientValue; } - private static Quaternion GetQuaternionPropertyValue(SerializedProperty p) { return p.quaternionValue; } - private static char GetCharacterPropertyValue(SerializedProperty p) { return (char)p.intValue; } - - - // Basic conversions - private static float GetDoublePropertyValueAsFloat(SerializedProperty p) { return (float)p.doubleValue; } - private static double GetFloatPropertyValueAsDouble(SerializedProperty p) { return (double)p.floatValue; } - private static string GetCharacterPropertyValueAsString(SerializedProperty p) { return new string((char)p.intValue, 1); } - - //this one is a bit more tricky - private static string GetEnumPropertyValueAsString(SerializedProperty p) { return p.enumDisplayNames[p.enumValueIndex]; } - - - /// Property setters - private static void SetIntPropertyValue(SerializedProperty p, int v) { p.intValue = v; } - private static void SetBoolPropertyValue(SerializedProperty p, bool v) { p.boolValue = v; } - private static void SetFloatPropertyValue(SerializedProperty p, float v) { p.floatValue = v; } - private static void SetDoublePropertyValue(SerializedProperty p, double v) { p.doubleValue = v; } - private static void SetStringPropertyValue(SerializedProperty p, string v) { p.stringValue = v; } - private static void SetColorPropertyValue(SerializedProperty p, Color v) { p.colorValue = v; } - private static void SetObjectRefPropertyValue(SerializedProperty p, UnityEngine.Object v) { p.objectReferenceValue = v; } - private static void SetLayerMaskPropertyValue(SerializedProperty p, int v) { p.intValue = v; } - private static void SetVector2PropertyValue(SerializedProperty p, Vector2 v) { p.vector2Value = v; } - private static void SetVector3PropertyValue(SerializedProperty p, Vector3 v) { p.vector3Value = v; } - private static void SetVector4PropertyValue(SerializedProperty p, Vector4 v) { p.vector4Value = v; } - private static void SetVector2IntPropertyValue(SerializedProperty p, Vector2Int v) { p.vector2IntValue = v; } - private static void SetVector3IntPropertyValue(SerializedProperty p, Vector3Int v) { p.vector3IntValue = v; } - private static void SetRectPropertyValue(SerializedProperty p, Rect v) { p.rectValue = v; } - private static void SetRectIntPropertyValue(SerializedProperty p, RectInt v) { p.rectIntValue = v; } - private static void SetAnimationCurvePropertyValue(SerializedProperty p, AnimationCurve v) { p.animationCurveValue = v; } - private static void SetBoundsPropertyValue(SerializedProperty p, Bounds v) { p.boundsValue = v; } - private static void SetBoundsIntPropertyValue(SerializedProperty p, BoundsInt v) { p.boundsIntValue = v; } - private static void SetGradientPropertyValue(SerializedProperty p, Gradient v) {p.gradientValue = v; } - private static void SetQuaternionPropertyValue(SerializedProperty p, Quaternion v) { p.quaternionValue = v; } - private static void SetCharacterPropertyValue(SerializedProperty p, char v) { p.intValue = v; } - - // Conversions - private static void SetDoublePropertyValueFromFloat(SerializedProperty p, float v) { p.doubleValue = v; } - private static void SetFloatPropertyValueFromDouble(SerializedProperty p, double v) { p.floatValue = (float)v; } - private static void SetCharacterPropertyValueFromString(SerializedProperty p, string v) - { - if (v.Length > 0) - { - p.intValue = v[0]; - } - } - - //this one is a bit more tricky - private static void SetEnumPropertyValueFromString(SerializedProperty p, string v) { p.enumValueIndex = FindStringIndex(p.enumDisplayNames, v); } - - // A No Linq implementation to avoid allocations - private static int FindStringIndex(string[] values, string v) - { - for (var i = 0; i < values.Length; ++i) - { - if (values[i] == v) - return i; - } - - return -1; - } - - // Equality comparers - internal static bool ValueEquals(TValue value, SerializedProperty p, Func propertyReadFunc) - { - var propVal = propertyReadFunc(p); - return EqualityComparer.Default.Equals(value, propVal); - } - - internal static bool ValueEquals(string value, SerializedProperty p, Func propertyReadFunc) - { - if (p.propertyType == SerializedPropertyType.Enum) - return p.enumDisplayNames[p.enumValueIndex] == value; - else - return p.ValueEquals(value); - } - - internal static bool ValueEquals(AnimationCurve value, SerializedProperty p, Func propertyReadFunc) - { - return p.ValueEquals(value); - } - - internal static bool ValueEquals(Gradient value, SerializedProperty p, Func propertyReadFunc) - { - return p.ValueEquals(value); - } - - internal static bool SlowEnumValueEquals(string value, SerializedProperty p, Func propertyReadFunc) - { - var propVal = propertyReadFunc(p); - return EqualityComparer.Default.Equals(value, propVal); - } - - private static void DefaultBind(VisualElement element, SerializedObjectUpdateWrapper objWrapper, SerializedProperty prop, - Func propertyReadFunc, Action propertyWriteFunc, - Func, bool> valueComparerFunc) - { - var field = element as INotifyValueChanged; - - if (field != null) - { - SerializedObjectBinding.CreateBind(field, objWrapper, prop, propertyReadFunc, - propertyWriteFunc, valueComparerFunc); - } - else - { - Debug.LogWarning(string.Format("Field type {0} is not compatible with {2} property \"{1}\"", - element.GetType().FullName, prop.propertyPath, prop.type)); - } - } - - private static void EnumBind(PopupField popup, SerializedObjectUpdateWrapper objWrapper, SerializedProperty prop) - { - SerializedEnumBinding.CreateBind(popup, objWrapper, prop); - } - - private static void CreateBindingObjectForProperty(VisualElement element, SerializedObjectUpdateWrapper objWrapper, SerializedProperty prop) - { - if (element is Foldout) - { - var foldout = element as Foldout; - SerializedObjectBinding.CreateBind( - foldout, objWrapper, prop, - p => p.isExpanded, - (p, v) => p.isExpanded = v, - ValueEquals); - - return; - } - - switch (prop.propertyType) - { - case SerializedPropertyType.Integer: - DefaultBind(element, objWrapper, prop, GetIntPropertyValue, SetIntPropertyValue, ValueEquals); - break; - case SerializedPropertyType.Boolean: - DefaultBind(element, objWrapper, prop, GetBoolPropertyValue, SetBoolPropertyValue, ValueEquals); - break; - case SerializedPropertyType.Float: - if (prop.type == "float") - { - if (element is INotifyValueChanged) - { - DefaultBind(element, objWrapper, prop, GetFloatPropertyValueAsDouble, SetFloatPropertyValueFromDouble, ValueEquals); - } - else - { - DefaultBind(element, objWrapper, prop, GetFloatPropertyValue, SetFloatPropertyValue, ValueEquals); - } - } - else - { - if (element is INotifyValueChanged) - { - DefaultBind(element, objWrapper, prop, GetDoublePropertyValueAsFloat, SetDoublePropertyValueFromFloat, ValueEquals); - } - else - { - DefaultBind(element, objWrapper, prop, GetDoublePropertyValue, SetDoublePropertyValue, ValueEquals); - } - } - - break; - case SerializedPropertyType.String: - DefaultBind(element, objWrapper, prop, GetStringPropertyValue, SetStringPropertyValue, ValueEquals); - break; - case SerializedPropertyType.Color: - DefaultBind(element, objWrapper, prop, GetColorPropertyValue, SetColorPropertyValue, ValueEquals); - break; - case SerializedPropertyType.ObjectReference: - DefaultBind(element, objWrapper, prop, GetObjectRefPropertyValue, SetObjectRefPropertyValue, ValueEquals); - break; - case SerializedPropertyType.LayerMask: - DefaultBind(element, objWrapper, prop, GetLayerMaskPropertyValue, SetLayerMaskPropertyValue, ValueEquals); - break; - case SerializedPropertyType.Enum: - if (element is PopupField) - { - EnumBind((PopupField)element, objWrapper, prop); - } - else - { - DefaultBind(element, objWrapper, prop, GetEnumPropertyValueAsString, SetEnumPropertyValueFromString, SlowEnumValueEquals); - } - - break; - case SerializedPropertyType.Vector2: - DefaultBind(element, objWrapper, prop, GetVector2PropertyValue, SetVector2PropertyValue, ValueEquals); - break; - case SerializedPropertyType.Vector3: - DefaultBind(element, objWrapper, prop, GetVector3PropertyValue, SetVector3PropertyValue, ValueEquals); - break; - case SerializedPropertyType.Vector4: - DefaultBind(element, objWrapper, prop, GetVector4PropertyValue, SetVector4PropertyValue, ValueEquals); - break; - case SerializedPropertyType.Rect: - DefaultBind(element, objWrapper, prop, GetRectPropertyValue, SetRectPropertyValue, ValueEquals); - break; - case SerializedPropertyType.ArraySize: - DefaultBind(element, objWrapper, prop, GetIntPropertyValue, SetIntPropertyValue, ValueEquals); - break; - case SerializedPropertyType.AnimationCurve: - DefaultBind(element, objWrapper, prop, GetAnimationCurvePropertyValue, SetAnimationCurvePropertyValue, ValueEquals); - break; - case SerializedPropertyType.Bounds: - DefaultBind(element, objWrapper, prop, GetBoundsPropertyValue, SetBoundsPropertyValue, ValueEquals); - break; - case SerializedPropertyType.Gradient: - DefaultBind(element, objWrapper, prop, GetGradientPropertyValue, SetGradientPropertyValue, ValueEquals); - break; - case SerializedPropertyType.Quaternion: - DefaultBind(element, objWrapper, prop, GetQuaternionPropertyValue, SetQuaternionPropertyValue, ValueEquals); - break; - case SerializedPropertyType.FixedBufferSize: - DefaultBind(element, objWrapper, prop, GetIntPropertyValue, SetIntPropertyValue, ValueEquals); - break; - case SerializedPropertyType.Vector2Int: - DefaultBind(element, objWrapper, prop, GetVector2IntPropertyValue, SetVector2IntPropertyValue, ValueEquals); - break; - case SerializedPropertyType.Vector3Int: - DefaultBind(element, objWrapper, prop, GetVector3IntPropertyValue, SetVector3IntPropertyValue, ValueEquals); - break; - case SerializedPropertyType.RectInt: - DefaultBind(element, objWrapper, prop, GetRectIntPropertyValue, SetRectIntPropertyValue, ValueEquals); - break; - case SerializedPropertyType.BoundsInt: - DefaultBind(element, objWrapper, prop, GetBoundsIntPropertyValue, SetBoundsIntPropertyValue, ValueEquals); - break; - case SerializedPropertyType.Character: - if (element is INotifyValueChanged) - { - DefaultBind(element, objWrapper, prop, GetCharacterPropertyValueAsString, SetCharacterPropertyValueFromString, ValueEquals); - } - else - { - DefaultBind(element, objWrapper, prop, GetCharacterPropertyValue, SetCharacterPropertyValue, ValueEquals); - } - break; - case SerializedPropertyType.ExposedReference: - case SerializedPropertyType.Generic: - // nothing to bind here - break; - default: - Debug.LogWarning(string.Format("Binding is not supported for {0} properties \"{1}\"", prop.type, - prop.propertyPath)); - break; - } - } - - private class SerializedObjectUpdateWrapper - { - SerializedObjectChangeTracker tracker; - public UInt64 LastRevision {get; private set; } - public SerializedObject obj {get; private set; } - - public SerializedObjectUpdateWrapper(SerializedObject so) - { - tracker = new SerializedObjectChangeTracker(so); - obj = so; - } - - private bool wasUpdated {get; set; } - - public void UpdateRevision() - { - tracker.UpdateTrackedVersion(); - LastRevision = tracker.CurrentRevision; - } - - public bool IsValid() - { - if (obj == null) - return false; - - return obj.isValid; - } - - public void UpdateIfNecessary() - { - if (!wasUpdated) - { - obj.UpdateIfRequiredOrScript(); - obj.UpdateExpandedState(); - UpdateRevision(); - wasUpdated = true; - } - } - - public void ResetUpdate() - { - wasUpdated = false; - } - } - - private abstract class SerializedObjectBindingBase : IBinding - { - public SerializedObjectUpdateWrapper boundObject; - public string boundPropertyPath; - public SerializedProperty boundProperty; - - protected bool isReleased { get; set; } - protected bool isUpdating { get; set; } - public abstract void Update(); - public abstract void Release(); - - public void PreUpdate() - { - boundObject.UpdateIfNecessary(); - } - - public virtual void ResetUpdate() - { - if (boundObject != null) - { - boundObject.ResetUpdate(); - } - } - - protected static void UpdateElementStyle(VisualElement element, SerializedProperty prop) - { - if (prop.serializedObject.targetObjects.Length == 1 && prop.isInstantiatedPrefab && prop.prefabOverride) - element.AddToClassList(BindingExtensions.k_PrefabOverrideClassName); - else - element.RemoveFromClassList(BindingExtensions.k_PrefabOverrideClassName); - } - - protected bool IsPropertyValid() - { - if (boundProperty != null) - { - return boundProperty.isValid; - } - return false; - } - } - - private abstract class SerializedObjectBindingToBaseField : SerializedObjectBindingBase where TField : class, INotifyValueChanged - { - private TField m_Field; - - protected TField field - { - get { return m_Field; } - set - { - m_Field?.RemoveOnValueChanged(FieldValueChanged); - - VisualElement ve = m_Field as VisualElement; - if (ve != null) - { - ve.UnregisterCallback(OnFieldAttached); - ve.UnregisterCallback(OnFieldDetached); - } - - m_Field = value; - UpdateFieldIsAttached(); - if (m_Field != null) - { - m_Field.OnValueChanged(FieldValueChanged); - - ve = m_Field as VisualElement; - if (ve != null) - { - ve.RegisterCallback(OnFieldAttached); - ve.RegisterCallback(OnFieldDetached); - } - FieldBinding = this; - } - } - } - - protected IBinding FieldBinding - { - get - { - var bindable = m_Field as IBindable; - return bindable?.binding; - } - set - { - var bindable = m_Field as IBindable; - if (bindable != null) - { - var previousBinding = bindable.binding; - bindable.binding = value; - if (previousBinding != this) - { - previousBinding?.Release(); - } - (m_Field as VisualElement)?.IncrementVersion(VersionChangeType.Bindings); - } - } - } - - protected bool isFieldAttached {get; private set; } - - private void FieldValueChanged(ChangeEvent evt) - { - if (isReleased || isUpdating) - return; - - var bindable = evt.target as IBindable; - var binding = bindable?.binding; - - if (binding == this && boundProperty != null && boundObject.IsValid()) - { - if (!isFieldAttached) - { - //we don't update when field is not attached to a panel - //but we don't kill binding either - return; - } - - UpdateLastFieldValue(); - - if (IsPropertyValid()) - { - if (SyncFieldValueToProperty()) - { - boundObject.UpdateRevision(); //we make sure to Poll the ChangeTracker here - boundObject.ResetUpdate(); - } - UpdateElementStyle(field as VisualElement, boundProperty); - return; - } - } - - // Something was wrong - Release(); - } - - private UInt64 lastUpdatedRevision = 0xFFFFFFFFFFFFFFFF; - - public void ResetCachedValues() - { - lastUpdatedRevision = 0xFFFFFFFFFFFFFFFF; - UpdateLastFieldValue(); - UpdateFieldIsAttached(); - } - - public override void Update() - { - if (isReleased) - return; - try - { - ResetUpdate(); - isUpdating = true; - - if (FieldBinding == this && boundObject.IsValid() && IsPropertyValid()) - { - if (lastUpdatedRevision == boundObject.LastRevision) - { - //nothing to do - return; - } - - lastUpdatedRevision = boundObject.LastRevision; - SyncPropertyToField(field, boundProperty); - return; - } - } - catch (ArgumentNullException) - { - //this can happen when serializedObject has been disposed of - } - finally - { - isUpdating = false; - } - // We unbind here - Release(); - } - - private void OnFieldAttached(AttachToPanelEvent evt) - { - isFieldAttached = true; - ResetCachedValues(); - } - - private void OnFieldDetached(DetachFromPanelEvent evt) - { - isFieldAttached = false; - } - - protected void UpdateFieldIsAttached() - { - VisualElement ve = m_Field as VisualElement; - - if (ve != null) - { - bool attached = ve.panel != null; - - if (isFieldAttached != attached) - { - isFieldAttached = attached; - if (attached) - { - ResetCachedValues(); - } - } - } - else - { - //we're not dealing with VisualElement - if (!isFieldAttached) - { - isFieldAttached = true; - ResetCachedValues(); - } - } - } - - // Read the value from the ui field and save it. - protected abstract void UpdateLastFieldValue(); - - protected abstract bool SyncFieldValueToProperty(); - protected abstract void SyncPropertyToField(TField c, SerializedProperty p); - } - - private class SerializedObjectBinding : SerializedObjectBindingToBaseField> - { - private Func propGetValue; - private Action propSetValue; - private Func, bool> propCompareValues; - - public static ObjectPool> s_Pool = - new ObjectPool>(32); - - //we need to keep a copy of the last value since some fields will allocate when getting the value - private TValue lastFieldValue; - - public static void CreateBind(INotifyValueChanged field, - SerializedObjectUpdateWrapper objWrapper, - SerializedProperty property, - Func propGetValue, - Action propSetValue, - Func, bool> propCompareValues) - { - var newBinding = s_Pool.Get(); - newBinding.isReleased = false; - newBinding.SetBinding(field, objWrapper, property, propGetValue, propSetValue, propCompareValues); - } - - private void SetBinding(INotifyValueChanged c, - SerializedObjectUpdateWrapper objWrapper, - SerializedProperty property, - Func getValue, - Action setValue, - Func, bool> compareValues) - { - this.field = c; - property.unsafeMode = true; - this.boundPropertyPath = property.propertyPath; - this.boundObject = objWrapper; - this.boundProperty = property; - this.propGetValue = getValue; - this.propSetValue = setValue; - this.propCompareValues = compareValues; - this.lastFieldValue = c.value; - - Update(); - } - - protected override void SyncPropertyToField(INotifyValueChanged c, SerializedProperty p) - { - if (!propCompareValues(lastFieldValue, p, propGetValue)) - { - lastFieldValue = propGetValue(p); - c.value = lastFieldValue; - } - } - - protected override void UpdateLastFieldValue() - { - lastFieldValue = field.value; - } - - protected override bool SyncFieldValueToProperty() - { - if (!propCompareValues(lastFieldValue, boundProperty, propGetValue)) - { - propSetValue(boundProperty, lastFieldValue); - boundProperty.m_SerializedObject.ApplyModifiedProperties(); - return true; - } - return false; - } - - public override void Release() - { - if (isReleased) - return; - - if (FieldBinding == this) - { - FieldBinding = null; - } - - boundObject = null; - boundProperty = null; - field = null; - propGetValue = null; - propSetValue = null; - propCompareValues = null; - lastFieldValue = default(TValue); - isReleased = true; - s_Pool.Release(this); - } - } - - // specific enum version that binds on the index property of the PopupField - private class SerializedEnumBinding : SerializedObjectBindingToBaseField> - { - public static ObjectPool s_Pool = - new ObjectPool(32); - - //we need to keep a copy of the last value since some fields will allocate when getting the value - private int lastFieldValueIndex; - - private List originalChoices; - private int originalIndex; - - public static void CreateBind(PopupField field, SerializedObjectUpdateWrapper objWrapper, - SerializedProperty property) - { - var newBinding = s_Pool.Get(); - newBinding.isReleased = false; - newBinding.SetBinding(field, objWrapper, property); - } - - private void SetBinding(PopupField c, SerializedObjectUpdateWrapper objWrapper, - SerializedProperty property) - { - this.field = c; - property.unsafeMode = true; - this.boundPropertyPath = property.propertyPath; - this.boundObject = objWrapper; - this.boundProperty = property; - this.originalChoices = field.choices; - this.originalIndex = field.index; - this.field.choices = property.enumLocalizedDisplayNames.ToList(); - this.lastFieldValueIndex = c.index; - - Update(); - } - - protected override void SyncPropertyToField(PopupField c, SerializedProperty p) - { - int propValueIndex = p.enumValueIndex; - if (propValueIndex != lastFieldValueIndex) - { - lastFieldValueIndex = propValueIndex; - c.index = propValueIndex; - } - } - - protected override void UpdateLastFieldValue() - { - lastFieldValueIndex = field.index; - } - - protected override bool SyncFieldValueToProperty() - { - if (lastFieldValueIndex != boundProperty.enumValueIndex) - { - boundProperty.enumValueIndex = lastFieldValueIndex; - boundProperty.m_SerializedObject.ApplyModifiedProperties(); - return true; - } - return false; - } - - public override void Release() - { - if (isReleased) - return; - - if (FieldBinding == this) - { - //we set the popup values to the original ones - try - { - var previousField = field; - field = null; - previousField.choices = originalChoices; - previousField.index = originalIndex; - } - catch (ArgumentException) - { - //we did our best - } - - FieldBinding = null; - } - - boundObject = null; - boundProperty = null; - field = null; - lastFieldValueIndex = -1; - isReleased = true; - s_Pool.Release(this); - } - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/BoundsField.cs b/Editor/Mono/UIElements/Experimental/Controls/BoundsField.cs deleted file mode 100644 index f659e91513..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/BoundsField.cs +++ /dev/null @@ -1,90 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class BoundsField : BaseField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BaseField.UxmlTraits - { - UxmlFloatAttributeDescription m_CenterXValue = new UxmlFloatAttributeDescription { name = "cx" }; - UxmlFloatAttributeDescription m_CenterYValue = new UxmlFloatAttributeDescription { name = "cy" }; - UxmlFloatAttributeDescription m_CenterZValue = new UxmlFloatAttributeDescription { name = "cz" }; - - UxmlFloatAttributeDescription m_ExtentsXValue = new UxmlFloatAttributeDescription { name = "ex" }; - UxmlFloatAttributeDescription m_ExtentsYValue = new UxmlFloatAttributeDescription { name = "ey" }; - UxmlFloatAttributeDescription m_ExtentsZValue = new UxmlFloatAttributeDescription { name = "ez" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - BoundsField f = (BoundsField)ve; - f.SetValueWithoutNotify(new Bounds( - new Vector3(m_CenterXValue.GetValueFromBag(bag, cc), m_CenterYValue.GetValueFromBag(bag, cc), m_CenterZValue.GetValueFromBag(bag, cc)), - new Vector3(m_ExtentsXValue.GetValueFromBag(bag, cc), m_ExtentsYValue.GetValueFromBag(bag, cc), m_ExtentsZValue.GetValueFromBag(bag, cc)))); - } - } - - private Vector3Field m_CenterField; - private Vector3Field m_ExtentsField; - - public BoundsField() - { - m_CenterField = new Vector3Field(); - - m_CenterField.OnValueChanged(e => - { - Bounds current = value; - current.center = e.newValue; - value = current; - }); - - var centerGroup = new VisualElement(); - centerGroup.AddToClassList("group"); - centerGroup.Add(new Label("Center")); - centerGroup.Add(m_CenterField); - this.shadow.Add(centerGroup); - - m_ExtentsField = new Vector3Field(); - - m_ExtentsField.OnValueChanged(e => - { - Bounds current = value; - current.extents = e.newValue; - value = current; - }); - - var extentsGroup = new VisualElement(); - extentsGroup.AddToClassList("group"); - extentsGroup.contentContainer.Add(new Label("Extents")); - extentsGroup.contentContainer.Add(m_ExtentsField); - this.shadow.Add(extentsGroup); - } - - protected internal override void ExecuteDefaultAction(EventBase evt) - { - base.ExecuteDefaultAction(evt); - - // Focus first field if any - if (evt.GetEventTypeId() == FocusEvent.TypeId()) - { - m_CenterField.Focus(); - } - } - - public override void SetValueWithoutNotify(Bounds newValue) - { - base.SetValueWithoutNotify(newValue); - m_CenterField.SetValueWithoutNotify(m_Value.center); - m_ExtentsField.SetValueWithoutNotify(m_Value.extents); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/BoundsIntField.cs b/Editor/Mono/UIElements/Experimental/Controls/BoundsIntField.cs deleted file mode 100644 index c1c45773d0..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/BoundsIntField.cs +++ /dev/null @@ -1,91 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class BoundsIntField : BaseField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BaseField.UxmlTraits - { - UxmlIntAttributeDescription m_PositionXValue = new UxmlIntAttributeDescription { name = "px" }; - UxmlIntAttributeDescription m_PositionYValue = new UxmlIntAttributeDescription { name = "py" }; - UxmlIntAttributeDescription m_PositionZValue = new UxmlIntAttributeDescription { name = "pz" }; - - UxmlIntAttributeDescription m_SizeXValue = new UxmlIntAttributeDescription { name = "sx" }; - UxmlIntAttributeDescription m_SizeYValue = new UxmlIntAttributeDescription { name = "sy" }; - UxmlIntAttributeDescription m_SizeZValue = new UxmlIntAttributeDescription { name = "sz" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - var f = (BoundsIntField)ve; - f.SetValueWithoutNotify(new BoundsInt( - new Vector3Int(m_PositionXValue.GetValueFromBag(bag, cc), m_PositionYValue.GetValueFromBag(bag, cc), m_PositionZValue.GetValueFromBag(bag, cc)), - new Vector3Int(m_SizeXValue.GetValueFromBag(bag, cc), m_SizeYValue.GetValueFromBag(bag, cc), m_SizeZValue.GetValueFromBag(bag, cc)))); - } - } - - private Vector3IntField m_PositionField; - private Vector3IntField m_SizeField; - - public BoundsIntField() - { - m_PositionField = new Vector3IntField(); - - m_PositionField.OnValueChanged(e => - { - var current = value; - current.position = e.newValue; - value = current; - }); - - var centerGroup = new VisualElement(); - centerGroup.AddToClassList("group"); - centerGroup.Add(new Label("Position")); - centerGroup.Add(m_PositionField); - this.shadow.Add(centerGroup); - - m_SizeField = new Vector3IntField(); - - m_SizeField.OnValueChanged(e => - { - var current = value; - current.size = e.newValue; - value = current; - }); - - var extentsGroup = new VisualElement(); - extentsGroup.AddToClassList("group"); - extentsGroup.contentContainer.Add(new Label("Size")); - extentsGroup.contentContainer.Add(m_SizeField); - this.shadow.Add(extentsGroup); - } - - protected internal override void ExecuteDefaultAction(EventBase evt) - { - base.ExecuteDefaultAction(evt); - - // Focus first field if any - if (evt.GetEventTypeId() == FocusEvent.TypeId()) - { - m_PositionField.Focus(); - } - } - - public override void SetValueWithoutNotify(BoundsInt newValue) - { - base.SetValueWithoutNotify(newValue); - m_PositionField.SetValueWithoutNotify(m_Value.position); - m_SizeField.SetValueWithoutNotify(m_Value.size); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/ColorField.cs b/Editor/Mono/UIElements/Experimental/Controls/ColorField.cs deleted file mode 100644 index ebe1c93530..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/ColorField.cs +++ /dev/null @@ -1,126 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class ColorField : BaseField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BaseField.UxmlTraits - { - UxmlColorAttributeDescription m_Value = new UxmlColorAttributeDescription { name = "value" }; - UxmlBoolAttributeDescription m_ShowEyeDropper = new UxmlBoolAttributeDescription { name = "show-eye-dropper", obsoleteNames = new[] { "showEyeDropper" }, defaultValue = true }; - UxmlBoolAttributeDescription m_ShowAlpha = new UxmlBoolAttributeDescription { name = "show-alpha", obsoleteNames = new[] { "showAlpha" }, defaultValue = true }; - UxmlBoolAttributeDescription m_Hdr = new UxmlBoolAttributeDescription { name = "hdr" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - ((ColorField)ve).SetValueWithoutNotify(m_Value.GetValueFromBag(bag, cc)); - ((ColorField)ve).showEyeDropper = m_ShowEyeDropper.GetValueFromBag(bag, cc); - ((ColorField)ve).showAlpha = m_ShowAlpha.GetValueFromBag(bag, cc); - ((ColorField)ve).hdr = m_Hdr.GetValueFromBag(bag, cc); - } - } - - public bool showEyeDropper { get; set; } - public bool showAlpha { get; set; } - public bool hdr { get; set; } - - private bool m_SetKbControl; - private bool m_ResetKbControl; - - private IMGUIContainer m_ColorField; - - // Since the ColorField is containing a child in the focus ring, - // it must make sure the child focus follow the focusIndex - public override int focusIndex - { - get { return base.focusIndex; } - set - { - base.focusIndex = value; - if (m_ColorField != null) - { - m_ColorField.focusIndex = value; - } - } - } - - - public ColorField() - { - showEyeDropper = true; - showAlpha = true; - - // The focus on a color field is implemented like a BaseCompoundField : the ColorField and its inner child - // are both put in the focus ring. When the ColorField is receiving the Focus, it is "delegating" it to the inner child, - // which is, in this case, the IMGUIContainer. - m_ColorField = new IMGUIContainer(OnGUIHandler) { name = "InternalColorField", useUIElementsFocusStyle = true }; - Add(m_ColorField); - } - - [Obsolete("This method is replaced by simply using this.value. The default behaviour has been changed to notify when changed. If the behaviour is not to be notified, SetValueWithoutNotify() must be used.", false)] - public override void SetValueAndNotify(Color newValue) - { - if (value != newValue) - { - value = newValue; - } - } - - protected internal override void ExecuteDefaultAction(EventBase evt) - { - base.ExecuteDefaultAction(evt); - - if (evt.GetEventTypeId() == FocusEvent.TypeId()) - { - m_SetKbControl = true; - // Make sure the inner IMGUIContainer is receiving the focus - m_ColorField.Focus(); - } - - if (evt.GetEventTypeId() == BlurEvent.TypeId()) - { - m_ResetKbControl = true; - } - } - - protected internal override void ExecuteDefaultActionAtTarget(EventBase evt) - { - if (evt.GetEventTypeId() == KeyDownEvent.TypeId()) - { - m_ColorField.HandleEvent(evt); - } - } - - private void OnGUIHandler() - { - // Dirty repaint on eye dropper update to preview the color under the cursor - if (Event.current.type == EventType.ExecuteCommand && Event.current.commandName == EventCommandNames.EyeDropperUpdate) - { - IncrementVersion(VersionChangeType.Repaint); - } - - Color newColor = EditorGUILayout.ColorField(GUIContent.none, value, showEyeDropper, showAlpha, hdr); - value = newColor; - if (m_SetKbControl) - { - GUIUtility.SetKeyboardControlToFirstControlId(); - m_SetKbControl = false; - } - if (m_ResetKbControl) - { - GUIUtility.keyboardControl = 0; - m_ResetKbControl = false; - } - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/CompoundFields.cs b/Editor/Mono/UIElements/Experimental/Controls/CompoundFields.cs deleted file mode 100644 index 49dec0aac8..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/CompoundFields.cs +++ /dev/null @@ -1,222 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class RectField : BaseCompositeField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BaseCompositeField.UxmlTraits - { - UxmlFloatAttributeDescription m_XValue = new UxmlFloatAttributeDescription { name = "x" }; - UxmlFloatAttributeDescription m_YValue = new UxmlFloatAttributeDescription { name = "y" }; - UxmlFloatAttributeDescription m_WValue = new UxmlFloatAttributeDescription { name = "w" }; - UxmlFloatAttributeDescription m_HValue = new UxmlFloatAttributeDescription { name = "h" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - RectField r = (RectField)ve; - r.SetValueWithoutNotify(new Rect(m_XValue.GetValueFromBag(bag, cc), m_YValue.GetValueFromBag(bag, cc), m_WValue.GetValueFromBag(bag, cc), m_HValue.GetValueFromBag(bag, cc))); - } - } - - internal override FieldDescription[] DescribeFields() - { - return new[] - { - new FieldDescription("X", r => r.x, (ref Rect r, float v) => r.x = v), - new FieldDescription("Y", r => r.y, (ref Rect r, float v) => r.y = v), - new FieldDescription("W", r => r.width, (ref Rect r, float v) => r.width = v), - new FieldDescription("H", r => r.height, (ref Rect r, float v) => r.height = v), - }; - } - } - - public class RectIntField : BaseCompositeField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BaseCompositeField.UxmlTraits - { - UxmlIntAttributeDescription m_XValue = new UxmlIntAttributeDescription { name = "x" }; - UxmlIntAttributeDescription m_YValue = new UxmlIntAttributeDescription { name = "y" }; - UxmlIntAttributeDescription m_WValue = new UxmlIntAttributeDescription { name = "w" }; - UxmlIntAttributeDescription m_HValue = new UxmlIntAttributeDescription { name = "h" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - var r = (RectIntField)ve; - r.SetValueWithoutNotify(new RectInt(m_XValue.GetValueFromBag(bag, cc), m_YValue.GetValueFromBag(bag, cc), m_WValue.GetValueFromBag(bag, cc), m_HValue.GetValueFromBag(bag, cc))); - } - } - - internal override FieldDescription[] DescribeFields() - { - return new[] - { - new FieldDescription("X", r => r.x, (ref RectInt r, int v) => r.x = v), - new FieldDescription("Y", r => r.y, (ref RectInt r, int v) => r.y = v), - new FieldDescription("W", r => r.width, (ref RectInt r, int v) => r.width = v), - new FieldDescription("H", r => r.height, (ref RectInt r, int v) => r.height = v), - }; - } - } - - public class Vector2Field : BaseCompositeField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BaseCompositeField.UxmlTraits - { - UxmlFloatAttributeDescription m_XValue = new UxmlFloatAttributeDescription { name = "x" }; - UxmlFloatAttributeDescription m_YValue = new UxmlFloatAttributeDescription { name = "y" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - Vector2Field f = (Vector2Field)ve; - f.value = new Vector2(m_XValue.GetValueFromBag(bag, cc), m_YValue.GetValueFromBag(bag, cc)); - } - } - - internal override FieldDescription[] DescribeFields() - { - return new[] - { - new FieldDescription("X", r => r.x, (ref Vector2 r, float v) => r.x = v), - new FieldDescription("Y", r => r.y, (ref Vector2 r, float v) => r.y = v), - }; - } - } - - public class Vector3Field : BaseCompositeField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BaseCompositeField.UxmlTraits - { - UxmlFloatAttributeDescription m_XValue = new UxmlFloatAttributeDescription { name = "x" }; - UxmlFloatAttributeDescription m_YValue = new UxmlFloatAttributeDescription { name = "y" }; - UxmlFloatAttributeDescription m_ZValue = new UxmlFloatAttributeDescription { name = "z" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - Vector3Field f = (Vector3Field)ve; - f.value = new Vector3(m_XValue.GetValueFromBag(bag, cc), m_YValue.GetValueFromBag(bag, cc), m_ZValue.GetValueFromBag(bag, cc)); - } - } - - internal override FieldDescription[] DescribeFields() - { - return new[] - { - new FieldDescription("X", r => r.x, (ref Vector3 r, float v) => r.x = v), - new FieldDescription("Y", r => r.y, (ref Vector3 r, float v) => r.y = v), - new FieldDescription("Z", r => r.z, (ref Vector3 r, float v) => r.z = v), - }; - } - } - - public class Vector4Field : BaseCompositeField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BaseCompositeField.UxmlTraits - { - UxmlFloatAttributeDescription m_XValue = new UxmlFloatAttributeDescription { name = "x" }; - UxmlFloatAttributeDescription m_YValue = new UxmlFloatAttributeDescription { name = "y" }; - UxmlFloatAttributeDescription m_ZValue = new UxmlFloatAttributeDescription { name = "z" }; - UxmlFloatAttributeDescription m_WValue = new UxmlFloatAttributeDescription { name = "w" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - Vector4Field f = (Vector4Field)ve; - f.value = new Vector4(m_XValue.GetValueFromBag(bag, cc), m_YValue.GetValueFromBag(bag, cc), m_ZValue.GetValueFromBag(bag, cc), m_WValue.GetValueFromBag(bag, cc)); - } - } - - internal override FieldDescription[] DescribeFields() - { - return new[] - { - new FieldDescription("X", r => r.x, (ref Vector4 r, float v) => r.x = v), - new FieldDescription("Y", r => r.y, (ref Vector4 r, float v) => r.y = v), - new FieldDescription("Z", r => r.z, (ref Vector4 r, float v) => r.z = v), - new FieldDescription("W", r => r.w, (ref Vector4 r, float v) => r.w = v), - }; - } - } - - public class Vector2IntField : BaseCompositeField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BaseCompositeField.UxmlTraits - { - UxmlIntAttributeDescription m_XValue = new UxmlIntAttributeDescription { name = "x" }; - UxmlIntAttributeDescription m_YValue = new UxmlIntAttributeDescription { name = "y" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - var f = (Vector2IntField)ve; - f.value = new Vector2Int(m_XValue.GetValueFromBag(bag, cc), m_YValue.GetValueFromBag(bag, cc)); - } - } - - internal override FieldDescription[] DescribeFields() - { - return new[] - { - new FieldDescription("X", r => r.x, (ref Vector2Int r, int v) => r.x = v), - new FieldDescription("Y", r => r.y, (ref Vector2Int r, int v) => r.y = v), - }; - } - } - - public class Vector3IntField : BaseCompositeField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BaseCompositeField.UxmlTraits - { - UxmlIntAttributeDescription m_XValue = new UxmlIntAttributeDescription { name = "x" }; - UxmlIntAttributeDescription m_YValue = new UxmlIntAttributeDescription { name = "y" }; - UxmlIntAttributeDescription m_ZValue = new UxmlIntAttributeDescription { name = "z" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - var f = (Vector3IntField)ve; - f.value = new Vector3Int(m_XValue.GetValueFromBag(bag, cc), m_YValue.GetValueFromBag(bag, cc), m_ZValue.GetValueFromBag(bag, cc)); - } - } - internal override FieldDescription[] DescribeFields() - { - return new[] - { - new FieldDescription("X", r => r.x, (ref Vector3Int r, int v) => r.x = v), - new FieldDescription("Y", r => r.y, (ref Vector3Int r, int v) => r.y = v), - new FieldDescription("Z", r => r.z, (ref Vector3Int r, int v) => r.z = v), - }; - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/CurveField.cs b/Editor/Mono/UIElements/Experimental/Controls/CurveField.cs deleted file mode 100644 index 9bfd43d676..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/CurveField.cs +++ /dev/null @@ -1,526 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine; -using UnityEditorInternal; -using UnityEngine.Experimental.UIElements; -using UnityEngine.Experimental.UIElements.StyleSheets; -using Object = UnityEngine.Object; - -namespace UnityEditor.Experimental.UIElements -{ - public class CurveField : BaseField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BaseField.UxmlTraits {} - - private const string k_CurveColorProperty = "curve-color"; - public Rect ranges { get; set; } - - StyleValue m_CurveColor; - private Color curveColor - { - get - { - return m_CurveColor.GetSpecifiedValueOrDefault(Color.green); - } - } - - private bool m_ValueNull; - private bool m_TextureDirty; - - public enum RenderMode - { - Texture, - Mesh, - Default = Texture - } - - RenderMode m_RenderMode = RenderMode.Default; - - public RenderMode renderMode - { - get { return m_RenderMode; } - set - { - if (m_RenderMode != value) - { - m_RenderMode = value; - - m_Content = new CurveFieldContent(); - if (renderMode == RenderMode.Mesh) - { - Insert(0, m_Content); - } - else - { - m_Content.RemoveFromHierarchy(); - m_Content = null; - } - - m_TextureDirty = true; - } - } - } - - internal static AnimationCurve CopyCurve(AnimationCurve other) - { - AnimationCurve curveCopy = new AnimationCurve(); - curveCopy.keys = other.keys; - curveCopy.preWrapMode = other.preWrapMode; - curveCopy.postWrapMode = other.postWrapMode; - return curveCopy; - } - - public override AnimationCurve value - { - get - { - if (m_ValueNull) return null; - - return CopyCurve(m_Value); - } - set - { - //I need to have total ownership of the curve, I won't be able to know if it is changed outside. so I'm duplicating it. - if (value != null || !m_ValueNull) // let's not reinitialize an initialized curve - { - if (panel != null) - { - using (ChangeEvent evt = ChangeEvent.GetPooled(m_Value, value)) - { - evt.target = this; - SetValueWithoutNotify(value); - SendEvent(evt); - } - } - else - { - SetValueWithoutNotify(value); - } - } - } - } - CurveFieldContent m_Content; - - public CurveField() - { - ranges = Rect.zero; - - m_Value = new AnimationCurve(new Keyframe[0]); - - VisualElement borderElement = new VisualElement() { name = "border", pickingMode = PickingMode.Ignore }; - Add(borderElement); - } - - void OnDetach() - { - if (m_Mesh != null) - Object.DestroyImmediate(m_Mesh); - if (style.backgroundImage.value != null) - Object.DestroyImmediate(style.backgroundImage.value); - m_Mesh = null; - style.backgroundImage = null; - m_TextureDirty = true; - } - - [Obsolete("This method is replaced by simply using this.value. The default behaviour has been changed to notify when changed. If the behaviour is not to be notified, SetValueWithoutNotify() must be used.", false)] - public override void SetValueAndNotify(AnimationCurve newValue) - { - value = newValue; - } - - public override void SetValueWithoutNotify(AnimationCurve newValue) - { - m_ValueNull = newValue == null; - if (!m_ValueNull) - { - m_Value.keys = newValue.keys; - m_Value.preWrapMode = newValue.preWrapMode; - m_Value.postWrapMode = newValue.postWrapMode; - } - else - { - m_Value.keys = new Keyframe[0]; - m_Value.preWrapMode = WrapMode.Once; - m_Value.postWrapMode = WrapMode.Once; - } - m_TextureDirty = true; - if (CurveEditorWindow.visible && Object.ReferenceEquals(CurveEditorWindow.curve, m_Value)) - { - CurveEditorWindow.curve = m_Value; - CurveEditorWindow.instance.Repaint(); - } - - IncrementVersion(VersionChangeType.Repaint); - - m_Content?.IncrementVersion(VersionChangeType.Repaint); - } - - protected override void OnStyleResolved(ICustomStyle style) - { - base.OnStyleResolved(style); - - Color color = curveColor; - style.ApplyCustomProperty(k_CurveColorProperty, ref m_CurveColor); - - if (color != curveColor && renderMode == RenderMode.Texture) - { - // The mesh texture is updated at each repaint, the standard texture should however be regenerated - m_TextureDirty = true; - } - } - - void ShowCurveEditor() - { - if (!enabledInHierarchy) - return; - - CurveEditorSettings settings = new CurveEditorSettings(); - if (m_Value == null) - m_Value = new AnimationCurve(); - CurveEditorWindow.instance.Show(OnCurveChanged, settings); - CurveEditorWindow.curve = m_Value; - - CurveEditorWindow.color = curveColor; - } - - protected internal override void ExecuteDefaultAction(EventBase evt) - { - base.ExecuteDefaultAction(evt); - - if ((evt as MouseDownEvent)?.button == (int)MouseButton.LeftMouse || (evt as KeyDownEvent)?.character == '\n') - ShowCurveEditor(); - else if (evt.GetEventTypeId() == DetachFromPanelEvent.TypeId()) - OnDetach(); - if (evt.GetEventTypeId() == GeometryChangedEvent.TypeId()) - m_TextureDirty = true; - } - - void OnCurveChanged(AnimationCurve curve) - { - CurveEditorWindow.curve = m_Value; - value = m_Value; - } - - public override void OnPersistentDataReady() - { - base.OnPersistentDataReady(); - m_TextureDirty = true; - } - - // Must be the same with AACurveField.shader - const float k_EdgeWidth = 2; - const float k_MinEdgeWidth = 1.75f; - const float k_HalfWidth = k_EdgeWidth * 0.5f; - const float k_VertexHalfWidth = k_HalfWidth + 1; - - const int k_HorizontalCurveResolution = 256; - - void FillCurveData() - { - AnimationCurve curve = value; - - if (m_Mesh == null) - { - m_Mesh = new Mesh(); - m_Mesh.hideFlags = HideFlags.HideAndDontSave; - - m_Content.SetMesh(m_Mesh); - } - - if (curve.keys.Length < 2) - return; - Vector3[] vertices = m_Mesh.vertices; - Vector3[] normals = m_Mesh.normals; - if (vertices == null || vertices.Length != k_HorizontalCurveResolution * 2) - { - vertices = new Vector3[k_HorizontalCurveResolution * 2]; - normals = new Vector3[k_HorizontalCurveResolution * 2]; - } - - float startTime = curve.keys[0].time; - float endTime = curve.keys[curve.keys.Length - 1].time; - float duration = endTime - startTime; - - float minValue = Mathf.Infinity; - float maxValue = -Mathf.Infinity; - - float[] timeCache = new float[k_HorizontalCurveResolution]; - int keyCount = curve.keys.Length; - int noKeySampleCount = k_HorizontalCurveResolution - keyCount; - - timeCache[0] = curve.keys[0].time; - - int usedSamples = 1; - for (int k = 1; k < keyCount; ++k) - { - float sliceStartTime = timeCache[usedSamples - 1]; - float sliceEndTime = curve.keys[k].time; - float sliceDuration = sliceEndTime - sliceStartTime; - int sliceSampleCount = Mathf.FloorToInt((float)noKeySampleCount * sliceDuration / duration); - if (k == keyCount - 1) - { - sliceSampleCount = k_HorizontalCurveResolution - usedSamples - 1; - } - - for (int i = 1; i < sliceSampleCount + 1; ++i) - { - float time = sliceStartTime + i * sliceDuration / (sliceSampleCount + 1); - timeCache[usedSamples + i - 1] = time; - } - - timeCache[usedSamples + sliceSampleCount] = curve.keys[k].time; - usedSamples += sliceSampleCount + 1; - } - - float[] valueCache = new float[k_HorizontalCurveResolution]; - - for (int i = 0; i < k_HorizontalCurveResolution; ++i) - { - float ct = timeCache[i]; - - float currentValue = curve.Evaluate(ct); - - if (currentValue > maxValue) - { - maxValue = currentValue; - } - if (currentValue < minValue) - { - minValue = currentValue; - } - - valueCache[i] = currentValue; - } - - Vector3 scale = new Vector3(m_Content.layout.width, m_Content.layout.height); - - vertices[0] = vertices[1] = Vector3.Scale(new Vector3(0, 1 - Mathf.InverseLerp(minValue, maxValue, valueCache[0]), 0), scale); - - Vector3 secondPoint = Vector3.Scale(new Vector3(1.0f / k_HorizontalCurveResolution, 1 - Mathf.InverseLerp(minValue, maxValue, valueCache[1]), 0), scale); - Vector3 prevDir = (secondPoint - vertices[0]).normalized; - - Vector3 norm = new Vector3(prevDir.y, -prevDir.x, 1); - - normals[0] = -norm * k_VertexHalfWidth; - normals[1] = norm * k_VertexHalfWidth; - - Vector3 currentPoint = secondPoint; - - for (int i = 1; i < k_HorizontalCurveResolution - 1; ++i) - { - vertices[i * 2] = vertices[i * 2 + 1] = currentPoint; - - Vector3 nextPoint = Vector3.Scale(new Vector3(Mathf.InverseLerp(startTime, endTime, timeCache[i + 1]), 1 - Mathf.InverseLerp(minValue, maxValue, valueCache[i + 1]), 0), scale); - - Vector3 nextDir = (nextPoint - currentPoint).normalized; - Vector3 dir = (prevDir + nextDir).normalized; - norm = new Vector3(dir.y, -dir.x, 1); - normals[i * 2] = -norm * k_VertexHalfWidth; - normals[i * 2 + 1] = norm * k_VertexHalfWidth; - - currentPoint = nextPoint; - prevDir = nextDir; - } - - vertices[(k_HorizontalCurveResolution - 1) * 2] = vertices[(k_HorizontalCurveResolution - 1) * 2 + 1] = currentPoint; - - norm = new Vector3(prevDir.y, -prevDir.x, 1); - normals[(k_HorizontalCurveResolution - 1) * 2] = -norm * k_VertexHalfWidth; - normals[(k_HorizontalCurveResolution - 1) * 2 + 1] = norm * k_VertexHalfWidth; - - m_Mesh.vertices = vertices; - m_Mesh.normals = normals; - - //fill triangle indices as it is a triangle strip - int[] indices = new int[(k_HorizontalCurveResolution * 2 - 2) * 3]; - - for (int i = 0; i < k_HorizontalCurveResolution * 2 - 2; ++i) - { - if ((i % 2) == 0) - { - indices[i * 3] = i; - indices[i * 3 + 1] = i + 1; - indices[i * 3 + 2] = i + 2; - } - else - { - indices[i * 3] = i + 1; - indices[i * 3 + 1] = i; - indices[i * 3 + 2] = i + 2; - } - } - - m_Mesh.triangles = indices; - } - - void SetupMeshRepaint() - { - if (m_TextureDirty || m_Mesh == null) - { - m_TextureDirty = false; - style.backgroundImage = null; - - FillCurveData(); - } - m_Content.curveColor = curveColor; - } - - void SetupStandardRepaint() - { - if (!m_TextureDirty) return; - - m_TextureDirty = false; - - int previewWidth = (int)layout.width; - int previewHeight = (int)layout.height; - - Rect rangeRect = new Rect(0, 0, 1, 1); - - if (ranges.width > 0 && ranges.height > 0) - { - rangeRect = ranges; - } - else if (!m_ValueNull && m_Value.keys.Length > 1) - { - float xMin = Mathf.Infinity; - float yMin = Mathf.Infinity; - float xMax = -Mathf.Infinity; - float yMax = -Mathf.Infinity; - - for (int i = 0; i < m_Value.keys.Length; ++i) - { - float y = m_Value.keys[i].value; - float x = m_Value.keys[i].time; - if (xMin > x) - { - xMin = x; - } - if (xMax < x) - { - xMax = x; - } - if (yMin > y) - { - yMin = y; - } - if (yMax < y) - { - yMax = y; - } - } - - if (yMin == yMax) - { - yMax = yMin + 1; - } - if (xMin == xMax) - { - xMax = xMin + 1; - } - - rangeRect = Rect.MinMaxRect(xMin, yMin, xMax, yMax); - } - - if (previewHeight > 0 && previewWidth > 0) - { - if (!m_ValueNull) - { - style.backgroundImage = AnimationCurvePreviewCache.GenerateCurvePreview( - previewWidth, - previewHeight, - rangeRect, - m_Value, - curveColor, - style.backgroundImage.value); - } - else - { - style.backgroundImage = null; - } - } - } - - Mesh m_Mesh = null; - protected override void DoRepaint(IStylePainter painter) - { - if (renderMode == RenderMode.Mesh) - { - SetupMeshRepaint(); - } - else - { - SetupStandardRepaint(); - } - } - - class CurveFieldContent : VisualElement - { - Material m_Mat; - Mesh m_Mesh; - - public Color curveColor { get; set; } - - public void SetMesh(Mesh mesh) - { - m_Mesh = mesh; - } - - public CurveFieldContent() - { - pickingMode = PickingMode.Ignore; - } - - protected internal override void ExecuteDefaultAction(EventBase evt) - { - base.ExecuteDefaultAction(evt); - - if (evt.GetEventTypeId() == DetachFromPanelEvent.TypeId()) - OnDetach(); - } - - void OnDetach() - { - Object.DestroyImmediate(m_Mat); - m_Mat = null; - } - - protected override void DoRepaint(IStylePainter painter) - { - if (m_Mesh != null) - { - if (m_Mat == null) - { - m_Mat = new Material(EditorGUIUtility.LoadRequired("Shaders/UIElements/AACurveField.shader") as Shader); - - m_Mat.hideFlags = HideFlags.HideAndDontSave; - } - - float scale = worldTransform.MultiplyVector(Vector3.one).x; - - float realWidth = CurveField.k_EdgeWidth; - if (realWidth * scale < CurveField.k_MinEdgeWidth) - { - realWidth = CurveField.k_MinEdgeWidth / scale; - } - - // Send the view zoom factor so that the antialias width do not grow when zooming in. - m_Mat.SetFloat("_ZoomFactor", scale * realWidth / CurveField.k_EdgeWidth * EditorGUIUtility.pixelsPerPoint); - - // Send the view zoom correction so that the vertex shader can scale the edge triangles when below m_MinWidth. - m_Mat.SetFloat("_ZoomCorrection", realWidth / CurveField.k_EdgeWidth); - - m_Mat.SetColor("_Color", (QualitySettings.activeColorSpace == ColorSpace.Linear) ? curveColor.gamma : curveColor); - - var stylePainter = (IStylePainterInternal)painter; - var meshParams = MeshStylePainterParameters.GetDefault(m_Mesh, m_Mat); - stylePainter.DrawMesh(meshParams); - } - } - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/DoubleField.cs b/Editor/Mono/UIElements/Experimental/Controls/DoubleField.cs deleted file mode 100644 index 30df7e9921..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/DoubleField.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class DoubleField : TextValueField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : TextValueField.UxmlTraits - { - UxmlDoubleAttributeDescription m_Value = new UxmlDoubleAttributeDescription { name = "value" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - ((DoubleField)ve).SetValueWithoutNotify(m_Value.GetValueFromBag(bag, cc)); - } - } - - public DoubleField() - : this(kMaxLengthNone) {} - - public DoubleField(int maxLength) - : base(maxLength) - { - formatString = EditorGUI.kDoubleFieldFormatString; - } - - protected override string allowedCharacters - { - get { return EditorGUI.s_AllowedCharactersForFloat; } - } - - public override void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, double startValue) - { - double sensitivity = NumericFieldDraggerUtility.CalculateFloatDragSensitivity(startValue); - float acceleration = NumericFieldDraggerUtility.Acceleration(speed == DeltaSpeed.Fast, speed == DeltaSpeed.Slow); - double v = value; - v += NumericFieldDraggerUtility.NiceDelta(delta, acceleration) * sensitivity; - v = MathUtils.RoundBasedOnMinimumDifference(v, sensitivity); - value = v; - } - - protected override string ValueToString(double v) - { - return v.ToString(formatString); - } - - protected override double StringToValue(string str) - { - double v; - EditorGUI.StringToDouble(str, out v); - return v; - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/EnumField.cs b/Editor/Mono/UIElements/Experimental/Controls/EnumField.cs deleted file mode 100644 index 9a510795e5..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/EnumField.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class EnumField : BaseField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BaseField.UxmlTraits - { - UxmlStringAttributeDescription m_Type = new UxmlStringAttributeDescription { name = "type", use = UxmlAttributeDescription.Use.Required}; - UxmlStringAttributeDescription m_Value = new UxmlStringAttributeDescription { name = "value" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - EnumField enumField = (EnumField)ve; - // Only works for the currently running assembly - enumField.m_EnumType = Type.GetType(m_Type.GetValueFromBag(bag, cc)); - if (enumField.m_EnumType != null) - { - string v = m_Value.GetValueFromBag(bag, cc); - - if (!Enum.IsDefined(enumField.m_EnumType, v)) - { - Debug.LogErrorFormat("Could not parse value of '{0}', because it isn't defined in the {1} enum.", v, enumField.m_EnumType.FullName); - enumField.SetValueWithoutNotify(null); - } - else - { - enumField.SetValueWithoutNotify((Enum)Enum.Parse(enumField.m_EnumType, v)); - } - } - } - } - - private Type m_EnumType; - private TextElement m_TextElement; - - public string text - { - get { return m_TextElement.text; } - } - - private void Initialize(Enum defaultValue) - { - m_TextElement = new TextElement(); - m_TextElement.pickingMode = PickingMode.Ignore; - Add(m_TextElement); - if (defaultValue != null) - { - Init(defaultValue); - } - } - - public EnumField() - { - Initialize(null); - } - - public EnumField(Enum defaultValue) - { - Initialize(defaultValue); - } - - public void Init(Enum defaultValue) - { - m_EnumType = defaultValue.GetType(); - SetValueWithoutNotify(defaultValue); - } - - [Obsolete("This method is replaced by simply using this.value. The default behaviour has been changed to notify when changed. If the behaviour is not to be notified, SetValueWithoutNotify() must be used.", false)] - public override void SetValueAndNotify(Enum newValue) - { - if (value != newValue) - { - value = newValue; - } - } - - public override void SetValueWithoutNotify(Enum newValue) - { - if (m_Value != newValue) - { - base.SetValueWithoutNotify(newValue); - m_TextElement.text = ObjectNames.NicifyVariableName(m_Value.ToString()); - } - } - - protected internal override void ExecuteDefaultActionAtTarget(EventBase evt) - { - base.ExecuteDefaultActionAtTarget(evt); - - if ((evt as MouseDownEvent)?.button == (int)MouseButton.LeftMouse || (evt as KeyDownEvent)?.character == '\n') - { - ShowMenu(); - evt.StopPropagation(); - } - } - - private void ShowMenu() - { - if (m_EnumType == null) - return; - - var menu = new GenericMenu(); - - foreach (Enum item in Enum.GetValues(m_EnumType)) - { - bool isSelected = item.CompareTo(value) == 0; - string label = ObjectNames.NicifyVariableName(item.ToString()); - menu.AddItem(new GUIContent(label), isSelected, - contentView => ChangeValueFromMenu(contentView), - item); - } - - var menuPosition = new Vector2(0.0f, layout.height); - menuPosition = this.LocalToWorld(menuPosition); - var menuRect = new Rect(menuPosition, Vector2.zero); - menu.DropDown(menuRect); - } - - private void ChangeValueFromMenu(object menuItem) - { - value = menuItem as Enum; - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/FloatField.cs b/Editor/Mono/UIElements/Experimental/Controls/FloatField.cs deleted file mode 100644 index 80704b1811..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/FloatField.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class FloatField : TextValueField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : TextValueField.UxmlTraits - { - UxmlFloatAttributeDescription m_Value = new UxmlFloatAttributeDescription { name = "value" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - ((FloatField)ve).SetValueWithoutNotify(m_Value.GetValueFromBag(bag, cc)); - } - } - - public FloatField() - : this(kMaxLengthNone) {} - - public FloatField(int maxLength) - : base(maxLength) - { - formatString = EditorGUI.kFloatFieldFormatString; - } - - protected override string allowedCharacters - { - get { return EditorGUI.s_AllowedCharactersForFloat; } - } - - public override void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, float startValue) - { - double sensitivity = NumericFieldDraggerUtility.CalculateFloatDragSensitivity(startValue); - float acceleration = NumericFieldDraggerUtility.Acceleration(speed == DeltaSpeed.Fast, speed == DeltaSpeed.Slow); - double v = value; - v += NumericFieldDraggerUtility.NiceDelta(delta, acceleration) * sensitivity; - v = MathUtils.RoundBasedOnMinimumDifference(v, sensitivity); - value = MathUtils.ClampToFloat(v); - } - - protected override string ValueToString(float v) - { - return v.ToString(formatString); - } - - protected override float StringToValue(string str) - { - double v; - EditorGUI.StringToDouble(str, out v); - return MathUtils.ClampToFloat(v); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/GradientField.cs b/Editor/Mono/UIElements/Experimental/Controls/GradientField.cs deleted file mode 100644 index 10177ce0e4..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/GradientField.cs +++ /dev/null @@ -1,155 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine; -using UnityEditorInternal; -using UnityEngine.Experimental.UIElements; -using Object = UnityEngine.Object; - -namespace UnityEditor.Experimental.UIElements -{ - public class GradientField : BaseField - { - static readonly GradientColorKey k_WhiteKeyBegin = new GradientColorKey(Color.white, 0); - static readonly GradientColorKey k_WhiteKeyEnd = new GradientColorKey(Color.white, 1); - static readonly GradientAlphaKey k_AlphaKeyBegin = new GradientAlphaKey(1, 0); - static readonly GradientAlphaKey k_AlphaKeyEnd = new GradientAlphaKey(1, 1); - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BaseField.UxmlTraits {} - - private bool m_ValueNull; - public override Gradient value - { - get - { - if (m_ValueNull) return null; - - return GradientCopy(m_Value); - } - set - { - if (value != null || !m_ValueNull) // let's not reinitialize an initialized gradient - { - if (panel != null) - { - using (ChangeEvent evt = ChangeEvent.GetPooled(m_Value, value)) - { - evt.target = this; - SetValueWithoutNotify(value); - SendEvent(evt); - } - } - else - { - SetValueWithoutNotify(value); - } - } - } - } - - internal static Gradient GradientCopy(Gradient other) - { - Gradient gradientCopy = new Gradient(); - gradientCopy.colorKeys = other.colorKeys; - gradientCopy.alphaKeys = other.alphaKeys; - gradientCopy.mode = other.mode; - return gradientCopy; - } - - public GradientField() - { - VisualElement borderElement = new VisualElement() { name = "border", pickingMode = PickingMode.Ignore }; - Add(borderElement); - - m_Value = new Gradient(); - } - - protected internal override void ExecuteDefaultAction(EventBase evt) - { - base.ExecuteDefaultAction(evt); - - if ((evt as MouseDownEvent)?.button == (int)MouseButton.LeftMouse || (evt as KeyDownEvent)?.character == '\n') - ShowGradientPicker(); - else if (evt.GetEventTypeId() == DetachFromPanelEvent.TypeId()) - OnDetach(); - else if (evt.GetEventTypeId() == AttachToPanelEvent.TypeId()) - OnAttach(); - } - - void OnDetach() - { - if (style.backgroundImage.value != null) - { - Object.DestroyImmediate(style.backgroundImage.value); - style.backgroundImage = null; - } - } - - void OnAttach() - { - UpdateGradientTexture(); - } - - void ShowGradientPicker() - { - GradientPicker.Show(m_Value, true, OnGradientChanged); - } - - public override void OnPersistentDataReady() - { - base.OnPersistentDataReady(); - UpdateGradientTexture(); - } - - void UpdateGradientTexture() - { - if (m_ValueNull) - { - style.backgroundImage = null; - } - else - { - Texture2D gradientTexture = UnityEditorInternal.GradientPreviewCache.GenerateGradientPreview(value, style.backgroundImage.value); - - style.backgroundImage = gradientTexture; - - IncrementVersion(VersionChangeType.Repaint); // since the Texture2D object can be reused, force dirty because the backgroundImage change will only trigger the Dirty if the Texture2D objects are different. - } - } - - void OnGradientChanged(Gradient newValue) - { - value = newValue; - - GradientPreviewCache.ClearCache(); // needed because GradientEditor itself uses the cache and will no invalidate it on changes. - IncrementVersion(VersionChangeType.Repaint); - } - - public override void SetValueWithoutNotify(Gradient newValue) - { - m_ValueNull = newValue == null; - if (!m_ValueNull) - { - m_Value.colorKeys = newValue.colorKeys; - m_Value.alphaKeys = newValue.alphaKeys; - m_Value.mode = newValue.mode; - } - else // restore the internal gradient to the default state. - { - m_Value.colorKeys = new[] { k_WhiteKeyBegin, k_WhiteKeyEnd }; - m_Value.alphaKeys = new[] { k_AlphaKeyBegin, k_AlphaKeyEnd }; - m_Value.mode = GradientMode.Blend; - } - UpdateGradientTexture(); - } - - [Obsolete("This method is replaced by simply using this.value. The default behaviour has been changed to notify when changed. If the behaviour is not to be notified, SetValueWithoutNotify() must be used.", false)] - public override void SetValueAndNotify(Gradient newValue) - { - value = newValue; - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/IntegerField.cs b/Editor/Mono/UIElements/Experimental/Controls/IntegerField.cs deleted file mode 100644 index d9aee658ab..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/IntegerField.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class IntegerField : TextValueField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : TextValueField.UxmlTraits - { - UxmlIntAttributeDescription m_Value = new UxmlIntAttributeDescription { name = "value" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - ((IntegerField)ve).SetValueWithoutNotify(m_Value.GetValueFromBag(bag, cc)); - } - } - - public IntegerField() - : this(kMaxLengthNone) {} - - public IntegerField(int maxLength) - : base(maxLength) - { - formatString = EditorGUI.kIntFieldFormatString; - } - - protected override string allowedCharacters - { - get { return EditorGUI.s_AllowedCharactersForInt; } - } - - public override void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, int startValue) - { - double sensitivity = NumericFieldDraggerUtility.CalculateIntDragSensitivity(startValue); - float acceleration = NumericFieldDraggerUtility.Acceleration(speed == DeltaSpeed.Fast, speed == DeltaSpeed.Slow); - long v = value; - v += (long)Math.Round(NumericFieldDraggerUtility.NiceDelta(delta, acceleration) * sensitivity); - value = MathUtils.ClampToInt(v); - } - - protected override string ValueToString(int v) - { - return v.ToString(formatString); - } - - protected override int StringToValue(string str) - { - long v; - EditorGUI.StringToLong(text, out v); - return MathUtils.ClampToInt(v); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/LayerField.cs b/Editor/Mono/UIElements/Experimental/Controls/LayerField.cs deleted file mode 100644 index d4dfd4841f..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/LayerField.cs +++ /dev/null @@ -1,123 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Experimental.UIElements; -using UnityEditorInternal; - -namespace UnityEditor.Experimental.UIElements -{ - public class LayerField : PopupField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : PopupField.UxmlTraits - { - UxmlIntAttributeDescription m_Value = new UxmlIntAttributeDescription { name = "value" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - var lf = (LayerField)ve; - lf.SetValueWithoutNotify(m_Value.GetValueFromBag(bag, cc)); - } - } - - internal override string GetValueToDisplay() - { - return InternalEditorUtility.GetLayerName(m_Value); - } - - public override int value - { - get { return base.value; } - set - { - if (m_Choices.Contains(value)) - { - base.value = value; - } - } - } - - public override Func formatSelectedValueCallback - { - get { return null; } - set - { - Debug.LogWarning(L10n.Tr("LayerField doesn't support the formatting of the selected value.")); - m_FormatSelectedValueCallback = null; - } - } - - public override Func formatListItemCallback - { - get { return null; } - set - { - Debug.LogWarning(L10n.Tr("LayerField doesn't support the formatting of the list items.")); - m_FormatListItemCallback = null; - } - } - - public override void SetValueWithoutNotify(int newValue) - { - if (m_Choices.Contains(newValue)) - { - base.SetValueWithoutNotify(newValue); - } - } - - static List InitializeLayers() - { - var listOfIndex = new List(); - for (var i = 0; i < 32; i++) - { - if (InternalEditorUtility.GetLayerName(i).Length != 0) - { - listOfIndex.Add(i); - } - } - return listOfIndex; - } - - public LayerField() : base(InitializeLayers()) - { - } - - public LayerField(int defaultValue) : this() - { - SetValueWithoutNotify(defaultValue); - } - - internal override void AddMenuItems(GenericMenu menu) - { - choices = InitializeLayers(); - string[] layerList = InternalEditorUtility.GetLayersWithId(); - for (var i = 0; i < layerList.Length; i++) - { - var item = layerList[i]; - var menuItemIndex = m_Choices[i]; - var isSelected = (menuItemIndex == value); - menu.AddItem(new GUIContent(item), isSelected, - () => ChangeValueFromMenu(menuItemIndex)); - } - menu.AddItem(new GUIContent(""), false, null); - menu.AddItem(new GUIContent(L10n.Tr("Add Layer...")), false, OpenLayerInspector); - } - - void ChangeValueFromMenu(int menuItemIndex) - { - value = menuItemIndex; - } - - static void OpenLayerInspector() - { - TagManagerInspector.ShowWithInitialExpansion(TagManagerInspector.InitialExpansionState.Layers); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/LayerMaskField.cs b/Editor/Mono/UIElements/Experimental/Controls/LayerMaskField.cs deleted file mode 100644 index c45001e5fe..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/LayerMaskField.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class LayerMaskField : MaskField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : MaskField.UxmlTraits {} - - public override Func formatSelectedValueCallback - { - get { return null; } - set - { - Debug.LogWarning(L10n.Tr("LayerMaskField doesn't support the formatting of the selected value.")); - m_FormatSelectedValueCallback = null; - } - } - - public override Func formatListItemCallback - { - get { return null; } - set - { - Debug.LogWarning(L10n.Tr("LayerMaskField doesn't support the formatting of the list items.")); - m_FormatListItemCallback = null; - } - } - - void UpdateLayersInfo() - { - // Get the layers : names and values - string[] layerNames = null; - int[] layerValues = null; - TagManager.GetDefinedLayers(ref layerNames, ref layerValues); - - // Create the appropriate lists... - choices = new List(layerNames); - choicesMasks = new List(layerValues); - } - - public LayerMaskField(int defaultMask) : this() - { - SetValueWithoutNotify(defaultMask); - } - - public LayerMaskField() - { - UpdateLayersInfo(); - } - - internal override void AddMenuItems(GenericMenu menu) - { - // We must update the choices and the values since we don't know if they changed... - UpdateLayersInfo(); - - // Create the menu the usual way... - base.AddMenuItems(menu); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/LongField.cs b/Editor/Mono/UIElements/Experimental/Controls/LongField.cs deleted file mode 100644 index 050990a1ce..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/LongField.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class LongField : TextValueField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : TextValueField.UxmlTraits - { - UxmlLongAttributeDescription m_Value = new UxmlLongAttributeDescription { name = "value" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - ((LongField)ve).SetValueWithoutNotify(m_Value.GetValueFromBag(bag, cc)); - } - } - - public LongField() - : this(kMaxLengthNone) {} - - public LongField(int maxLength) - : base(maxLength) - { - formatString = EditorGUI.kIntFieldFormatString; - } - - protected override string allowedCharacters - { - get { return EditorGUI.s_AllowedCharactersForInt; } - } - - public override void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, long startValue) - { - double sensitivity = NumericFieldDraggerUtility.CalculateIntDragSensitivity(startValue); - float acceleration = NumericFieldDraggerUtility.Acceleration(speed == DeltaSpeed.Fast, speed == DeltaSpeed.Slow); - long v = value; - v += (long)Math.Round(NumericFieldDraggerUtility.NiceDelta(delta, acceleration) * sensitivity); - value = v; - } - - protected override string ValueToString(long v) - { - return v.ToString(formatString); - } - - protected override long StringToValue(string str) - { - long v; - EditorGUI.StringToLong(text, out v); - return v; - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/MaskField.cs b/Editor/Mono/UIElements/Experimental/Controls/MaskField.cs deleted file mode 100644 index ff5c82e292..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/MaskField.cs +++ /dev/null @@ -1,428 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Experimental.UIElements; -using UnityEngine.Profiling; - -namespace UnityEditor.Experimental.UIElements -{ - public class MaskField : BasePopupField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BasePopupField.UxmlTraits - { - UxmlStringAttributeDescription m_MaskChoices = new UxmlStringAttributeDescription { name = "choices" }; - UxmlIntAttributeDescription m_MaskValue = new UxmlIntAttributeDescription { name = "value" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - var f = (MaskField)ve; - string choicesFromBag = m_MaskChoices.GetValueFromBag(bag, cc); - // Here the choices is comma separated in the string... - string[] choices = choicesFromBag.Split(','); - - if (choices.Length != 0) - { - List listOfChoices = new List(); - foreach (var choice in choices) - { - listOfChoices.Add(choice.Trim()); - } - f.choices = listOfChoices; - } - // The mask is simply an int - f.SetValueWithoutNotify(m_MaskValue.GetValueFromBag(bag, cc)); - } - } - - static int s_NothingIndex = 0; - static int s_EverythingIndex = 1; - static int s_TotalIndex = 2; - - // This is the list of string representing all the user choices - List m_UserChoices; - - // This is the list of masks for every specific choices... if null, the mask will be computed with the default values - // More details about this : - // In IMGUI, the MaskField is only allowing the creation of the field with an array of choices that will have a mask - // based on power of 2 value starting from 1. - // However, the LayerMaskField is created based on the Layers and do not necessarily has power of 2 consecutive masks. - // Therefore, this specific internal field (in IMGUI...) is requiring a specific array to contain the mask value of the - // actual list of choices. - List m_UserChoicesMasks; - - // This is containing a mask to cover all the choices from the list. Computed with the help of m_UserChoicesMasks - // or based on the power of 2 mask values. - int m_FullChoiceMask; - - internal override List choices - { - get { return m_UserChoices; } - set - { - if (value == null) - { - throw new ArgumentNullException("choices", "choices can't be null"); - } - - // Keep the original list in a separate user list ... - if (m_UserChoices == null) - { - m_UserChoices = new List(); - } - else - { - m_UserChoices.Clear(); - } - m_UserChoices.AddRange(value); - - // Now, add the nothing and everything choices... - if (m_Choices == null) - { - m_Choices = new List(); - } - else - { - m_Choices.Clear(); - } - m_Choices.Add(L10n.Tr("Nothing")); - m_Choices.Add(L10n.Tr("Everything")); - m_Choices.AddRange(m_UserChoices); - - ComputeFullChoiceMask(); - - // Make sure to update the text displayed - SetValueWithoutNotify(m_Value); - } - } - internal virtual List choicesMasks - { - get { return m_UserChoicesMasks; } - set - { - if (value == null) - { - m_UserChoicesMasks = null; - } - else - { - // Keep the original list in a separate user list ... - if (m_UserChoicesMasks == null) - { - m_UserChoicesMasks = new List(); - } - else - { - m_UserChoicesMasks.Clear(); - } - m_UserChoicesMasks.AddRange(value); - ComputeFullChoiceMask(); - // Make sure to update the text displayed - SetValueWithoutNotify(m_Value); - } - } - } - - public virtual Func formatSelectedValueCallback - { - get { return m_FormatSelectedValueCallback; } - set - { - m_FormatSelectedValueCallback = value; - m_TextElement.text = GetValueToDisplay(); - } - } - - public virtual Func formatListItemCallback - { - get { return m_FormatListItemCallback; } - set { m_FormatListItemCallback = value; } - } - - public override void SetValueWithoutNotify(int newValue) - { - base.SetValueWithoutNotify(UpdateMaskIfEverything(newValue)); - } - - internal override string GetListItemToDisplay(int itemIndex) - { - string displayedValue = GetDisplayedValue(itemIndex); - if (ShouldFormatListItem(itemIndex)) - displayedValue = m_FormatListItemCallback(displayedValue); - - return displayedValue; - } - - internal override string GetValueToDisplay() - { - string displayedValue = GetDisplayedValue(m_Value); - if (ShouldFormatSelectedValue()) - displayedValue = m_FormatSelectedValueCallback(displayedValue); - return displayedValue; - } - - // Trick to get the number of selected values... - // A power of 2 number means only 1 selected... - internal bool IsPowerOf2(int itemIndex) - { - return ((itemIndex & (itemIndex - 1)) == 0); - } - - internal bool ShouldFormatListItem(int itemIndex) - { - return itemIndex != 0 && itemIndex != -1 && m_FormatListItemCallback != null; - } - - internal bool ShouldFormatSelectedValue() - { - return m_Value != 0 && m_Value != -1 && m_FormatSelectedValueCallback != null && IsPowerOf2(m_Value); - } - - internal string GetDisplayedValue(int itemIndex) - { - var newValueToShowUser = ""; - - switch (itemIndex) - { - case 0: - newValueToShowUser = m_Choices[s_NothingIndex]; - break; - - case ~0: - newValueToShowUser = m_Choices[s_EverythingIndex]; - break; - - default: - // Show up the right selected value - if (IsPowerOf2(itemIndex)) - { - var indexOfValue = 0; - if (m_UserChoicesMasks != null) - { - // Find the actual index of the selected choice... - foreach (int itemMask in m_UserChoicesMasks) - { - if ((itemMask & itemIndex) == itemIndex) - { - indexOfValue = m_UserChoicesMasks.IndexOf(itemMask); - break; - } - } - } - else - { - while ((1 << indexOfValue) != itemIndex) - { - indexOfValue++; - } - } - - // To get past the Nothing + Everything choices... - indexOfValue += s_TotalIndex; - if (indexOfValue < m_Choices.Count) - { - newValueToShowUser = m_Choices[indexOfValue]; - } - } - else - { - newValueToShowUser = L10n.Tr("Mixed ..."); - } - break; - } - return newValueToShowUser; - } - - internal override void AddMenuItems(GenericMenu menu) - { - foreach (var item in m_Choices) - { - var maskOfItem = GetMaskValueOfItem(item); - var isSelected = false; - switch (maskOfItem) - { - case 0: - if (value == 0) - { - isSelected = true; - } - break; - - case ~0: - if (value == ~0) - { - isSelected = true; - } - break; - - default: - if ((maskOfItem & value) == maskOfItem) - { - isSelected = true; - } - break; - } - - menu.AddItem(new GUIContent(GetListItemToDisplay(maskOfItem)), isSelected, () => ChangeValueFromMenu(item)); - } - } - - void ComputeFullChoiceMask() - { - // Compute the full mask for all the items... it is not necessarily ~0 (which is all bits set to 1) - if (m_UserChoices.Count == 0) - { - m_FullChoiceMask = 0; - } - else - { - if ((m_UserChoicesMasks != null) && (m_UserChoicesMasks.Count == m_UserChoices.Count)) - { - if (m_UserChoices.Count >= (sizeof(int) * 8)) - { - m_FullChoiceMask = ~0; - } - else - { - m_FullChoiceMask = 0; - foreach (int itemMask in m_UserChoicesMasks) - { - m_FullChoiceMask |= itemMask; - } - } - } - else - { - if (m_UserChoices.Count >= (sizeof(int) * 8)) - { - m_FullChoiceMask = ~0; - } - else - { - m_FullChoiceMask = (1 << m_UserChoices.Count) - 1; - } - } - } - } - - private MaskField(List choices, Func formatSelectedValueCallback = null, Func formatListItemCallback = null) - { - this.choices = choices; - m_FormatListItemCallback = formatListItemCallback; - m_FormatSelectedValueCallback = formatSelectedValueCallback; - } - - public MaskField(List choices, int defaultMask, Func formatSelectedValueCallback = null, Func formatListItemCallback = null) : - this(choices, formatSelectedValueCallback, formatListItemCallback) - { - SetValueWithoutNotify(defaultMask); - } - - public MaskField() - { - } - - // Returns the mask to be used for the item... - int GetMaskValueOfItem(string item) - { - var maskValue = 0; - var indexOfItem = m_Choices.IndexOf(item); - switch (indexOfItem) - { - case 0: // Nothing - maskValue = 0; - break; - case 1: // Everything - maskValue = ~0; - break; - default: // All others - if (indexOfItem > 0) - { - if ((m_UserChoicesMasks != null) && (m_UserChoicesMasks.Count == m_UserChoices.Count)) - { - maskValue = m_UserChoicesMasks[(indexOfItem - s_TotalIndex)]; - } - else - { - maskValue = 1 << (indexOfItem - s_TotalIndex); - } - } - else - { - // If less than 0, it means the item was not found... - maskValue = 0; - } - - break; - } - return maskValue; - } - - // Based on the current mask, this is updating the value of the actual mask to use vs the full mask. - // This is returning ~0 if all the values are selected... - int UpdateMaskIfEverything(int currentMask) - { - int newMask = currentMask; - // If the mask is full, put back the Everything flag. - if (m_FullChoiceMask != 0) - { - if ((currentMask & m_FullChoiceMask) == m_FullChoiceMask) - { - newMask = ~0; - } - else - { - newMask &= m_FullChoiceMask; - } - } - - return newMask; - } - - private void ChangeValueFromMenu(string menuItem) - { - var newMask = value; - var maskFromItem = GetMaskValueOfItem(menuItem); - switch (maskFromItem) - { - // Nothing - case 0: - newMask = 0; - break; - - // Everything - case ~0: - newMask = ~0; - break; - - default: - // Make sure to have only the real selected one... - newMask &= m_FullChoiceMask; - - // Add or remove the newly selected... - if ((newMask & maskFromItem) == maskFromItem) - { - newMask &= ~maskFromItem; - } - else - { - newMask |= maskFromItem; - } - - // If the mask is full, put back the Everything flag. - newMask = UpdateMaskIfEverything(newMask); - break; - } - // Finally, make sure to update the value of the mask... - value = newMask; - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/ObjectField.cs b/Editor/Mono/UIElements/Experimental/Controls/ObjectField.cs deleted file mode 100644 index 08d6283a15..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/ObjectField.cs +++ /dev/null @@ -1,256 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Experimental.UIElements; -using Object = UnityEngine.Object; - -namespace UnityEditor.Experimental.UIElements -{ - public class ObjectField : BaseField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : BaseField.UxmlTraits - { - UxmlBoolAttributeDescription m_AllowSceneObjects = new UxmlBoolAttributeDescription { name = "allow-scene-objects", obsoleteNames = new[] { "allowSceneObjects" }, defaultValue = true }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - ((ObjectField)ve).allowSceneObjects = m_AllowSceneObjects.GetValueFromBag(bag, cc); - } - } - - public override void SetValueWithoutNotify(Object newValue) - { - var valueChanged = !EqualityComparer.Default.Equals(this.value, newValue); - - base.SetValueWithoutNotify(newValue); - - if (valueChanged) - { - m_ObjectFieldDisplay.Update(); - } - } - - private Type m_objectType; - - public Type objectType - { - get { return m_objectType; } - set - { - if (m_objectType != value) - { - m_objectType = value; - m_ObjectFieldDisplay.Update(); - } - } - } - - public bool allowSceneObjects { get; set; } - - private class ObjectFieldDisplay : VisualElement - { - private readonly ObjectField m_ObjectField; - private readonly Image m_ObjectIcon; - private readonly Label m_ObjectLabel; - - public ObjectFieldDisplay(ObjectField objectField) - { - m_ObjectIcon = new Image {scaleMode = ScaleMode.ScaleAndCrop, pickingMode = PickingMode.Ignore}; - m_ObjectLabel = new Label {pickingMode = PickingMode.Ignore}; - m_ObjectField = objectField; - - Update(); - - Add(m_ObjectIcon); - Add(m_ObjectLabel); - } - - public void Update() - { - GUIContent content = EditorGUIUtility.ObjectContent(m_ObjectField.value, m_ObjectField.objectType); - m_ObjectIcon.image = content.image; - m_ObjectLabel.text = content.text; - } - - protected internal override void ExecuteDefaultActionAtTarget(EventBase evt) - { - base.ExecuteDefaultActionAtTarget(evt); - - if ((evt as MouseDownEvent)?.button == (int)MouseButton.LeftMouse) - OnMouseDown(evt as MouseDownEvent); - else if ((evt as KeyDownEvent)?.character == '\n') - OnKeyboardEnter(); - else if (evt.GetEventTypeId() == DragUpdatedEvent.TypeId()) - OnDragUpdated(evt); - else if (evt.GetEventTypeId() == DragPerformEvent.TypeId()) - OnDragPerform(evt); - else if (evt.GetEventTypeId() == DragLeaveEvent.TypeId()) - OnDragLeave(); - } - - private void OnDragLeave() - { - // Make sure we've cleared the accept drop look, whether we we in a drop operation or not. - RemoveFromClassList("acceptDrop"); - } - - private void OnMouseDown(MouseDownEvent evt) - { - Object actualTargetObject = m_ObjectField.value; - Component com = actualTargetObject as Component; - if (com) - actualTargetObject = com.gameObject; - - if (actualTargetObject == null) - return; - - // One click shows where the referenced object is, or pops up a preview - if (evt.clickCount == 1) - { - // ping object - bool anyModifiersPressed = evt.shiftKey || evt.ctrlKey; - if (!anyModifiersPressed && actualTargetObject) - { - EditorGUIUtility.PingObject(actualTargetObject); - } - evt.StopPropagation(); - } - // Double click opens the asset in external app or changes selection to referenced object - else if (evt.clickCount == 2) - { - if (actualTargetObject) - { - AssetDatabase.OpenAsset(actualTargetObject); - GUIUtility.ExitGUI(); - } - evt.StopPropagation(); - } - } - - private void OnKeyboardEnter() - { - m_ObjectField.ShowObjectSelector(); - } - - private Object DNDValidateObject() - { - Object[] references = DragAndDrop.objectReferences; - Object validatedObject = EditorGUI.ValidateObjectFieldAssignment(references, m_ObjectField.objectType, null, EditorGUI.ObjectFieldValidatorOptions.None); - - if (validatedObject != null) - { - // If scene objects are not allowed and object is a scene object then clear - if (!m_ObjectField.allowSceneObjects && !EditorUtility.IsPersistent(validatedObject)) - validatedObject = null; - } - return validatedObject; - } - - private void OnDragUpdated(EventBase evt) - { - Object validatedObject = DNDValidateObject(); - if (validatedObject != null) - { - DragAndDrop.visualMode = DragAndDropVisualMode.Generic; - AddToClassList("acceptDrop"); - - evt.StopPropagation(); - } - } - - private void OnDragPerform(EventBase evt) - { - Object validatedObject = DNDValidateObject(); - if (validatedObject != null) - { - DragAndDrop.visualMode = DragAndDropVisualMode.Generic; - m_ObjectField.value = validatedObject; - - DragAndDrop.AcceptDrag(); - RemoveFromClassList("acceptDrop"); - - evt.StopPropagation(); - } - } - } - - private class ObjectFieldSelector : VisualElement - { - private readonly ObjectField m_ObjectField; - - public ObjectFieldSelector(ObjectField objectField) - { - m_ObjectField = objectField; - } - - protected internal override void ExecuteDefaultAction(EventBase evt) - { - base.ExecuteDefaultAction(evt); - - if ((evt as MouseDownEvent)?.button == (int)MouseButton.LeftMouse) - m_ObjectField.ShowObjectSelector(); - } - } - - public override int focusIndex - { - get { return base.focusIndex; } - set - { - base.focusIndex = value; - if (m_ObjectFieldDisplay != null) - { - m_ObjectFieldDisplay.focusIndex = value; - } - } - } - - private readonly ObjectFieldDisplay m_ObjectFieldDisplay; - - public ObjectField() - { - allowSceneObjects = true; - - m_ObjectFieldDisplay = new ObjectFieldDisplay(this) {focusIndex = 0}; - var objectSelector = new ObjectFieldSelector(this); - - Add(m_ObjectFieldDisplay); - Add(objectSelector); - } - - [Obsolete("This method is replaced by simply using this.value. The default behaviour has been changed to notify when changed. If the behaviour is not to be notified, SetValueWithoutNotify() must be used.", false)] - public override void SetValueAndNotify(Object newValue) - { - if (newValue != value) - { - value = newValue; - } - } - - protected internal override void ExecuteDefaultAction(EventBase evt) - { - base.ExecuteDefaultAction(evt); - - if (evt.GetEventTypeId() == FocusEvent.TypeId()) - m_ObjectFieldDisplay.Focus(); - } - - private void OnObjectChanged(Object obj) - { - value = obj; - } - - internal void ShowObjectSelector() - { - ObjectSelector.get.Show(value, objectType, null, allowSceneObjects, null, OnObjectChanged, OnObjectChanged); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/PopupField.cs b/Editor/Mono/UIElements/Experimental/Controls/PopupField.cs deleted file mode 100644 index 3f5247cc0f..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/PopupField.cs +++ /dev/null @@ -1,133 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class PopupField : BasePopupField - { - public virtual Func formatSelectedValueCallback - { - get { return m_FormatSelectedValueCallback; } - set - { - m_FormatSelectedValueCallback = value; - m_TextElement.text = GetValueToDisplay(); - } - } - - public virtual Func formatListItemCallback - { - get { return m_FormatListItemCallback; } - set { m_FormatListItemCallback = value; } - } - - internal override string GetValueToDisplay() - { - if (m_FormatSelectedValueCallback != null) - return m_FormatSelectedValueCallback(value); - return value.ToString(); - } - - internal override string GetListItemToDisplay(T value) - { - if (m_FormatListItemCallback != null) - return m_FormatListItemCallback(value); - return value.ToString(); - } - - public override T value - { - get { return base.value; } - set - { - int newIndex = m_Choices.IndexOf(value); - if (newIndex < 0) - { - throw new ArgumentException(string.Format("Value {0} is not present in the list of possible values", value)); - } - m_Index = newIndex; - - base.value = value; - } - } - - public override void SetValueWithoutNotify(T newValue) - { - int newIndex = m_Choices.IndexOf(newValue); - if (newIndex < 0) - { - throw new ArgumentException(string.Format("Value {0} is not present in the list of possible values", newValue)); - } - m_Index = newIndex; - - base.SetValueWithoutNotify(newValue); - } - - private int m_Index = -1; - public int index - { - get { return m_Index; } - set - { - if (value != m_Index) - { - if (value >= m_Choices.Count || value < 0) - throw new ArgumentException(string.Format("Index {0} is beyond the scope of possible value", value)); - m_Index = value; - this.value = m_Choices[m_Index]; - } - } - } - - protected PopupField(List choices, Func formatSelectedValueCallback = null, Func formatListItemCallback = null) - { - this.choices = choices; - m_FormatSelectedValueCallback = formatSelectedValueCallback; - m_FormatListItemCallback = formatListItemCallback; - } - - public PopupField(List choices, T defaultValue, Func formatSelectedValueCallback = null, Func formatListItemCallback = null) : - this(choices, formatSelectedValueCallback, formatListItemCallback) - { - if (defaultValue == null) - throw new ArgumentNullException("defaultValue", "defaultValue can't be null"); - - if (!m_Choices.Contains(defaultValue)) - throw new ArgumentException(string.Format("Default value {0} is not present in the list of possible values", defaultValue)); - - // Note: idx will be set when setting value - SetValueWithoutNotify(defaultValue); - } - - public PopupField(List choices, int defaultIndex, Func formatSelectedValueCallback = null, Func formatListItemCallback = null) : - this(choices, formatSelectedValueCallback, formatListItemCallback) - { - if (defaultIndex >= m_Choices.Count || defaultIndex < 0) - throw new ArgumentException(string.Format("Default Index {0} is beyond the scope of possible value", value)); - - // Note: value will be set when setting idx - index = defaultIndex; - } - - internal override void AddMenuItems(GenericMenu menu) - { - foreach (T item in m_Choices) - { - bool isSelected = EqualityComparer.Default.Equals(item, value); - menu.AddItem(new GUIContent(GetListItemToDisplay(item)), isSelected, - () => ChangeValueFromMenu(item)); - } - } - - private void ChangeValueFromMenu(T menuItem) - { - value = menuItem; - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/PropertyControl.cs b/Editor/Mono/UIElements/Experimental/Controls/PropertyControl.cs deleted file mode 100644 index 8136226ed6..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/PropertyControl.cs +++ /dev/null @@ -1,312 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - static class BuiltInTypeConverter - { - static Dictionary s_TypeDictionary; - - static BuiltInTypeConverter() - { - if (s_TypeDictionary == null) - { - s_TypeDictionary = new Dictionary(); - s_TypeDictionary.Add("bool", typeof(long)); - s_TypeDictionary.Add("byte", typeof(byte)); - s_TypeDictionary.Add("sbyte", typeof(sbyte)); - s_TypeDictionary.Add("char", typeof(char)); - s_TypeDictionary.Add("decimal", typeof(decimal)); - s_TypeDictionary.Add("double", typeof(double)); - s_TypeDictionary.Add("float", typeof(float)); - s_TypeDictionary.Add("int", typeof(int)); - s_TypeDictionary.Add("uint", typeof(uint)); - s_TypeDictionary.Add("long", typeof(long)); - s_TypeDictionary.Add("ulong", typeof(ulong)); - s_TypeDictionary.Add("object", typeof(object)); - s_TypeDictionary.Add("short", typeof(short)); - s_TypeDictionary.Add("ushort", typeof(ushort)); - s_TypeDictionary.Add("string", typeof(string)); - } - } - - public static Type GetTypeFromName(string typeName) - { - Type t; - if (!s_TypeDictionary.TryGetValue(typeName, out t)) - { - t = Type.GetType(typeName); - } - - return t; - } - } - internal class PropertyControl : BaseField - { - public new class UxmlFactory : UxmlFactory, UxmlTraits> - { - public override string uxmlName - { - get - { - string name = typeof(PropertyControl).Name; - if (name.Contains("`")) - { - name = name.Substring(0, name.IndexOf("`")); - } - return name; - } - } - - public override string uxmlQualifiedName - { - get { return uxmlNamespace + "." + uxmlName; } - } - - public override bool AcceptsAttributeBag(IUxmlAttributes bag, CreationContext cc) - { - string type = m_Traits.GetValueType(bag, cc); - if (BuiltInTypeConverter.GetTypeFromName(type) == typeof(TType)) - { - return true; - } - - return false; - } - } - - public new class UxmlTraits : BaseField.UxmlTraits - { - UxmlStringAttributeDescription m_TypeOf = new UxmlStringAttributeDescription { name = "value-type", obsoleteNames = new[] {"typeOf"}, use = UxmlAttributeDescription.Use.Required }; - UxmlStringAttributeDescription m_Value = new UxmlStringAttributeDescription { name = "value" }; - UxmlStringAttributeDescription m_Label = new UxmlStringAttributeDescription { name = "label" }; - - public UxmlTraits() - { - m_TypeOf.restriction = new UxmlEnumeration - { - values = Enum.GetValues(typeof(DataType)).Cast() - .Where(dt => dt != DataType.Unsupported) - .Select(dt => dt.ToString()).ToList() - }; - } - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - var initValue = m_Value.GetValueFromBag(bag, cc); - var text = m_Label.GetValueFromBag(bag, cc); - ((PropertyControl)ve).SetValueWithoutNotify(((PropertyControl)ve).StringToValue(initValue)); - ((PropertyControl)ve).label = text; - } - - public string GetValueType(IUxmlAttributes bag, CreationContext cc) - { - return m_TypeOf.GetValueFromBag(bag, cc); - } - } - - enum DataType - { - Long, - Double, - Int, - Float, - String, - Unsupported - } - - private Func GetValueDelegate; - private Action SetValueDelegate; - - private Label m_Label; - private BaseField m_Field; - - public PropertyControl() - : this("") - {} - - public PropertyControl(string labelText) - { - Init("", labelText); - } - - private void Init(string initialValue, string labelText) - { - CacheType(); - - AddToClassList("propertyControl"); - m_Label = new Label(labelText); - - Add(m_Label); - CreateControl(); - SetValueWithoutNotify(StringToValue(initialValue)); - - EnableMouseDraggerForNumericType(); - } - - DataType dataType { get; set; } - - private void CacheType() - { - var ttype = typeof(TType); - if (ttype == typeof(long)) - dataType = DataType.Long; - else if (ttype == typeof(int)) - dataType = DataType.Int; - else if (ttype == typeof(float)) - dataType = DataType.Float; - else if (ttype == typeof(double)) - dataType = DataType.Double; - else if (ttype == typeof(string)) - dataType = DataType.String; - else - { - dataType = DataType.Unsupported; - throw new NotSupportedException($"Unsupported type for PropertyControl {ttype}"); - } - } - - private void EnableMouseDraggerForNumericType() - { - switch (dataType) - { - case DataType.Long: - AddLabelDragger(); - break; - case DataType.Int: - AddLabelDragger(); - break; - case DataType.Float: - AddLabelDragger(); - break; - case DataType.Double: - AddLabelDragger(); - break; - default: - break; - } - } - - private void AddLabelDragger() - { - var dragger = new FieldMouseDragger((IValueField)m_Field); - dragger.SetDragZone(m_Label); - - m_Label.AddToClassList("propertyControlDragger"); - } - - private static TTo ConvertType(TFrom value) - { - return (TTo)Convert.ChangeType(value, typeof(TTo)); - } - - private void CreateControl() where TControlType : BaseField, new() - { - var c = new TControlType(); - GetValueDelegate = () => ConvertType(c.value); - SetValueDelegate = (x) => c.value = ConvertType(x); - m_Field = c as BaseField; - } - - private void CreateControl() - { - switch (dataType) - { - case DataType.Long: - CreateControl(); - break; - case DataType.Int: - CreateControl(); - break; - case DataType.Float: - CreateControl(); - break; - case DataType.Double: - CreateControl(); - break; - case DataType.String: - CreateControl(); - break; - } - - if (m_Field == null) - throw new NotSupportedException($"Unsupported type attribute: {typeof(TType)}"); - - m_Field.AddToClassList("propertyControlControl"); - m_Field.OnValueChanged(OnFieldValueChanged); - Add(m_Field); - } - - public string label - { - get { return m_Label.text; } - set { m_Label.text = value; } - } - - private TType StringToValue(string str) - { - switch (dataType) - { - case DataType.Long: - case DataType.Int: - { - long v; - EditorGUI.StringToLong(str, out v); - return ConvertType(v); - } - case DataType.Double: - case DataType.Float: - { - double v; - EditorGUI.StringToDouble(str, out v); - return ConvertType(v); - } - } - return ConvertType(str); - } - - private void OnFieldValueChanged(ChangeEvent evt) - { - using (ChangeEvent newEvent = ChangeEvent.GetPooled(evt.previousValue, evt.newValue)) - { - newEvent.target = this; - SendEvent(newEvent); - } - } - - public override void SetValueWithoutNotify(TType newValue) - { - m_Field.SetValueWithoutNotify(newValue); - } - - [Obsolete("This method is replaced by simply using this.value. The default behaviour has been changed to notify when changed. If the behaviour is not to be notified, SetValueWithoutNotify() must be used.", false)] - public override void SetValueAndNotify(TType newValue) - { - value = newValue; - } - - public override TType value - { - get { return GetValueDelegate(); } - set { SetValueDelegate(value); } - } - - protected internal override void ExecuteDefaultAction(EventBase evt) - { - base.ExecuteDefaultAction(evt); - - // Delegate focus to the control - if (evt.GetEventTypeId() == FocusEvent.TypeId()) - m_Field.Focus(); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/TagField.cs b/Editor/Mono/UIElements/Experimental/Controls/TagField.cs deleted file mode 100644 index 85e5c19b64..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/TagField.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Experimental.UIElements; -using UnityEditorInternal; - -namespace UnityEditor.Experimental.UIElements -{ - public class TagField : PopupField - { - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : PopupField.UxmlTraits - { - UxmlStringAttributeDescription m_Value = new UxmlStringAttributeDescription { name = "value" }; - - public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc) - { - base.Init(ve, bag, cc); - - var tagField = (TagField)ve; - tagField.SetValueWithoutNotify(m_Value.GetValueFromBag(bag, cc)); - } - } - - internal override string GetValueToDisplay() - { - return m_Value; - } - - public override string value - { - get { return base.value; } - set - { - // Allow the setting of value outside of Tags, but do nothing with them... - if (m_Choices.Contains(value)) - { - base.value = value; - } - } - } - - public override void SetValueWithoutNotify(string newValue) - { - // Allow the setting of value outside of Tags, but do nothing with them... - if (m_Choices.Contains(newValue)) - { - base.SetValueWithoutNotify(newValue); - } - } - - public override Func formatSelectedValueCallback - { - get { return null; } - set - { - Debug.LogWarning(L10n.Tr("TagField doesn't support the formatting of the selected value.")); - m_FormatSelectedValueCallback = null; - } - } - - public override Func formatListItemCallback - { - get { return null; } - set - { - Debug.LogWarning(L10n.Tr("TagField doesn't support the formatting of the list items.")); - m_FormatListItemCallback = null; - } - } - - static List InitializeTags() - { - return new List(InternalEditorUtility.tags); - } - - public TagField() : base(InitializeTags()) {} - - public TagField(string defaultValue) : this() - { - SetValueWithoutNotify(defaultValue); - } - - internal override void AddMenuItems(GenericMenu menu) - { - choices = InitializeTags(); - foreach (var menuItem in choices) - { - var isSelected = (menuItem == value); - menu.AddItem(new GUIContent(menuItem), isSelected, () => ChangeValueFromMenu(menuItem)); - } - menu.AddItem(new GUIContent(""), false, null); // This is a separator... - menu.AddItem(new GUIContent(L10n.Tr("Add Tag...")), false, OpenTagInspector); - } - - void ChangeValueFromMenu(string menuItem) - { - value = menuItem; - } - - static void OpenTagInspector() - { - TagManagerInspector.ShowWithInitialExpansion(TagManagerInspector.InitialExpansionState.Tags); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Controls/TextValueField.cs b/Editor/Mono/UIElements/Experimental/Controls/TextValueField.cs deleted file mode 100644 index b8ec857cfc..0000000000 --- a/Editor/Mono/UIElements/Experimental/Controls/TextValueField.cs +++ /dev/null @@ -1,153 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public enum DeltaSpeed - { - Fast, - Normal, - Slow - } - - public interface IValueField - { - T value { get; set; } - - void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, T startValue); - } - - // Implements a control with a value of type T backed by a text. - public abstract class TextValueField : TextInputFieldBase, IValueField - { - public new class UxmlTraits : TextInputFieldBase.UxmlTraits {} - - protected TextValueField(int maxLength) - : base(maxLength, Char.MinValue) - { - m_UpdateTextFromValue = true; - SetValueWithoutNotify(default(T)); - } - - private bool m_UpdateTextFromValue; - - public override T value - { - get { return base.value; } - set - { - base.value = value; - if (m_UpdateTextFromValue) - text = ValueToString(m_Value); - } - } - - private void UpdateValueFromText() - { - T newValue = StringToValue(text); - value = newValue; - } - - public override void SetValueWithoutNotify(T newValue) - { - base.SetValueWithoutNotify(newValue); - if (!isDelayed && m_UpdateTextFromValue) - { - // Value is the same but the text might not be in sync - // In the case of an expression like 2+2, the text might not be equal to the result - text = ValueToString(m_Value); - } - } - - [Obsolete("This method is replaced by simply using this.value. The default behaviour has been changed to notify when changed. If the behaviour is not to be notified, SetValueWithoutNotify() must be used.", false)] - public override void SetValueAndNotify(T newValue) - { - if (!EqualityComparer.Default.Equals(value, newValue)) - { - value = newValue; - } - } - - internal override bool AcceptCharacter(char c) - { - return c != 0 && allowedCharacters.IndexOf(c) != -1; - } - - protected abstract string allowedCharacters { get; } - - public string formatString { get; set; } - - public abstract void ApplyInputDeviceDelta(Vector3 delta, DeltaSpeed speed, T startValue); - - protected abstract string ValueToString(T value); - - protected abstract T StringToValue(string str); - - protected internal override void ExecuteDefaultActionAtTarget(EventBase evt) - { - base.ExecuteDefaultActionAtTarget(evt); - - bool hasChanged = false; - if (evt.GetEventTypeId() == KeyDownEvent.TypeId()) - { - KeyDownEvent kde = evt as KeyDownEvent; - if (kde.character == '\n') - { - UpdateValueFromText(); - } - else - { - hasChanged = true; - } - } - else if (evt.GetEventTypeId() == ExecuteCommandEvent.TypeId()) - { - ExecuteCommandEvent commandEvt = evt as ExecuteCommandEvent; - string cmdName = commandEvt.commandName; - if (cmdName == EventCommandNames.Paste || cmdName == EventCommandNames.Cut) - { - hasChanged = true; - } - } - - if (!isDelayed && hasChanged) - { - // Prevent text from changing when the value change - // This allow expression (2+2) or string like 00123 to remain as typed in the TextField until enter is pressed - m_UpdateTextFromValue = false; - try - { - UpdateValueFromText(); - } - finally - { - m_UpdateTextFromValue = true; - } - } - } - - protected internal override void ExecuteDefaultAction(EventBase evt) - { - base.ExecuteDefaultAction(evt); - - if (evt.GetEventTypeId() == BlurEvent.TypeId()) - { - if (string.IsNullOrEmpty(text)) - { - // Make sure that empty field gets the default value - value = default(T); - } - else - { - UpdateValueFromText(); - } - } - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/EditorContextualMenuManager.cs b/Editor/Mono/UIElements/Experimental/EditorContextualMenuManager.cs deleted file mode 100644 index 599abe328d..0000000000 --- a/Editor/Mono/UIElements/Experimental/EditorContextualMenuManager.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - class EditorContextualMenuManager : ContextualMenuManager - { - public override void DisplayMenuIfEventMatches(EventBase evt, IEventHandler eventHandler) - { - if (Application.platform == RuntimePlatform.OSXEditor || Application.platform == RuntimePlatform.OSXPlayer) - { - if (evt.GetEventTypeId() == MouseDownEvent.TypeId()) - { - MouseDownEvent e = evt as MouseDownEvent; - - if (e.button == (int)MouseButton.RightMouse || - (e.button == (int)MouseButton.LeftMouse && e.modifiers == EventModifiers.Control)) - { - DisplayMenu(evt, eventHandler); - evt.StopPropagation(); - return; - } - } - } - else - { - if (evt.GetEventTypeId() == MouseUpEvent.TypeId()) - { - MouseUpEvent e = evt as MouseUpEvent; - if (e.button == (int)MouseButton.RightMouse) - { - DisplayMenu(evt, eventHandler); - evt.StopPropagation(); - return; - } - } - } - - if (evt.GetEventTypeId() == KeyUpEvent.TypeId()) - { - KeyUpEvent e = evt as KeyUpEvent; - if (e.keyCode == KeyCode.Menu) - { - DisplayMenu(evt, eventHandler); - evt.StopPropagation(); - } - } - } - - protected internal override void DoDisplayMenu(DropdownMenu menu, EventBase triggerEvent) - { - menu.DoDisplayEditorMenu(triggerEvent); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/EditorCursor.cs b/Editor/Mono/UIElements/Experimental/EditorCursor.cs deleted file mode 100644 index b01eb0916d..0000000000 --- a/Editor/Mono/UIElements/Experimental/EditorCursor.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - internal class EditorCursorManager : ICursorManager - { - public void SetCursor(CursorStyle cursor) - { - if (GUIView.current == null) - { - // Cannot set the cursor if the current view is null. - return; - } - - if (cursor.texture != null) - { - EditorGUIUtility.SetCurrentViewCursor(cursor.texture, cursor.hotspot, MouseCursor.CustomCursor); - } - else - { - EditorGUIUtility.SetCurrentViewCursor(null, Vector2.zero, (MouseCursor)cursor.defaultCursorId); - } - } - - public void ResetCursor() - { - if (GUIView.current == null) - { - // Cannot clear the cursor if the current view is null. - return; - } - EditorGUIUtility.ClearCurrentViewCursor(); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/EditorMenuExtensions.cs b/Editor/Mono/UIElements/Experimental/EditorMenuExtensions.cs deleted file mode 100644 index af126c40e7..0000000000 --- a/Editor/Mono/UIElements/Experimental/EditorMenuExtensions.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - static class EditorMenuExtensions - { - static GenericMenu PrepareMenu(DropdownMenu menu, EventBase triggerEvent) - { - menu.PrepareForDisplay(triggerEvent); - - var genericMenu = new GenericMenu(); - foreach (var item in menu.MenuItems()) - { - var action = item as DropdownMenu.MenuAction; - if (action != null) - { - if ((action.status & DropdownMenu.MenuAction.StatusFlags.Hidden) == DropdownMenu.MenuAction.StatusFlags.Hidden) - { - continue; - } - - bool isChecked = (action.status & DropdownMenu.MenuAction.StatusFlags.Checked) == DropdownMenu.MenuAction.StatusFlags.Checked; - - if ((action.status & DropdownMenu.MenuAction.StatusFlags.Disabled) == DropdownMenu.MenuAction.StatusFlags.Disabled) - { - genericMenu.AddDisabledItem(new GUIContent(action.name)); - } - else - { - genericMenu.AddItem(new GUIContent(action.name), isChecked, () => - { - action.Execute(); - }); - } - } - else - { - var separator = item as DropdownMenu.Separator; - if (separator != null) - { - genericMenu.AddSeparator(separator.subMenuPath); - } - } - } - - return genericMenu; - } - - public static void DoDisplayEditorMenu(this DropdownMenu menu, Vector2 position) - { - PrepareMenu(menu, null).DropDown(new Rect(position, Vector2.zero)); - } - - public static void DoDisplayEditorMenu(this DropdownMenu menu, EventBase triggerEvent) - { - GenericMenu genericMenu = PrepareMenu(menu, triggerEvent); - - Vector2 position = Vector2.zero; - if (triggerEvent is IMouseEvent) - { - position = ((IMouseEvent)triggerEvent).mousePosition; - } - else if (triggerEvent.target is VisualElement) - { - position = ((VisualElement)triggerEvent.target).layout.center; - } - - genericMenu.DropDown(new Rect(position, Vector2.zero)); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/EditorWindowPersistentViewData.cs b/Editor/Mono/UIElements/Experimental/EditorWindowPersistentViewData.cs deleted file mode 100644 index 91542ac827..0000000000 --- a/Editor/Mono/UIElements/Experimental/EditorWindowPersistentViewData.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using UnityEditor; -using UnityEngine; -using UnityEngine.Experimental.UIElements; -using SerializableJsonDictionary = UnityEditor.Experimental.UIElements.SerializableJsonDictionary; - -namespace UnityEditor.Experimental.UIElements -{ - [LibraryFolderPath("UIElements/EditorWindows")] - internal class EditorWindowPersistentViewData : ScriptableSingletonDictionary< - EditorWindowPersistentViewData, - SerializableJsonDictionary> - { - public static SerializableJsonDictionary GetEditorData(EditorWindow window) - { - string editorPrefFileName = window.GetType().ToString(); - return instance[editorPrefFileName]; - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/FieldMouseDragger.cs b/Editor/Mono/UIElements/Experimental/FieldMouseDragger.cs deleted file mode 100644 index e5776aac28..0000000000 --- a/Editor/Mono/UIElements/Experimental/FieldMouseDragger.cs +++ /dev/null @@ -1,101 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class FieldMouseDragger - { - public FieldMouseDragger(IValueField drivenField) - { - m_DrivenField = drivenField; - m_DragElement = null; - m_DragHotZone = new Rect(0, 0, -1, -1); - dragging = false; - } - - IValueField m_DrivenField; - VisualElement m_DragElement; - Rect m_DragHotZone; - - public bool dragging; - public T startValue; - - public void SetDragZone(VisualElement dragElement) - { - SetDragZone(dragElement, new Rect(0, 0, -1, -1)); - } - - public void SetDragZone(VisualElement dragElement, Rect hotZone) - { - if (m_DragElement != null) - { - m_DragElement.UnregisterCallback(UpdateValueOnMouseDown); - m_DragElement.UnregisterCallback(UpdateValueOnMouseMove); - m_DragElement.UnregisterCallback(UpdateValueOnMouseUp); - m_DragElement.UnregisterCallback(UpdateValueOnKeyDown); - } - - m_DragElement = dragElement; - m_DragHotZone = hotZone; - - if (m_DragElement != null) - { - dragging = false; - m_DragElement.RegisterCallback(UpdateValueOnMouseDown); - m_DragElement.RegisterCallback(UpdateValueOnMouseMove); - m_DragElement.RegisterCallback(UpdateValueOnMouseUp); - m_DragElement.RegisterCallback(UpdateValueOnKeyDown); - } - } - - void UpdateValueOnMouseDown(MouseDownEvent evt) - { - if (evt.button == 0 && (m_DragHotZone.width < 0 || m_DragHotZone.height < 0 || m_DragHotZone.Contains(m_DragElement.WorldToLocal(evt.mousePosition)))) - { - m_DragElement.CaptureMouse(); - - // Make sure no other elements can capture the mouse! - evt.StopPropagation(); - - dragging = true; - startValue = m_DrivenField.value; - - EditorGUIUtility.SetWantsMouseJumping(1); - } - } - - void UpdateValueOnMouseMove(MouseMoveEvent evt) - { - if (dragging) - { - DeltaSpeed s = evt.shiftKey ? DeltaSpeed.Fast : (evt.altKey ? DeltaSpeed.Slow : DeltaSpeed.Normal); - m_DrivenField.ApplyInputDeviceDelta(evt.mouseDelta, s, startValue); - } - } - - void UpdateValueOnMouseUp(MouseUpEvent evt) - { - if (dragging) - { - dragging = false; - MouseCaptureController.ReleaseMouse(); - EditorGUIUtility.SetWantsMouseJumping(0); - } - } - - void UpdateValueOnKeyDown(KeyDownEvent evt) - { - if (dragging && evt.keyCode == KeyCode.Escape) - { - dragging = false; - m_DrivenField.value = startValue; - MouseCaptureController.ReleaseMouse(); - EditorGUIUtility.SetWantsMouseJumping(0); - } - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/PanelDebug.cs b/Editor/Mono/UIElements/Experimental/PanelDebug.cs deleted file mode 100644 index 64a7ad2615..0000000000 --- a/Editor/Mono/UIElements/Experimental/PanelDebug.cs +++ /dev/null @@ -1,183 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - internal class PanelDebug : IPanelDebug - { - private HashSet m_Debuggers = new HashSet(); - private List m_RepaintDatas = new List(); - private IPanel m_Panel; - private bool m_IsShowingOverlay = false; - - public bool showOverlay - { - get - { - foreach (var debugger in m_Debuggers) - { - if (debugger.showOverlay) - return true; - } - - return false; - } - } - - public uint highlightedElement { get; private set; } = 0; - - public PanelDebug(IPanel panel) - { - m_Panel = panel; - } - - public void AttachDebugger(IPanelDebugger debugger) - { - if (m_Debuggers.Add(debugger)) - { - debugger.panelDebug = this; - m_Panel.visualTree.MarkDirtyRepaint(); - } - } - - public void DetachDebugger(IPanelDebugger debugger) - { - debugger.panelDebug = null; - m_Debuggers.Remove(debugger); - m_Panel.visualTree.MarkDirtyRepaint(); - } - - public void Refresh() - { - if (showOverlay) - { - RecordRepaintData(m_Panel.visualTree); - DrawRepaintData(); - m_IsShowingOverlay = true; - } - else if (m_IsShowingOverlay) - { - // Clear the overlay - m_IsShowingOverlay = false; - m_Panel.visualTree.MarkDirtyRepaint(); - } - - foreach (var debugger in m_Debuggers) - { - debugger.Refresh(); - } - } - - public bool InterceptEvents(Event ev) - { - bool intercepted = false; - foreach (var debugger in m_Debuggers) - { - intercepted |= debugger.InterceptEvents(ev); - } - - return intercepted; - } - - public void SetHighlightElement(VisualElement ve) - { - var controlId = ve != null ? ve.controlid : 0; - if (highlightedElement != controlId) - { - highlightedElement = controlId; - m_Panel.visualTree.MarkDirtyRepaint(); - } - } - - private void RecordRepaintData(VisualElement ve) - { - m_RepaintDatas.Add(new RepaintData(ve.controlid, - ve.worldBound, - Color.HSVToRGB(ve.controlid * 11 % 32 / 32.0f, .6f, 1.0f))); - - for (int i = 0; i < ve.shadow.childCount; i++) - { - var child = ve.shadow[i]; - RecordRepaintData(child); - } - } - - public void DrawRepaintData() - { - RepaintData onTopElement = null; - foreach (var repaintData in m_RepaintDatas) - { - var color = repaintData.color; - if (highlightedElement != 0) - if (highlightedElement != repaintData.controlId) - { - color = Color.gray; - } - else - { - onTopElement = repaintData; - continue; - } - DrawRect(repaintData.contentRect, color); - } - - m_RepaintDatas.Clear(); - if (onTopElement != null) - DrawRect(onTopElement.contentRect, onTopElement.color); - } - - public static void DrawRect(Rect sp, Color c) - { - sp.xMin++; - sp.xMax--; - sp.yMin++; - sp.yMax--; - - HandleUtility.ApplyWireMaterial(); - GL.PushMatrix(); - GL.Begin(GL.LINES); - - GL.Color(c); - GL.Vertex3(sp.xMin, sp.yMin, 0); - GL.Color(c); - GL.Vertex3(sp.xMax, sp.yMin, 0); - - GL.Color(c); - GL.Vertex3(sp.xMax, sp.yMin, 0); - GL.Color(c); - GL.Vertex3(sp.xMax, sp.yMax, 0); - - GL.Color(c); - GL.Vertex3(sp.xMax, sp.yMax, 0); - GL.Color(c); - GL.Vertex3(sp.xMin, sp.yMax, 0); - - GL.Color(c); - GL.Vertex3(sp.xMin, sp.yMax, 0); - GL.Color(c); - GL.Vertex3(sp.xMin, sp.yMin, 0); - GL.End(); - GL.PopMatrix(); - } - - private class RepaintData - { - public readonly Color color; - public readonly Rect contentRect; - public readonly uint controlId; - - public RepaintData(uint controlId, Rect contentRect, Color color) - { - this.contentRect = contentRect; - this.color = color; - this.controlId = controlId; - } - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Toolbar/IToolbarMenuElement.cs b/Editor/Mono/UIElements/Experimental/Toolbar/IToolbarMenuElement.cs deleted file mode 100644 index 02229cf103..0000000000 --- a/Editor/Mono/UIElements/Experimental/Toolbar/IToolbarMenuElement.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System.Linq; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public interface IToolbarMenuElement - { - DropdownMenu menu { get; } - } - - public static class ToolbarMenuElementExtensions - { - public static void ShowMenu(this IToolbarMenuElement tbe) - { - if (!tbe.menu.MenuItems().Any()) - return; - - var ve = tbe as VisualElement; - if (ve == null) - return; - - Vector2 pos = new Vector2(ve.layout.xMin, ve.layout.yMax); - pos = ve.parent.LocalToWorld(pos); - - tbe.menu.DoDisplayEditorMenu(pos); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Toolbar/Toolbar.cs b/Editor/Mono/UIElements/Experimental/Toolbar/Toolbar.cs deleted file mode 100644 index acc41fb541..0000000000 --- a/Editor/Mono/UIElements/Experimental/Toolbar/Toolbar.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class Toolbar : VisualElement - { - public new class UxmlFactory : UxmlFactory {} - - internal static void SetToolbarStyleSheet(VisualElement ve) - { - ve.AddStyleSheetPath("StyleSheets/ToolbarCommon.uss"); - ve.AddStyleSheetPath("StyleSheets/Toolbar" + (EditorGUIUtility.isProSkin ? "Dark" : "Light") + ".uss"); - } - - public Toolbar() - { - SetToolbarStyleSheet(this); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarButton.cs b/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarButton.cs deleted file mode 100644 index 4ecb87e6aa..0000000000 --- a/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarButton.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class ToolbarButton : Button - { - public new class UxmlFactory : UxmlFactory {} - public new class UxmlTraits : Button.UxmlTraits {} - - const string k_ClassName = "toolbarButton"; - public ToolbarButton(Action clickEvent) : - base(clickEvent) - { - Toolbar.SetToolbarStyleSheet(this); - AddToClassList(k_ClassName); - } - - public ToolbarButton() : this(() => {}) - { - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarMenu.cs b/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarMenu.cs deleted file mode 100644 index 40f83c6f23..0000000000 --- a/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarMenu.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public abstract class ToolbarMenuBase : TextElement, IToolbarMenuElement - { - Clickable clickable; - - public DropdownMenu menu { get; } - - protected ToolbarMenuBase(string classList) : - this() - { - Toolbar.SetToolbarStyleSheet(this); - AddToClassList(classList); - } - - ToolbarMenuBase() - { - clickable = new Clickable(this.ShowMenu); - this.AddManipulator(clickable); - menu = new DropdownMenu(); - } - } - - public class ToolbarMenu : ToolbarMenuBase - { - public new class UxmlFactory : UxmlFactory {} - public new class UxmlTraits : TextElement.UxmlTraits {} - - const string k_ClassName = "toolbarMenu"; - public ToolbarMenu() : - base(k_ClassName) - { - } - } - - public class ToolbarPopup : ToolbarMenuBase - { - public new class UxmlFactory : UxmlFactory {} - public new class UxmlTraits : TextElement.UxmlTraits {} - - const string k_ClassName = "toolbarPopup"; - public ToolbarPopup() : - base(k_ClassName) - { - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarPopupSearchField.cs b/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarPopupSearchField.cs deleted file mode 100644 index 5dc36e7c9b..0000000000 --- a/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarPopupSearchField.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class ToolbarPopupSearchField : ToolbarSearchField, IToolbarMenuElement - { - public new class UxmlFactory : UxmlFactory {} - - const string k_SearchButtonClassName = "toolbarSearchFieldPopup"; - - public DropdownMenu menu { get; } - - public ToolbarPopupSearchField() : - base(k_SearchButtonClassName) - { - menu = new DropdownMenu(); - m_SearchButton.clickable.clicked += this.ShowMenu; - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarSearchField.cs b/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarSearchField.cs deleted file mode 100644 index 2ed54290a1..0000000000 --- a/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarSearchField.cs +++ /dev/null @@ -1,139 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class ToolbarSearchField : VisualElement, INotifyValueChanged - { - public new class UxmlFactory : UxmlFactory {} - - const string k_ClassName = "toolbarSearchField"; - - const string k_SearchButtonClassName = "toolbarSearchFieldButton"; - - const string k_EmptyEndClassName = "toolbarSearchFieldEnd"; - const string k_CancelButtonEndClassName = "toolbarSearchFieldCancelButton"; - - protected Button m_SearchButton; - Button m_CancelButton; - TextField m_TextField; - - string m_CurrentText; - - public string value - { - get - { - return m_CurrentText; - } - set - { - if (m_CurrentText == value) - return; - - if (panel != null) - { - using (ChangeEvent evt = ChangeEvent.GetPooled(m_CurrentText, value)) - { - evt.target = this; - SetValueWithoutNotify(value); - SendEvent(evt); - } - } - else - { - SetValueWithoutNotify(value); - } - } - } - - public ToolbarSearchField() : - this(k_SearchButtonClassName) - { - Toolbar.SetToolbarStyleSheet(this); - } - - protected ToolbarSearchField(string searchButtonStyleClassName) - { - m_CurrentText = String.Empty; - - AddToClassList(k_ClassName); - - m_SearchButton = new Button(() => {}); - m_SearchButton.AddToClassList(searchButtonStyleClassName); - shadow.Add(m_SearchButton); - - m_TextField = new TextField(); - m_SearchButton.shadow.Add(m_TextField); - m_TextField.OnValueChanged(OnTextChanged); - m_TextField.RegisterCallback(OnTextFieldKeyDown); - - m_CancelButton = new Button(() => {}); - m_CancelButton.AddToClassList(k_EmptyEndClassName); - shadow.Add(m_CancelButton); - } - - void OnTextChanged(ChangeEvent change) - { - value = change.newValue; - } - - void ClearTextField() - { - value = String.Empty; - } - - void OnTextFieldKeyDown(KeyDownEvent evt) - { - if (evt.keyCode == KeyCode.Escape) - ClearTextField(); - } - - void OnCancelButtonClick() - { - ClearTextField(); - } - - public void SetValueWithoutNotify(string newValue) - { - if (m_CurrentText == newValue) - return; - - if (string.IsNullOrEmpty(m_CurrentText) && !string.IsNullOrEmpty(newValue)) - { - m_CancelButton.RemoveFromClassList(k_EmptyEndClassName); - m_CancelButton.AddToClassList(k_CancelButtonEndClassName); - m_CancelButton.clickable.clicked += OnCancelButtonClick; - } - else if (!string.IsNullOrEmpty(m_CurrentText) && string.IsNullOrEmpty(newValue)) - { - m_CancelButton.AddToClassList(k_EmptyEndClassName); - m_CancelButton.RemoveFromClassList(k_CancelButtonEndClassName); - m_CancelButton.clickable.clicked -= OnCancelButtonClick; - } - - m_CurrentText = newValue; - m_TextField.value = m_CurrentText; - } - - [Obsolete("This method is replaced by simply using this.value. The default behaviour has been changed to notify when changed. If the behaviour is not to be notified, SetValueWithoutNotify() must be used.", false)] - public void SetValueAndNotify(string newValue) - { - } - - public void OnValueChanged(EventCallback> callback) - { - RegisterCallback(callback); - } - - public void RemoveOnValueChanged(EventCallback> callback) - { - UnregisterCallback(callback); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarSpacer.cs b/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarSpacer.cs deleted file mode 100644 index 53c49176b8..0000000000 --- a/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarSpacer.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class ToolbarSpacer : VisualElement - { - public new class UxmlFactory : UxmlFactory {} - - const string k_ClassName = "toolbarSpacer"; - public ToolbarSpacer() - { - Toolbar.SetToolbarStyleSheet(this); - AddToClassList(k_ClassName); - } - } - - public class ToolbarFlexSpacer : ToolbarSpacer - { - public new class UxmlFactory : UxmlFactory {} - - const string k_ClassName = "toolbarFlexSpacer"; - public ToolbarFlexSpacer() - { - ClearClassList(); - AddToClassList(k_ClassName); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarToggle.cs b/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarToggle.cs deleted file mode 100644 index b112a7cce0..0000000000 --- a/Editor/Mono/UIElements/Experimental/Toolbar/ToolbarToggle.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - public class ToolbarToggle : Toggle - { - public new class UxmlFactory : UxmlFactory {} - public new class UxmlTraits : Toggle.UxmlTraits {} - - const string k_ClassName = "toolbarButton"; - public ToolbarToggle() - { - Toolbar.SetToolbarStyleSheet(this); - AddToClassList(k_ClassName); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/Tooltip.cs b/Editor/Mono/UIElements/Experimental/Tooltip.cs deleted file mode 100644 index 3aa5dc1da0..0000000000 --- a/Editor/Mono/UIElements/Experimental/Tooltip.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using UnityEngine; -using UnityEngine.Experimental.UIElements; -using UnityEngine.Experimental.UIElements.StyleEnums; -using RequiredByNativeCodeAttribute = UnityEngine.Scripting.RequiredByNativeCodeAttribute; - -namespace UnityEditor.Experimental.UIElements -{ - static class Tooltip - { - internal static void SetTooltip(float mouseX, float mouseY) - { - //mouseX,mouseY are screen relative. - GUIView view = GUIView.mouseOverView; - if (view != null && view.uieMode == GUIView.UIElementsMode.Experimental && view.experimentalVisualTree != null && view.experimentalVisualTree.panel != null) - { - var panel = view.experimentalVisualTree.panel; - - // Pick expect view relative coordinates. - VisualElement target = panel.Pick(new Vector2(mouseX, mouseY) - view.screenPosition.position); - if (target != null) - { - using (var tooltipEvent = TooltipEvent.GetPooled()) - { - tooltipEvent.target = target; - tooltipEvent.tooltip = null; - tooltipEvent.rect = Rect.zero; - target.SendEvent(tooltipEvent); - - if (!string.IsNullOrEmpty(tooltipEvent.tooltip) && !tooltipEvent.isDefaultPrevented) - { - Rect rect = tooltipEvent.rect; - rect.position += view.screenPosition.position; //SetMouseTooltip expects Screen relative coordinates. - - GUIStyle.SetMouseTooltip(tooltipEvent.tooltip, rect); - } - } - } - } - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/UIElementsEditorUtility.cs b/Editor/Mono/UIElements/Experimental/UIElementsEditorUtility.cs deleted file mode 100644 index 4d92682374..0000000000 --- a/Editor/Mono/UIElements/Experimental/UIElementsEditorUtility.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using UnityEngine; -using UnityEngine.Experimental.UIElements; -using UnityEngine.Experimental.UIElements.StyleSheets; - -namespace UnityEditor.Experimental.UIElements -{ - public static class UIElementsEditorUtility - { - internal static readonly string s_DefaultCommonStyleSheetPath = "StyleSheets/Experimental/DefaultCommon.uss"; - internal static readonly string s_DefaultCommonDarkStyleSheetPath = "StyleSheets/Experimental/DefaultCommonDark.uss"; - internal static readonly string s_DefaultCommonLightStyleSheetPath = "StyleSheets/Experimental/DefaultCommonLight.uss"; - - public static CursorStyle CreateDefaultCursorStyle(MouseCursor mouseCursor) - { - return new CursorStyle() { texture = null, hotspot = Vector2.zero, defaultCursorId = (int)mouseCursor }; - } - - internal static int GetCursorId(UnityEngine.UIElements.StyleSheet sheet, UnityEngine.UIElements.StyleValueHandle handle) - { - return StyleSheetCache.GetEnumValue(sheet, handle); - } - - internal static void AddDefaultEditorStyleSheets(VisualElement p) - { - if (p.styleSheets == null) - { - p.AddStyleSheetPath(s_DefaultCommonStyleSheetPath); - if (EditorGUIUtility.isProSkin) - { - p.AddStyleSheetPath(s_DefaultCommonDarkStyleSheetPath); - } - else - { - p.AddStyleSheetPath(s_DefaultCommonLightStyleSheetPath); - } - } - } - - internal static void ForceDarkStyleSheet(VisualElement ele) - { - if (!EditorGUIUtility.isProSkin) - { - var e = ele; - while (e != null) - { - if (e.HasStyleSheetPath(s_DefaultCommonLightStyleSheetPath)) - { - e.ReplaceStyleSheetPath(s_DefaultCommonLightStyleSheetPath, s_DefaultCommonDarkStyleSheetPath); - break; - } - e = e.parent; - } - } - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/UXMLEditorFactories.cs b/Editor/Mono/UIElements/Experimental/UXMLEditorFactories.cs deleted file mode 100644 index 84295d7209..0000000000 --- a/Editor/Mono/UIElements/Experimental/UXMLEditorFactories.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - internal class UXMLEditorFactories - { - private static bool s_Registered; - - internal static void RegisterAll() - { - if (s_Registered) - return; - - s_Registered = true; - - IUxmlFactory[] factories = - { - // Primitives - new TextElement.UxmlFactory(), - new FloatField.UxmlFactory(), - new DoubleField.UxmlFactory(), - new IntegerField.UxmlFactory(), - new LongField.UxmlFactory(), - new CurveField.UxmlFactory(), - new ObjectField.UxmlFactory(), - new ColorField.UxmlFactory(), - new EnumField.UxmlFactory(), - new MaskField.UxmlFactory(), - new LayerMaskField.UxmlFactory(), - new LayerField.UxmlFactory(), - new TagField.UxmlFactory(), - new GradientField.UxmlFactory(), - - // Compounds - new RectField.UxmlFactory(), - new Vector2Field.UxmlFactory(), - new Vector3Field.UxmlFactory(), - new Vector4Field.UxmlFactory(), - new BoundsField.UxmlFactory(), - new PropertyControl.UxmlFactory(), - new PropertyControl.UxmlFactory(), - new PropertyControl.UxmlFactory(), - new PropertyControl.UxmlFactory(), - new PropertyControl.UxmlFactory(), - - new RectIntField.UxmlFactory(), - new Vector2IntField.UxmlFactory(), - new Vector3IntField.UxmlFactory(), - new BoundsIntField.UxmlFactory(), - new VisualSplitter.UxmlFactory(), - // Toolbar - new Toolbar.UxmlFactory(), - new ToolbarButton.UxmlFactory(), - new ToolbarToggle.UxmlFactory(), - new ToolbarSpacer.UxmlFactory(), - new ToolbarFlexSpacer.UxmlFactory(), - new ToolbarMenu.UxmlFactory(), - new ToolbarPopup.UxmlFactory(), - new ToolbarSearchField.UxmlFactory(), - new ToolbarPopupSearchField.UxmlFactory(), - // Bound - //new PropertyField.UxmlFactory(), - //new InspectorElement.UxmlFactory(), - }; - - foreach (IUxmlFactory factory in factories) - { - VisualElementFactoryRegistry.RegisterFactory(factory); - } - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/UXMLSchemaGenerator.cs b/Editor/Mono/UIElements/Experimental/UXMLSchemaGenerator.cs deleted file mode 100644 index 5f3cebe70a..0000000000 --- a/Editor/Mono/UIElements/Experimental/UXMLSchemaGenerator.cs +++ /dev/null @@ -1,590 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Xml; -using System.Xml.Schema; -using UnityEditor.ProjectWindowCallback; -using UnityEngine; -using UnityEngine.Experimental.UIElements; - -namespace UnityEditor.Experimental.UIElements -{ - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public class UxmlNamespacePrefixAttribute : Attribute - { - public string ns { get; } - public string prefix { get; } - - public UxmlNamespacePrefixAttribute(string ns, string prefix) - { - this.ns = ns; - this.prefix = prefix; - } - } - - class UxmlSchemaGenerator - { - // Folder, relative to the project root. - internal const string k_SchemaFolder = "UIElementsSchema"; - - [MenuItem("Assets/Update UIElements Schema", false, 800)] - static void CreateTemplateMenuItem() - { - UpdateSchemaFiles(); - } - - public static void UpdateSchemaFiles() - { - Directory.CreateDirectory(k_SchemaFolder); - using (var it = GenerateSchemaFiles(k_SchemaFolder + "/").GetEnumerator()) - { - while (it.MoveNext()) - { - string fileName = it.Current; - if (it.MoveNext()) - { - string data = it.Current; - var action = ScriptableObject.CreateInstance(); - action.filecontent = data; - - ProjectWindowUtil.EndNameEditAction(action, 0, fileName, null); - Selection.activeObject = EditorUtility.InstanceIDToObject(0); - } - } - } - } - - internal static Dictionary GetNamespacePrefixDictionary() - { - return SchemaInfo.s_NamespacePrefix; - } - - sealed class UTF8StringWriter : StringWriter - { - public override Encoding Encoding - { - get { return Encoding.UTF8; } - } - } - - class SchemaInfo - { - public SchemaInfo(string uxmlNamespace) - { - schema = new XmlSchema(); - schema.ElementFormDefault = XmlSchemaForm.Qualified; - if (uxmlNamespace != String.Empty) - { - schema.TargetNamespace = uxmlNamespace; - } - - namepacePrefix = GetPrefixForNamespace(uxmlNamespace); - - importNamespaces = new HashSet(); - } - - public XmlSchema schema { get; set; } - public string namepacePrefix { get; set; } - public HashSet importNamespaces { get; set; } - - internal static Dictionary s_NamespacePrefix; - - static string GetPrefixForNamespace(string ns) - { - if (s_NamespacePrefix == null) - { - s_NamespacePrefix = new Dictionary(); - - s_NamespacePrefix.Add(String.Empty, "global"); - s_NamespacePrefix.Add(typeof(VisualElement).Namespace, "engine"); - s_NamespacePrefix.Add(typeof(UxmlSchemaGenerator).Namespace, "editor"); - - AppDomain currentDomain = AppDomain.CurrentDomain; - HashSet userAssemblies = new HashSet(ScriptingRuntime.GetAllUserAssemblies()); - foreach (Assembly assembly in currentDomain.GetAssemblies()) - { - if (!userAssemblies.Contains(assembly.GetName().Name + ".dll")) - continue; - - try - { - foreach (object nsPrefixAttributeObject in assembly.GetCustomAttributes(typeof(UxmlNamespacePrefixAttribute), false)) - { - UxmlNamespacePrefixAttribute nsPrefixAttribute = (UxmlNamespacePrefixAttribute)nsPrefixAttributeObject; - s_NamespacePrefix[nsPrefixAttribute.ns] = nsPrefixAttribute.prefix; - } - } - catch (TypeLoadException e) - { - Debug.LogWarningFormat("Error while loading types from assembly {0}: {1}", assembly.FullName, e); - } - } - } - - string prefix; - if (s_NamespacePrefix.TryGetValue(ns ?? String.Empty, out prefix)) - { - return prefix; - } - - s_NamespacePrefix[ns] = String.Empty; - return String.Empty; - } - } - - const string k_XmlSchemaNamespace = "http://www.w3.org/2001/XMLSchema"; - const string k_TypeSuffix = "Type"; - - class FactoryProcessingHelper - { - public class AttributeRecord - { - public XmlQualifiedName name { get; set; } - public UxmlAttributeDescription desc { get; set; } - } - - public Dictionary attributeTypeNames; - - HashSet m_KnownTypes; - - public FactoryProcessingHelper() - { - attributeTypeNames = new Dictionary(); - m_KnownTypes = new HashSet(); - } - - public void RegisterElementType(string elementName, string elementNameSpace) - { - m_KnownTypes.Add(new XmlQualifiedName(elementName, elementNameSpace)); - } - - public bool IsKnownElementType(string elementName, string elementNameSpace) - { - return m_KnownTypes.Contains(new XmlQualifiedName(elementName, elementNameSpace)); - } - } - - const string k_SchemaFileExtension = ".xsd"; - const string k_MainSchemaFileName = "UIElements" + k_SchemaFileExtension; - const string k_GlobalNamespaceSchemaFileName = "GlobalNamespace" + k_SchemaFileExtension; - - internal static IEnumerable GenerateSchemaFiles(string baseDir = null) - { - Dictionary schemas = new Dictionary(); - List deferredFactories = new List(); - FactoryProcessingHelper processingData = new FactoryProcessingHelper(); - - if (baseDir == null) - { - baseDir = Application.temporaryCachePath + "/"; - } - VisualElementFactoryRegistry.DiscoverFactories(); - - // Convert the factories into schemas info. - foreach (var factories in VisualElementFactoryRegistry.factories) - { - if (factories.Value.Count == 0) - continue; - - // Only process the first factory, as the other factories define the same element. - IUxmlFactory factory = factories.Value[0]; - if (!ProcessFactory(factory, schemas, processingData)) - { - // Could not process the factory now, because it depends on a yet unprocessed factory. - // Defer its processing. - deferredFactories.Add(factory); - } - } - - List deferredFactoriesCopy; - do - { - deferredFactoriesCopy = new List(deferredFactories); - foreach (var factory in deferredFactoriesCopy) - { - deferredFactories.Remove(factory); - if (!ProcessFactory(factory, schemas, processingData)) - { - // Could not process the factory now, because it depends on a yet unprocessed factory. - // Defer its processing again. - deferredFactories.Add(factory); - } - } - } - while (deferredFactoriesCopy.Count > deferredFactories.Count); - - if (deferredFactories.Count > 0) - { - Debug.Log("Some factories could not be processed because their base type is missing."); - } - - // Compile schemas. - XmlSchemaSet schemaSet = new XmlSchemaSet(); - XmlSchema masterSchema = new XmlSchema(); - masterSchema.ElementFormDefault = XmlSchemaForm.Qualified; - - XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable()); - nsmgr.AddNamespace("xs", k_XmlSchemaNamespace); - - File.Delete(baseDir + k_MainSchemaFileName); - - foreach (var schema in schemas) - { - if (schema.Value.schema.TargetNamespace != null) - { - nsmgr.AddNamespace(schema.Value.namepacePrefix, schema.Value.schema.TargetNamespace); - - // Import schema into the master schema. - XmlSchemaImport import = new XmlSchemaImport(); - import.Namespace = schema.Value.schema.TargetNamespace; - string schemaLocation = GetFileNameForNamespace(schema.Value.schema.TargetNamespace); - File.Delete(baseDir + schemaLocation); - import.SchemaLocation = schemaLocation; - masterSchema.Includes.Add(import); - } - else - { - XmlSchemaInclude include = new XmlSchemaInclude(); - string schemaLocation = GetFileNameForNamespace(null); - File.Delete(baseDir + schemaLocation); - include.SchemaLocation = schemaLocation; - masterSchema.Includes.Add(include); - } - - // Import referenced schemas into this XSD - foreach (string ns in schema.Value.importNamespaces) - { - if (ns != schema.Value.schema.TargetNamespace && ns != k_XmlSchemaNamespace) - { - XmlSchemaImport import = new XmlSchemaImport(); - import.Namespace = ns; - import.SchemaLocation = GetFileNameForNamespace(ns); - schema.Value.schema.Includes.Add(import); - } - } - - schemaSet.Add(schema.Value.schema); - } - schemaSet.Add(masterSchema); - schemaSet.Compile(); - - // Now generate the schema textual data. - foreach (XmlSchema compiledSchema in schemaSet.Schemas()) - { - string schemaName = compiledSchema.TargetNamespace; - - // Three possible cases: - // TargetNamespace == null and Items.Count == 0: the main schema, that include/import all other schema files - // TargetNamespace == null and Items.Count != 0: the schema file for the global namespace - // TargetNamespace != null: the schema file for TargetNamespace - if (schemaName == null && compiledSchema.Items.Count == 0) - { - schemaName = k_MainSchemaFileName; - } - else - { - schemaName = GetFileNameForNamespace(compiledSchema.TargetNamespace); - } - - yield return baseDir + schemaName; - - StringWriter strWriter = new UTF8StringWriter(); - compiledSchema.Write(strWriter, nsmgr); - yield return strWriter.ToString(); - } - } - - internal static string GetFileNameForNamespace(string ns) - { - return String.IsNullOrEmpty(ns) ? k_GlobalNamespaceSchemaFileName : ns + k_SchemaFileExtension; - } - - static bool ProcessFactory(IUxmlFactory factory, Dictionary schemas, FactoryProcessingHelper processingData) - { - if (factory.substituteForTypeName != null && factory.substituteForTypeName != String.Empty) - { - if (!processingData.IsKnownElementType(factory.substituteForTypeName, factory.substituteForTypeNamespace)) - { - // substituteForTypeName is not yet known. Defer processing to later. - return false; - } - } - - string uxmlNamespace = factory.uxmlNamespace; - SchemaInfo schemaInfo; - if (!schemas.TryGetValue(uxmlNamespace, out schemaInfo)) - { - schemaInfo = new SchemaInfo(uxmlNamespace); - schemas[uxmlNamespace] = schemaInfo; - } - - XmlSchemaType type = AddElementTypeToXmlSchema(factory, schemaInfo, processingData); - AddElementToXmlSchema(factory, schemaInfo, type); - - processingData.RegisterElementType(factory.uxmlName, factory.uxmlNamespace); - - return true; - } - - static XmlSchemaParticle MakeChoiceSequence(IEnumerable elements) - { - if (!elements.Any()) - { - return null; - } - else - { - XmlSchemaSequence sequence = new XmlSchemaSequence(); - sequence.MinOccurs = 0; - sequence.MaxOccursString = "unbounded"; - - if (elements.Count() == 1) - { - IEnumerator enumerator = elements.GetEnumerator(); - enumerator.MoveNext(); - XmlSchemaElement elementRef = new XmlSchemaElement(); - elementRef.RefName = new XmlQualifiedName(enumerator.Current.elementName, enumerator.Current.elementNamespace); - sequence.Items.Add(elementRef); - } - else - { - XmlSchemaChoice choice = new XmlSchemaChoice(); - - foreach (UxmlChildElementDescription element in elements) - { - XmlSchemaElement elementRef = new XmlSchemaElement(); - elementRef.RefName = new XmlQualifiedName(element.elementName, element.elementNamespace); - choice.Items.Add(elementRef); - } - sequence.Items.Add(choice); - } - - return sequence; - } - } - - static XmlSchemaType AddElementTypeToXmlSchema(IUxmlFactory factory, SchemaInfo schemaInfo, FactoryProcessingHelper processingData) - { - // We always have complex types with complex content. - XmlSchemaComplexType elementType = new XmlSchemaComplexType(); - elementType.Name = factory.uxmlName + k_TypeSuffix; - - XmlSchemaComplexContent content = new XmlSchemaComplexContent(); - elementType.ContentModel = content; - - // We only support restrictions of base types. - XmlSchemaComplexContentRestriction restriction = new XmlSchemaComplexContentRestriction(); - content.Content = restriction; - - if (factory.substituteForTypeName == String.Empty) - { - restriction.BaseTypeName = new XmlQualifiedName("anyType", k_XmlSchemaNamespace); - } - else - { - restriction.BaseTypeName = new XmlQualifiedName(factory.substituteForTypeName + k_TypeSuffix, factory.substituteForTypeNamespace); - schemaInfo.importNamespaces.Add(factory.substituteForTypeNamespace); - } - - if (factory.canHaveAnyAttribute) - { - XmlSchemaAnyAttribute anyAttribute = new XmlSchemaAnyAttribute(); - anyAttribute.ProcessContents = XmlSchemaContentProcessing.Lax; - restriction.AnyAttribute = anyAttribute; - } - - foreach (UxmlAttributeDescription attrDesc in factory.uxmlAttributesDescription) - { - XmlQualifiedName typeName = AddAttributeTypeToXmlSchema(schemaInfo, attrDesc, factory, processingData); - if (typeName != null) - { - AddAttributeToXmlSchema(restriction, attrDesc, typeName); - schemaInfo.importNamespaces.Add(attrDesc.typeNamespace); - } - } - - bool hasChildElements = false; - foreach (UxmlChildElementDescription childDesc in factory.uxmlChildElementsDescription) - { - hasChildElements = true; - schemaInfo.importNamespaces.Add(childDesc.elementNamespace); - } - - if (hasChildElements) - { - restriction.Particle = MakeChoiceSequence(factory.uxmlChildElementsDescription); - } - - schemaInfo.schema.Items.Add(elementType); - return elementType; - } - - static void AddElementToXmlSchema(IUxmlFactory factory, SchemaInfo schemaInfo, XmlSchemaType type) - { - XmlSchemaElement element = new XmlSchemaElement(); - element.Name = factory.uxmlName; - - if (type != null) - { - element.SchemaTypeName = new XmlQualifiedName(type.Name, factory.uxmlNamespace); - } - - if (factory.substituteForTypeName != String.Empty) - { - element.SubstitutionGroup = new XmlQualifiedName(factory.substituteForTypeName, factory.substituteForTypeNamespace); - } - - schemaInfo.schema.Items.Add(element); - } - - static XmlQualifiedName AddAttributeTypeToXmlSchema(SchemaInfo schemaInfo, UxmlAttributeDescription description, IUxmlFactory factory, FactoryProcessingHelper processingData) - { - if (description.name == null) - { - return null; - } - - string attrTypeName = factory.uxmlQualifiedName + "_" + description.name + "_" + k_TypeSuffix; - string attrTypeNameInBaseElement = factory.substituteForTypeQualifiedName + "_" + description.name + "_" + k_TypeSuffix; - - FactoryProcessingHelper.AttributeRecord attrRecord; - if (processingData.attributeTypeNames.TryGetValue(attrTypeNameInBaseElement, out attrRecord)) - { - // If restriction != baseElement.restriction, we need to declare a new type. - // Note: we do not support attributes having a less restrictive restriction than its base type. - if ((description.restriction == null && attrRecord.desc.restriction == null) || - (description.restriction != null && description.restriction.Equals(attrRecord.desc.restriction))) - { - // Register attrTypeName -> attrRecord for potential future derived elements. - processingData.attributeTypeNames.Add(attrTypeName, attrRecord); - return attrRecord.name; - } - } - - XmlQualifiedName xqn; - FactoryProcessingHelper.AttributeRecord attributeRecord; - - if (description.restriction == null) - { - // Type is a built-in type. - xqn = new XmlQualifiedName(description.type, description.typeNamespace); - attributeRecord = new FactoryProcessingHelper.AttributeRecord { name = xqn, desc = description }; - processingData.attributeTypeNames.Add(attrTypeName, attributeRecord); - return xqn; - } - - string attrTypeNameForSchema = factory.uxmlName + "_" + description.name + "_" + k_TypeSuffix; - xqn = new XmlQualifiedName(attrTypeNameForSchema, schemaInfo.schema.TargetNamespace); - - XmlSchemaSimpleType simpleType = new XmlSchemaSimpleType(); - simpleType.Name = attrTypeNameForSchema; - - UxmlEnumeration enumRestriction = description.restriction as UxmlEnumeration; - if (enumRestriction != null) - { - XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction(); - simpleType.Content = restriction; - restriction.BaseTypeName = new XmlQualifiedName(description.type, description.typeNamespace); - - foreach (var v in enumRestriction.values) - { - XmlSchemaEnumerationFacet enumValue = new XmlSchemaEnumerationFacet(); - enumValue.Value = v; - restriction.Facets.Add(enumValue); - } - } - else - { - UxmlValueMatches regexRestriction = description.restriction as UxmlValueMatches; - if (regexRestriction != null) - { - XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction(); - simpleType.Content = restriction; - restriction.BaseTypeName = new XmlQualifiedName(description.type, description.typeNamespace); - - XmlSchemaPatternFacet pattern = new XmlSchemaPatternFacet(); - pattern.Value = regexRestriction.regex; - restriction.Facets.Add(pattern); - } - else - { - UxmlValueBounds bounds = description.restriction as UxmlValueBounds; - if (bounds != null) - { - XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction(); - simpleType.Content = restriction; - restriction.BaseTypeName = new XmlQualifiedName(description.type, description.typeNamespace); - - XmlSchemaFacet facet; - if (bounds.excludeMin) - { - facet = new XmlSchemaMinExclusiveFacet(); - } - else - { - facet = new XmlSchemaMinInclusiveFacet(); - } - facet.Value = bounds.min; - restriction.Facets.Add(facet); - - if (bounds.excludeMax) - { - facet = new XmlSchemaMaxExclusiveFacet(); - } - else - { - facet = new XmlSchemaMaxInclusiveFacet(); - } - facet.Value = bounds.max; - restriction.Facets.Add(facet); - } - else - { - Debug.Log("Unsupported restriction type."); - } - } - } - - schemaInfo.schema.Items.Add(simpleType); - attributeRecord = new FactoryProcessingHelper.AttributeRecord { name = xqn, desc = description }; - processingData.attributeTypeNames.Add(attrTypeName, attributeRecord); - return xqn; - } - - static void AddAttributeToXmlSchema(XmlSchemaComplexContentRestriction restriction, UxmlAttributeDescription description, XmlQualifiedName typeName) - { - XmlSchemaAttribute attr = new XmlSchemaAttribute(); - attr.Name = description.name; - attr.SchemaTypeName = typeName; - - switch (description.use) - { - case UxmlAttributeDescription.Use.Optional: - attr.Use = XmlSchemaUse.Optional; - attr.DefaultValue = description.defaultValueAsString; - break; - - case UxmlAttributeDescription.Use.Prohibited: - attr.Use = XmlSchemaUse.Prohibited; - break; - - case UxmlAttributeDescription.Use.Required: - attr.Use = XmlSchemaUse.Required; - break; - - default: - attr.Use = XmlSchemaUse.None; - break; - } - - restriction.Attributes.Add(attr); - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/VisualSplitter.cs b/Editor/Mono/UIElements/Experimental/VisualSplitter.cs deleted file mode 100644 index 520693e9ff..0000000000 --- a/Editor/Mono/UIElements/Experimental/VisualSplitter.cs +++ /dev/null @@ -1,202 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; - -using UnityEngine; -using UnityEngine.Experimental.UIElements; -using UnityEngine.Experimental.UIElements.StyleEnums; - -namespace UnityEditor.Experimental.UIElements -{ - internal class VisualSplitter : VisualElement - { - const int kDefaultSplitSize = 10; - public int splitSize = kDefaultSplitSize; - - public new class UxmlFactory : UxmlFactory {} - - public new class UxmlTraits : VisualElement.UxmlTraits {} - - private class SplitManipulator : MouseManipulator - { - private int m_ActiveVisualElementIndex = -1; - private int m_NextVisualElementIndex = -1; - - private List m_AffectedElements; - - bool m_Active; - - public SplitManipulator() - { - activators.Add(new ManipulatorActivationFilter {button = MouseButton.LeftMouse}); - } - - protected override void RegisterCallbacksOnTarget() - { - target.RegisterCallback(OnMouseDown, TrickleDown.TrickleDown); - target.RegisterCallback(OnMouseMove, TrickleDown.TrickleDown); - target.RegisterCallback(OnMouseUp, TrickleDown.TrickleDown); - } - - protected override void UnregisterCallbacksFromTarget() - { - target.UnregisterCallback(OnMouseDown, TrickleDown.TrickleDown); - target.UnregisterCallback(OnMouseMove, TrickleDown.TrickleDown); - target.UnregisterCallback(OnMouseUp, TrickleDown.TrickleDown); - } - - protected void OnMouseDown(MouseDownEvent e) - { - if (CanStartManipulation(e)) - { - VisualSplitter visualSplitter = target as VisualSplitter; - FlexDirection flexDirection = visualSplitter.style.flexDirection; - - if (m_AffectedElements != null) - { - VisualElementListPool.Release(m_AffectedElements); - } - m_AffectedElements = visualSplitter.GetAffectedVisualElements(); - - for (int i = 0; i < m_AffectedElements.Count - 1; ++i) - { - VisualElement visualElement = m_AffectedElements[i]; - - Rect splitterRect = visualSplitter.GetSplitterRect(visualElement); - - if (splitterRect.Contains(e.localMousePosition)) - { - bool isReverse = flexDirection == FlexDirection.RowReverse || flexDirection == FlexDirection.ColumnReverse; - - if (isReverse) - { - m_ActiveVisualElementIndex = i + 1; - m_NextVisualElementIndex = i; - } - else - { - m_ActiveVisualElementIndex = i; - m_NextVisualElementIndex = i + 1; - } - - m_Active = true; - target.CaptureMouse(); - e.StopPropagation(); - } - } - } - } - - protected void OnMouseMove(MouseMoveEvent e) - { - if (m_Active) - { - // These calculations should only work if flex-basis is auto. - // However, Yoga implementation of flex-basis 0 is broken and behaves much like - // flex-basis auto, so it currently works with flex-basis 0 too. - - VisualSplitter visualSplitter = target as VisualSplitter; - VisualElement visualElement = m_AffectedElements[m_ActiveVisualElementIndex]; - VisualElement nextVisualElement = m_AffectedElements[m_NextVisualElementIndex]; - - FlexDirection flexDirection = visualSplitter.style.flexDirection; - bool isVertical = flexDirection == FlexDirection.Column || flexDirection == FlexDirection.ColumnReverse; - - float relativeMousePosition; - if (isVertical) - { - relativeMousePosition = (e.localMousePosition.y - visualElement.layout.yMin - visualElement.style.minHeight) / - (visualElement.layout.height + nextVisualElement.layout.height - - visualElement.style.minHeight - nextVisualElement.style.minHeight); - } - else - { - relativeMousePosition = (e.localMousePosition.x - visualElement.layout.xMin - visualElement.style.minWidth) / - (visualElement.layout.width + nextVisualElement.layout.width - - visualElement.style.minWidth - nextVisualElement.style.minWidth); - } - - relativeMousePosition = Math.Max(0.0f, Math.Min(1.0f, relativeMousePosition)); - - float totalFlex = visualElement.style.flexGrow + nextVisualElement.style.flexGrow; - visualElement.style.flexGrow = relativeMousePosition * totalFlex; - nextVisualElement.style.flexGrow = (1.0f - relativeMousePosition) * totalFlex; - - e.StopPropagation(); - } - } - - protected void OnMouseUp(MouseUpEvent e) - { - if (m_Active && CanStopManipulation(e)) - { - m_Active = false; - target.ReleaseMouse(); - e.StopPropagation(); - - m_ActiveVisualElementIndex = -1; - m_NextVisualElementIndex = -1; - } - } - } - - public VisualSplitter() - { - this.AddManipulator(new SplitManipulator()); - } - - public List GetAffectedVisualElements() - { - List elements = VisualElementListPool.Get(); - for (int i = 0; i < shadow.childCount; ++i) - { - VisualElement element = shadow[i]; - if (element.style.positionType == PositionType.Relative) - elements.Add(element); - } - - return elements; - } - - protected override void DoRepaint(IStylePainter painter) - { - for (int i = 0; i < shadow.childCount - 1; ++i) - { - VisualElement visualElement = shadow[i]; - bool isVertical = style.flexDirection == FlexDirection.Column || style.flexDirection == FlexDirection.ColumnReverse; - - EditorGUIUtility.AddCursorRect(GetSplitterRect(visualElement), isVertical ? MouseCursor.ResizeVertical : MouseCursor.SplitResizeLeftRight); - } - } - - public Rect GetSplitterRect(VisualElement visualElement) - { - Rect rect = visualElement.layout; - if (style.flexDirection == FlexDirection.Row) - { - rect.xMin = visualElement.layout.xMax - splitSize * 0.5f; - rect.xMax = visualElement.layout.xMax + splitSize * 0.5f; - } - else if (style.flexDirection == FlexDirection.RowReverse) - { - rect.xMin = visualElement.layout.xMin - splitSize * 0.5f; - rect.xMax = visualElement.layout.xMin + splitSize * 0.5f; - } - else if (style.flexDirection == FlexDirection.Column) - { - rect.yMin = visualElement.layout.yMax - splitSize * 0.5f; - rect.yMax = visualElement.layout.yMax + splitSize * 0.5f; - } - else if (style.flexDirection == FlexDirection.ColumnReverse) - { - rect.yMin = visualElement.layout.yMin - splitSize * 0.5f; - rect.yMax = visualElement.layout.yMin + splitSize * 0.5f; - } - - return rect; - } - } -} diff --git a/Editor/Mono/UIElements/Experimental/VisualTreeAssetEditor.cs b/Editor/Mono/UIElements/Experimental/VisualTreeAssetEditor.cs deleted file mode 100644 index dd9f1f6885..0000000000 --- a/Editor/Mono/UIElements/Experimental/VisualTreeAssetEditor.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEditor; -using UnityEngine; -using UnityEngine.Experimental.UIElements; -using Object = UnityEngine.Object; - -namespace UnityEditor.Experimental.UIElements -{ - [CustomEditor(typeof(VisualTreeAsset))] - internal class VisualTreeAssetEditor : ScriptableObjectAssetEditor - { - private Panel m_Panel; - private VisualElement m_Tree; - private VisualTreeAsset m_LastTree; - private Texture2D m_FileTypeIcon; - - protected void OnEnable() - { - m_FileTypeIcon = EditorGUIUtility.FindTexture(typeof(VisualTreeAsset)); - } - - protected void OnDestroy() - { - m_Panel = null; - if (m_LastTree != null) - { - UIElementsUtility.RemoveCachedPanel(m_LastTree.GetInstanceID()); - } - } - - public override bool HasPreviewGUI() - { - return true; - } - - private void RenderIcon(Rect iconRect) - { - Debug.Assert(m_FileTypeIcon != null); - GUI.DrawTexture(iconRect, m_FileTypeIcon, ScaleMode.ScaleToFit); - } - - public void Render(VisualTreeAsset vta, Rect r, GUIStyle background) - { - if (Event.current.type != EventType.Repaint || r.width < 100 && r.height < 100) - return; - - bool dirty = false; - if (vta != m_LastTree || !m_LastTree) - { - m_LastTree = vta; - m_Tree = vta.CloneTree(null); - m_Tree.StretchToParentSize(); - dirty = true; - } - - if (m_Panel == null) - { - m_Panel = UIElementsUtility.FindOrCreatePanel(m_LastTree, ContextType.Editor, new DataWatchService()); - if (m_Panel.visualTree.styleSheets == null) - { - UIElementsEditorUtility.AddDefaultEditorStyleSheets(m_Panel.visualTree); - m_Panel.visualTree.LoadStyleSheetsFromPaths(); - } - m_Panel.allowPixelCaching = false; - dirty = true; - } - - if (dirty) - { - m_Panel.visualTree.Clear(); - m_Panel.visualTree.Add(m_Tree); - } - - EditorGUI.DrawRect(r, EditorGUIUtility.kViewBackgroundColor); - - m_Panel.visualTree.layout = GUIClip.UnclipToWindow(r); - m_Panel.visualTree.IncrementVersion(VersionChangeType.Repaint); - - var oldState = SavedGUIState.Create(); - int clips = GUIClip.Internal_GetCount(); - while (clips > 0) - { - GUIClip.Pop(); - clips--; - } - - m_Panel.Repaint(Event.current); - - oldState.ApplyAndForget(); - } - - public override void OnPreviewGUI(Rect r, GUIStyle background) - { - const int k_IconSize = 64; - - base.OnPreviewGUI(r, background); - if (r.width > k_IconSize || r.height > k_IconSize) - Render(target as VisualTreeAsset, r, background); - else - RenderIcon(r); - } - } -} diff --git a/Editor/Mono/UIElements/Renderer/EditorAtlasMonitor.cs b/Editor/Mono/UIElements/Renderer/EditorAtlasMonitor.cs index 479f7a21b9..5a10d537b1 100644 --- a/Editor/Mono/UIElements/Renderer/EditorAtlasMonitor.cs +++ b/Editor/Mono/UIElements/Renderer/EditorAtlasMonitor.cs @@ -15,6 +15,11 @@ internal class EditorAtlasMonitor : IAtlasMonitor static EditorAtlasMonitor() { s_Monitors = new Dictionary(); + var createdAtlasManagerInstances = UIRAtlasManager.Instances(); + for (int i = 0; i != createdAtlasManagerInstances.Count; ++i) + { + OnAtlasManagerCreated(createdAtlasManagerInstances[i]); + } UIRAtlasManager.atlasManagerCreated += OnAtlasManagerCreated; UIRAtlasManager.atlasManagerDisposed += OnAtlasManagerDisposed; } diff --git a/Editor/Mono/UIElements/Tooltip.cs b/Editor/Mono/UIElements/Tooltip.cs index b8830517da..f9f7a034c9 100644 --- a/Editor/Mono/UIElements/Tooltip.cs +++ b/Editor/Mono/UIElements/Tooltip.cs @@ -15,7 +15,7 @@ internal static void SetTooltip(float mouseX, float mouseY) { //mouseX,mouseY are screen relative. GUIView view = GUIView.mouseOverView; - if (view != null && view.uieMode != GUIView.UIElementsMode.Experimental && view.visualTree != null && view.visualTree.panel != null) + if (view != null && view.visualTree != null && view.visualTree.panel != null) { var panel = view.visualTree.panel; @@ -40,9 +40,6 @@ internal static void SetTooltip(float mouseX, float mouseY) } } } - - //temporary for backwards compatibility - UnityEditor.Experimental.UIElements.Tooltip.SetTooltip(mouseX, mouseY); } } } diff --git a/Editor/Mono/UIElements/UIElementsEditorWindowCreator/UxmlTemplateCreator.cs b/Editor/Mono/UIElements/UIElementsEditorWindowCreator/UxmlTemplateCreator.cs index 5e6206a09d..b3f0df9ae8 100644 --- a/Editor/Mono/UIElements/UIElementsEditorWindowCreator/UxmlTemplateCreator.cs +++ b/Editor/Mono/UIElements/UIElementsEditorWindowCreator/UxmlTemplateCreator.cs @@ -61,7 +61,7 @@ public static string CreateUXMLTemplate(string folder) {3}"" > -", UnityEditor.Experimental.UIElements.UXMLImporterImpl.k_RootNode, xmlnsList, schemaDirectory, schemaLocationList); +", UnityEditor.UIElements.UXMLImporterImpl.k_RootNode, xmlnsList, schemaDirectory, schemaLocationList); return uxmlTemplate; } diff --git a/Editor/Mono/UIElements/UIElementsViewImporter.cs b/Editor/Mono/UIElements/UIElementsViewImporter.cs index 99855bcfd3..3f97a49839 100644 --- a/Editor/Mono/UIElements/UIElementsViewImporter.cs +++ b/Editor/Mono/UIElements/UIElementsViewImporter.cs @@ -14,12 +14,11 @@ using UnityEditor.StyleSheets; using UnityEngine; +using UnityEngine.UIElements; + using StyleSheet = UnityEngine.UIElements.StyleSheet; -using VisualTreeAsset = UnityEngine.Experimental.UIElements.VisualTreeAsset; -using TemplateAsset = UnityEngine.Experimental.UIElements.TemplateAsset; -using VisualElementAsset = UnityEngine.UIElements.VisualElementAsset; -namespace UnityEditor.Experimental.UIElements +namespace UnityEditor.UIElements { // Make sure UXML is imported after assets than can be addressed in USS [ScriptedImporter(version: 6, ext: "uxml", importQueueOffset: 1000)] @@ -51,7 +50,7 @@ public override void OnImportAsset(AssetImportContext args) } } - class UXMLImporterImpl : StyleValueImporter + internal class UXMLImporterImpl : StyleValueImporter { internal struct Error { diff --git a/Editor/Mono/UIElements/UXMLEditorFactories.cs b/Editor/Mono/UIElements/UXMLEditorFactories.cs index 1549f914c1..8db3afffdb 100644 --- a/Editor/Mono/UIElements/UXMLEditorFactories.cs +++ b/Editor/Mono/UIElements/UXMLEditorFactories.cs @@ -2,7 +2,7 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using UnityEditor.Experimental.UIElements; +using UnityEditor.UIElements; using UnityEngine.UIElements; namespace UnityEditor.UIElements diff --git a/Editor/Mono/UIElements/VisualTreeAssetEditor.cs b/Editor/Mono/UIElements/VisualTreeAssetEditor.cs index a64497cca4..687ea4e4e9 100644 --- a/Editor/Mono/UIElements/VisualTreeAssetEditor.cs +++ b/Editor/Mono/UIElements/VisualTreeAssetEditor.cs @@ -2,13 +2,8 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using System; -using UnityEditor; using UnityEngine; using UnityEngine.UIElements; -using Object = UnityEngine.Object; - -using VisualTreeAsset = UnityEngine.Experimental.UIElements.VisualTreeAsset; namespace UnityEditor.UIElements { @@ -17,7 +12,7 @@ internal class VisualTreeAssetEditor : ScriptableObjectAssetEditor { private Panel m_Panel; private VisualElement m_Tree; - private VisualTreeAsset m_LastTree; + private int m_LastTreeHash = -1; private Texture2D m_FileTypeIcon; protected void OnEnable() @@ -34,14 +29,6 @@ protected void OnDisable() } } - protected void OnDestroy() - { - if (m_LastTree != null) - { - UIElementsUtility.RemoveCachedPanel(m_LastTree.GetInstanceID()); - } - } - public override bool HasPreviewGUI() { return true; @@ -59,9 +46,10 @@ public void Render(VisualTreeAsset vta, Rect r, GUIStyle background) return; bool dirty = false; - if (vta != m_LastTree || !m_LastTree) + + if (m_LastTreeHash != vta.contentHash) { - m_LastTree = vta; + m_LastTreeHash = vta.contentHash; m_Tree = (vta as UnityEngine.UIElements.VisualTreeAsset).CloneTree(); m_Tree.StretchToParentSize(); dirty = true; @@ -69,7 +57,7 @@ public void Render(VisualTreeAsset vta, Rect r, GUIStyle background) if (m_Panel == null) { - m_Panel = UIElementsUtility.FindOrCreatePanel(m_LastTree, ContextType.Editor); + m_Panel = UIElementsUtility.FindOrCreatePanel(vta, ContextType.Editor); var visualTree = m_Panel.visualTree; visualTree.pseudoStates |= PseudoStates.Root; UIElementsEditorUtility.AddDefaultEditorStyleSheets(visualTree); @@ -98,11 +86,12 @@ public void Render(VisualTreeAsset vta, Rect r, GUIStyle background) } // Establish preview area viewport - { - var pixelsPerPoint = GUIUtility.pixelsPerPoint; - Rect viewportRect = new Rect(layoutRect.x * pixelsPerPoint, (GUIClip.visibleRect.height - layoutRect.yMax) * pixelsPerPoint, layoutRect.width * pixelsPerPoint, layoutRect.height * pixelsPerPoint); - GL.Viewport(viewportRect); - } + var pixelsPerPoint = GUIUtility.pixelsPerPoint; + var viewportRect = new Rect( + layoutRect.x * pixelsPerPoint, (GUIClip.visibleRect.height - layoutRect.yMax) * pixelsPerPoint, + layoutRect.width * pixelsPerPoint, layoutRect.height * pixelsPerPoint); + GL.Viewport(viewportRect); + m_Panel.Repaint(Event.current); oldState.ApplyAndForget(); diff --git a/Editor/Mono/Unsupported.bindings.cs b/Editor/Mono/Unsupported.bindings.cs index 6bd0fdd634..b637151588 100644 --- a/Editor/Mono/Unsupported.bindings.cs +++ b/Editor/Mono/Unsupported.bindings.cs @@ -78,15 +78,15 @@ public static bool IsDeveloperBuild() [FreeFunction("GetScreenManager().SetAllowCursorLock")] internal static extern void SetAllowCursorLock(bool allow, DisallowCursorLockReasons reasons); - public static bool SetOverrideRenderSettings(Scene scene) + public static bool SetOverrideLightingSettings(Scene scene) { - return SetOverrideRenderSettingsInternal(scene.handle); + return SetOverrideLightingSettingsInternal(scene.handle); } - internal static extern bool SetOverrideRenderSettingsInternal(int sceneHandle); + internal static extern bool SetOverrideLightingSettingsInternal(int sceneHandle); - public static extern void RestoreOverrideRenderSettings(); + public static extern void RestoreOverrideLightingSettings(); [FreeFunction("GetRenderSettings().SetUseFogNoDirty")] public static extern void SetRenderSettingsUseFogNoDirty(bool fog); diff --git a/Editor/Mono/Utils/Paths.cs b/Editor/Mono/Utils/Paths.cs index e3dc05fede..a1b6d964cc 100644 --- a/Editor/Mono/Utils/Paths.cs +++ b/Editor/Mono/Utils/Paths.cs @@ -3,9 +3,11 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; -using System.IO; using System.Collections.Generic; +using System.Globalization; +using System.IO; using System.Linq; +using System.Text; namespace UnityEditor.Utils { @@ -322,5 +324,20 @@ static string ToLiteral(string input) } return literal.ToString(); } + + public static string MakeValidFileName(string unsafeFileName) + { + var normalizedFileName = unsafeFileName.Trim().Normalize(NormalizationForm.FormD); + var stringBuilder = new StringBuilder(); + foreach (var c in normalizedFileName) + { + if (invalidFilenameChars.Contains(c)) + continue; + var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c); + if (unicodeCategory != UnicodeCategory.NonSpacingMark) + stringBuilder.Append(c); + } + return stringBuilder.ToString().Normalize(NormalizationForm.FormC); + } } } diff --git a/Editor/Mono/VersionControl/Common/VCProvider.cs b/Editor/Mono/VersionControl/Common/VCProvider.cs index 550d96ef0c..76266a378d 100644 --- a/Editor/Mono/VersionControl/Common/VCProvider.cs +++ b/Editor/Mono/VersionControl/Common/VCProvider.cs @@ -249,7 +249,7 @@ static public Task Checkout(UnityEngine.Object asset, CheckoutMode mode, ChangeS return CheckCallbackAndCheckout(assetList, mode, changeset); } - //*Undocumented + //*Undocumented : intention is to make this public static internal bool PromptAndCheckoutIfNeeded(string[] assets, string promptIfCheckoutIsNeeded, ChangeSet changeset = null) { var assetList = new AssetList(); diff --git a/Editor/Mono/VersionControl/UI/VCListControl.cs b/Editor/Mono/VersionControl/UI/VCListControl.cs index b52224b31a..3f0ff06100 100644 --- a/Editor/Mono/VersionControl/UI/VCListControl.cs +++ b/Editor/Mono/VersionControl/UI/VCListControl.cs @@ -788,7 +788,8 @@ void DrawItem(ListItem item, Rect area, float x, float y, bool focus, bool selec EditorGUI.Foldout(new Rect(x, y, 16, c_lineHeight), item.Expanded, GUIContent.none); } - Texture icon = item.Icon; + Texture icon = GetIconTexture(item); + Color tmpColor = GUI.color; Color tmpContentColor = GUI.contentColor; @@ -1355,5 +1356,17 @@ private bool HasHiddenMetaFile(ListItem item) ListItem twinMeta = GetTwinMeta(item); return twinMeta != null && twinMeta.Hidden; } + + private Texture GetIconTexture(ListItem item) + { + if (item.Asset != null && item.Asset.isInCurrentProject) + { + return item.Icon; + } + else + { + return defaultIcon; + } + } } } diff --git a/Editor/Mono/VersionControl/UI/VCWindowChange.cs b/Editor/Mono/VersionControl/UI/VCWindowChange.cs index c195cda427..b30f67256b 100644 --- a/Editor/Mono/VersionControl/UI/VCWindowChange.cs +++ b/Editor/Mono/VersionControl/UI/VCWindowChange.cs @@ -254,7 +254,10 @@ void OnSubmitGUI() GUILayout.BeginArea(r1); GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true)); GUILayout.EndArea(); - submitList.OnGUI(new Rect(r1.x + 2, r1.y + 2, r1.width - 4, r1.height - 4), true); + bool repaint = submitList.OnGUI(new Rect(r1.x + 2, r1.y + 2, r1.width - 4, r1.height - 4), true); + + if (repaint) + Repaint(); GUILayout.FlexibleSpace(); GUILayout.BeginHorizontal(); diff --git a/Editor/Mono/VersionControl/VCProvider.bindings.cs b/Editor/Mono/VersionControl/VCProvider.bindings.cs index 86aa9dbdd6..636eef5bd5 100644 --- a/Editor/Mono/VersionControl/VCProvider.bindings.cs +++ b/Editor/Mono/VersionControl/VCProvider.bindings.cs @@ -149,6 +149,9 @@ internal static extern CustomCommand[] customCommands [FreeFunction("VersionControlBindings::VCProvider::Internal_PromptAndCheckoutIfNeeded")] private static extern bool Internal_PromptAndCheckoutIfNeeded(string[] assets, string promptIfCheckoutIsNeeded, ChangeSet changeset); + [FreeFunction("VersionControlBindings::VCProvider::MakeEditable")] + static internal extern bool MakeEditable(string[] assets, [Out] string[] editableAssets); + [NativeThrows] [FreeFunction("VersionControlBindings::VCProvider::Internal_Delete")] private static extern Task Internal_Delete(Asset[] assets); diff --git a/Editor/Mono/VisualStudioIntegration/SolutionSynchronizationSettings.cs b/Editor/Mono/VisualStudioIntegration/SolutionSynchronizationSettings.cs index 0b7e6ded10..9277eca08a 100644 --- a/Editor/Mono/VisualStudioIntegration/SolutionSynchronizationSettings.cs +++ b/Editor/Mono/VisualStudioIntegration/SolutionSynchronizationSettings.cs @@ -55,7 +55,6 @@ public virtual string SolutionTemplate @" GlobalSection(SolutionProperties) = preSolution", @" HideSolutionNode = FALSE", @" EndGlobalSection", - @"{4}", @"EndGlobal", @"" }).Replace(" ", "\t"); @@ -196,7 +195,6 @@ public virtual string GetProjectFooterTemplate(ScriptingLanguage language) @" ", @" ", @" -->", - @" {0}", @"", @"" }); diff --git a/Editor/Mono/VisualStudioIntegration/SolutionSynchronizer.cs b/Editor/Mono/VisualStudioIntegration/SolutionSynchronizer.cs index 4fd1e0527d..81407c5212 100644 --- a/Editor/Mono/VisualStudioIntegration/SolutionSynchronizer.cs +++ b/Editor/Mono/VisualStudioIntegration/SolutionSynchronizer.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Security; using System.Security.Cryptography; -using System.Xml; using System.Text; using System.Text.RegularExpressions; @@ -33,6 +32,33 @@ enum ScriptingLanguage UnityScript, } + interface IAssemblyNameProvider + { + string GetAssemblyNameFromScriptPath(string path); + IEnumerable GetAllScriptAssemblies(Func shouldFileBePartOfSolution, string projectDirectory); + IEnumerable GetAllAssetPaths(); + } + + class AssemblyNameProvider : IAssemblyNameProvider + { + public string GetAssemblyNameFromScriptPath(string path) + { + return CompilationPipeline.GetAssemblyNameFromScriptPath(path); + } + + public IEnumerable GetAllScriptAssemblies(Func shouldFileBePartOfSolution, string projectDirectory) + { + return EditorCompilationInterface.Instance.GetAllScriptAssemblies(EditorScriptCompilationOptions.BuildingForEditor | EditorCompilationInterface.GetAdditionalEditorScriptCompilationOptions()) + .Where(i => 0 < i.Files.Length && i.Files.Any(shouldFileBePartOfSolution)) + .Select(x => x.ToMonoIsland(EditorScriptCompilationOptions.BuildingForEditor, string.Empty, projectDirectory)).ToList(); + } + + public IEnumerable GetAllAssetPaths() + { + return AssetDatabase.GetAllAssetPaths(); + } + } + class SolutionSynchronizer { enum Mode @@ -60,6 +86,7 @@ enum Mode {"hlsl", ScriptingLanguage.None}, {"glslinc", ScriptingLanguage.None}, {"template", ScriptingLanguage.None}, + {"raytrace", ScriptingLanguage.None}, }; private static readonly string[] reimportSyncExtensions = new[] { ".dll", ".asmdef" }; @@ -77,26 +104,23 @@ enum Mode { ScriptingLanguage.None, ".csproj" }, }; - static readonly Regex _MonoDevelopPropertyHeader = new Regex(@"^\s*GlobalSection\(MonoDevelopProperties.*\)"); public static readonly string MSBuildNamespaceUri = "http://schemas.microsoft.com/developer/msbuild/2003"; private readonly string _projectDirectory; private readonly ISolutionSynchronizationSettings _settings; private readonly string _projectName; + readonly IAssemblyNameProvider m_assemblyNameProvider; - - private static readonly string DefaultMonoDevelopSolutionProperties = string.Join("\r\n", new[] - { - " GlobalSection(MonoDevelopProperties) = preSolution", - " StartupItem = Assembly-CSharp.csproj", - " EndGlobalSection", - }).Replace(" ", "\t"); - - public SolutionSynchronizer(string projectDirectory, ISolutionSynchronizationSettings settings) + public SolutionSynchronizer(string projectDirectory, ISolutionSynchronizationSettings settings, IAssemblyNameProvider assemblyNameProvider) { _projectDirectory = projectDirectory.ConvertSeparatorsToUnity(); _settings = settings; _projectName = Path.GetFileName(_projectDirectory); + m_assemblyNameProvider = assemblyNameProvider; + } + + public SolutionSynchronizer(string projectDirectory, ISolutionSynchronizationSettings settings) : this(projectDirectory, settings, new AssemblyNameProvider()) + { } public SolutionSynchronizer(string projectDirectory) : this(projectDirectory, DefaultSynchronizationSettings) @@ -205,11 +229,15 @@ private bool ShouldSyncOnReimportedAsset(string asset) public void Sync() { + Profiler.BeginSample("SolutionSynchronizerSync"); // Do not sync solution until all Unity extensions are registered and initialized. // Otherwise Unity might emit errors when VSTU tries to generate the solution and // get all managed extensions, which not yet initialized. if (!InternalEditorUtility.IsUnityExtensionsInitialized()) + { + Profiler.EndSample(); return; + } SetupProjectSupportedExtensions(); @@ -222,6 +250,7 @@ public void Sync() } AssetPostprocessingInternal.CallOnGeneratedCSProjectFiles(); + Profiler.EndSample(); } internal void GenerateAndWriteSolutionAndProjects(ScriptEditorUtility.ScriptEditor scriptEditor) @@ -231,9 +260,7 @@ internal void GenerateAndWriteSolutionAndProjects(ScriptEditorUtility.ScriptEdit Profiler.BeginSample("SolutionSynchronizer.GetIslands"); // Only synchronize islands that have associated source files and ones that we actually want in the project. // This also filters out DLLs coming from .asmdef files in packages. - IEnumerable islands = EditorCompilationInterface.Instance.GetAllScriptAssemblies(EditorScriptCompilationOptions.BuildingForEditor | EditorCompilationInterface.GetAdditionalEditorScriptCompilationOptions()) - .Where(i => 0 < i.Files.Length && i.Files.Any(ShouldFileBePartOfSolution)) - .Select(x => x.ToMonoIsland(EditorScriptCompilationOptions.BuildingForEditor, string.Empty, _projectDirectory)).ToList(); + IEnumerable islands = m_assemblyNameProvider.GetAllScriptAssemblies(ShouldFileBePartOfSolution, _projectDirectory); Profiler.EndSample(); @@ -295,7 +322,7 @@ Dictionary GenerateAllAssetProjectParts() { Dictionary stringBuilders = new Dictionary(); - foreach (string asset in AssetDatabase.GetAllAssetPaths()) + foreach (string asset in m_assemblyNameProvider.GetAllAssetPaths()) { // Exclude files coming from packages except if they are internalized. if (IsNonInternalizedPackagePath(asset)) @@ -306,11 +333,16 @@ Dictionary GenerateAllAssetProjectParts() if (IsSupportedExtension(extension) && ScriptingLanguage.None == ScriptingLanguageFor(extension)) { // Find assembly the asset belongs to by adding script extension and using compilation pipeline. - var assemblyName = CompilationPipeline.GetAssemblyNameFromScriptPath(asset + ".cs"); - assemblyName = assemblyName ?? CompilationPipeline.GetAssemblyNameFromScriptPath(asset + ".js"); - assemblyName = assemblyName ?? CompilationPipeline.GetAssemblyNameFromScriptPath(asset + ".boo"); + var assemblyName = m_assemblyNameProvider.GetAssemblyNameFromScriptPath(asset + ".cs"); + assemblyName = assemblyName ?? m_assemblyNameProvider.GetAssemblyNameFromScriptPath(asset + ".js"); + assemblyName = assemblyName ?? m_assemblyNameProvider.GetAssemblyNameFromScriptPath(asset + ".boo"); - assemblyName = Path.GetFileNameWithoutExtension(assemblyName); + if (string.IsNullOrEmpty(assemblyName)) + { + continue; + } + + assemblyName = Utility.FileNameWithoutExtension(assemblyName); StringBuilder projectBuilder = null; @@ -320,7 +352,7 @@ Dictionary GenerateAllAssetProjectParts() stringBuilders[assemblyName] = projectBuilder; } - projectBuilder.AppendFormat(" {1}", EscapedRelativePathFor(asset), WindowsNewline); + projectBuilder.Append(" ").Append(WindowsNewline); } } @@ -474,7 +506,7 @@ string ProjectText(MonoIsland island, var references = new List(); var projectReferences = new List(); Match match; - bool isBuildingEditorProject = island._output.EndsWith("-Editor.dll"); + bool isBuildingEditorProject = island._isEditorAssembly; foreach (string file in island._files) { @@ -486,7 +518,7 @@ string ProjectText(MonoIsland island, if (".dll" != extension) { var tagName = "Compile"; - projectBuilder.AppendFormat(" <{0} Include=\"{1}\" />{2}", tagName, fullFile, WindowsNewline); + projectBuilder.Append(" <").Append(tagName).Append(" Include=\"").Append(fullFile).Append("\" />").Append(WindowsNewline); } else { @@ -495,7 +527,7 @@ string ProjectText(MonoIsland island, } string additionalAssetsForProject; - var assemblyName = Path.GetFileNameWithoutExtension(island._output); + var assemblyName = Utility.FileNameWithoutExtension(island._output); // Append additional non-script files that should be included in project generation. if (allAssetsProjectParts.TryGetValue(assemblyName, out additionalAssetsForProject)) @@ -506,7 +538,10 @@ string ProjectText(MonoIsland island, foreach (string reference in islandRefs) { - if (reference.EndsWith("/UnityEditor.dll") || reference.EndsWith("/UnityEngine.dll") || reference.EndsWith("\\UnityEditor.dll") || reference.EndsWith("\\UnityEngine.dll")) + if (reference.EndsWith("/UnityEditor.dll", StringComparison.Ordinal) + || reference.EndsWith("/UnityEngine.dll", StringComparison.Ordinal) + || reference.EndsWith("\\UnityEditor.dll", StringComparison.Ordinal) + || reference.EndsWith("\\UnityEngine.dll", StringComparison.Ordinal)) continue; match = scriptReferenceExpression.Match(reference); @@ -562,10 +597,9 @@ string ProjectText(MonoIsland island, if (targetAssembly != null) targetLanguage = (ScriptingLanguage)Enum.Parse(typeof(ScriptingLanguage), targetAssembly.Language.GetLanguageName(), true); referencedProject = reference.Groups["project"].Value; - projectBuilder.AppendFormat(" {2}", referencedProject, - GetProjectExtension(targetLanguage), WindowsNewline); - projectBuilder.AppendFormat(" {{{0}}}", ProjectGuid(Path.Combine("Temp", reference.Groups["project"].Value + ".dll")), WindowsNewline); - projectBuilder.AppendFormat(" {0}", referencedProject, WindowsNewline); + projectBuilder.Append(" ").Append(WindowsNewline); + projectBuilder.Append(" {").Append(ProjectGuid(Path.Combine("Temp", reference.Groups["project"].Value + ".dll"))).Append("}").Append(WindowsNewline); + projectBuilder.Append(" ").Append(referencedProject).Append("").Append(WindowsNewline); projectBuilder.AppendLine(" "); } } @@ -580,15 +614,15 @@ static void AppendReference(string fullReference, StringBuilder projectBuilder) var escapedFullPath = SecurityElement.Escape(fullReference); escapedFullPath = escapedFullPath.Replace("\\", "/"); escapedFullPath = escapedFullPath.Replace("\\\\", "/"); - projectBuilder.AppendFormat(" {1}", Path.GetFileNameWithoutExtension(escapedFullPath), WindowsNewline); - projectBuilder.AppendFormat(" {0}{1}", escapedFullPath, WindowsNewline); - projectBuilder.AppendFormat(" {0}", WindowsNewline); + projectBuilder.Append(" ").Append(WindowsNewline); + projectBuilder.Append(" ").Append(escapedFullPath).Append("").Append(WindowsNewline); + projectBuilder.Append(" ").Append(WindowsNewline); } public string ProjectFile(MonoIsland island) { ScriptingLanguage language = ScriptingLanguageFor(island); - return Path.Combine(_projectDirectory, string.Format("{0}{1}", Path.GetFileNameWithoutExtension(island._output), ProjectExtensions[language])); + return Path.Combine(_projectDirectory, string.Format("{0}{1}", Utility.FileNameWithoutExtension(island._output), ProjectExtensions[language])); } internal string SolutionFile() @@ -610,7 +644,7 @@ private string ProjectHeader(MonoIsland island, if (PlayerSettingsEditor.IsLatestApiCompatibility(island._api_compatibility_level)) { - targetframeworkversion = "v4.7.2"; + targetframeworkversion = "v4.7.1"; targetLanguageVersion = "latest"; cscToolPath = Paths.Combine(EditorApplication.applicationContentsPath, "Tools", "RoslynScripts"); @@ -634,7 +668,7 @@ private string ProjectHeader(MonoIsland island, _settings.EditorAssemblyPath, string.Join(";", new[] { "DEBUG", "TRACE"}.Concat(island._defines).Concat(responseFilesData.SelectMany(x => x.Defines)).Distinct().ToArray()), MSBuildNamespaceUri, - Path.GetFileNameWithoutExtension(island._output), + Utility.FileNameWithoutExtension(island._output), EditorSettings.projectGenerationRootNamespace, targetframeworkversion, targetLanguageVersion, @@ -683,7 +717,7 @@ private string SolutionText(IEnumerable islands, Mode mode) var relevantIslands = RelevantIslandsForMode(islands, mode); string projectEntries = GetProjectEntries(relevantIslands); string projectConfigurations = string.Join(WindowsNewline, relevantIslands.Select(i => GetProjectActiveConfigurations(ProjectGuid(i._output))).ToArray()); - return string.Format(_settings.SolutionTemplate, fileversion, vsversion, projectEntries, projectConfigurations, ReadExistingMonoDevelopSolutionProperties()); + return string.Format(_settings.SolutionTemplate, fileversion, vsversion, projectEntries, projectConfigurations); } private static IEnumerable RelevantIslandsForMode(IEnumerable islands, Mode mode) @@ -700,7 +734,7 @@ internal string GetProjectEntries(IEnumerable islands) { var projectEntries = islands.Select(i => string.Format( DefaultSynchronizationSettings.SolutionProjectEntryTemplate, - SolutionGuid(i), Path.GetFileNameWithoutExtension(i._output), Path.GetFileName(ProjectFile(i)), ProjectGuid(i._output) + SolutionGuid(i), Utility.FileNameWithoutExtension(i._output), Path.GetFileName(ProjectFile(i)), ProjectGuid(i._output) )); return string.Join(WindowsNewline, projectEntries.ToArray()); @@ -733,7 +767,7 @@ private string EscapedRelativePathFor(string file) string ProjectGuid(string assembly) { - return SolutionGuidGenerator.GuidForProject(_projectName + Path.GetFileNameWithoutExtension(assembly)); + return SolutionGuidGenerator.GuidForProject(_projectName + Utility.FileNameWithoutExtension(assembly)); } string SolutionGuid(MonoIsland island) @@ -743,79 +777,7 @@ string SolutionGuid(MonoIsland island) string ProjectFooter(MonoIsland island) { - return string.Format(_settings.GetProjectFooterTemplate(ScriptingLanguageFor(island)), ReadExistingMonoDevelopProjectProperties(island)); - } - - string ReadExistingMonoDevelopSolutionProperties() - { - if (!SolutionExists()) return DefaultMonoDevelopSolutionProperties; - string[] lines; - try - { - lines = File.ReadAllLines(SolutionFile()); - } - catch (IOException) - { - return DefaultMonoDevelopSolutionProperties; - } - - StringBuilder existingOptions = new StringBuilder(); - bool collecting = false; - - foreach (string line in lines) - { - if (_MonoDevelopPropertyHeader.IsMatch(line)) - { - collecting = true; - } - if (collecting) - { - if (line.Contains("EndGlobalSection")) - { - existingOptions.Append(line); - collecting = false; - } - else - existingOptions.AppendFormat("{0}{1}", line, WindowsNewline); - } - } - - if (0 < existingOptions.Length) - { - return existingOptions.ToString(); - } - - return DefaultMonoDevelopSolutionProperties; - } - - string ReadExistingMonoDevelopProjectProperties(MonoIsland island) - { - if (!ProjectExists(island)) return string.Empty; - XmlDocument doc = new XmlDocument(); - XmlNamespaceManager manager; - try - { - doc.Load(ProjectFile(island)); - manager = new XmlNamespaceManager(doc.NameTable); - manager.AddNamespace("msb", MSBuildNamespaceUri); - } - catch (Exception ex) - { - if (ex is IOException || - ex is XmlException) - return string.Empty; - throw; - } - - XmlNodeList nodes = doc.SelectNodes("/msb:Project/msb:ProjectExtensions", manager); - if (0 == nodes.Count) return string.Empty; - - StringBuilder sb = new StringBuilder(); - foreach (XmlNode node in nodes) - { - sb.AppendLine(node.OuterXml); - } - return sb.ToString(); + return _settings.GetProjectFooterTemplate(ScriptingLanguageFor(island)); } [Obsolete("Use AssemblyHelper.IsManagedAssembly")] diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000000..2303b574a4 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1 @@ +For terms of use, see https://unity3d.com/legal/licenses/Unity_Reference_Only_License diff --git a/Modules/Animation/ScriptBindings/AvatarBuilder.bindings.cs b/Modules/Animation/ScriptBindings/AvatarBuilder.bindings.cs index 78b386654b..5b6b14dbf7 100644 --- a/Modules/Animation/ScriptBindings/AvatarBuilder.bindings.cs +++ b/Modules/Animation/ScriptBindings/AvatarBuilder.bindings.cs @@ -88,6 +88,7 @@ public struct HumanDescription internal float m_ArmStretch; internal float m_LegStretch; internal float m_FeetSpacing; + internal float m_GlobalScale; internal string m_RootMotionBoneName; diff --git a/Modules/AssetBundle/Managed/AssetBundle.bindings.cs b/Modules/AssetBundle/Managed/AssetBundle.bindings.cs index 3fd9f51cf8..f7cfe65ab3 100644 --- a/Modules/AssetBundle/Managed/AssetBundle.bindings.cs +++ b/Modules/AssetBundle/Managed/AssetBundle.bindings.cs @@ -40,6 +40,7 @@ public enum AssetBundleLoadResult [NativeHeader("AssetBundleScriptingClasses.h")] [NativeHeader("Modules/AssetBundle/Public/AssetBundleSaveAndLoadHelper.h")] [NativeHeader("Modules/AssetBundle/Public/AssetBundleUtility.h")] + [NativeHeader("Modules/AssetBundle/Public/AssetBundleLoadAssetUtility.h")] [ExcludeFromPreset] public partial class AssetBundle : Object { diff --git a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterClipEditor.cs b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterClipEditor.cs index 86949bd7fe..bff5b11e02 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterClipEditor.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterClipEditor.cs @@ -112,7 +112,7 @@ private class Styles EditorGUIUtility.TrTextContent("Once", "The animation plays through to the end once and then stops."), EditorGUIUtility.TrTextContent("Loop", "The animation plays through and then restarts when the end is reached."), EditorGUIUtility.TrTextContent("PingPong", "The animation plays through and then plays in reverse from the end to the start, and so on."), - EditorGUIUtility.TrTextContent("ClampForever", "The animation plays through but the last frame is repeated indefinitely. This is not the same as Once mode because playback does not technically stop at the last frame (which is useful when blending animations).") + EditorGUIUtility.TrTextContent("ClampForever", "The animation plays through, but the last frame is repeated indefinitely. This is not the same as Once mode because playback does not technically stop at the last frame (which is useful when blending animations).") }; public GUIContent BakeIK = EditorGUIUtility.TrTextContent("Bake Animations", "Enable this when using IK or simulation in your animation package. Unity will convert to forward kinematics on import. This option is available only for Maya, 3dsMax and Cinema4D files."); diff --git a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterMaterialEditor.cs b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterMaterialEditor.cs index 45e8916c8a..eaa2337fa7 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterMaterialEditor.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterMaterialEditor.cs @@ -190,6 +190,10 @@ internal override void OnEnable() private void BuildMaterialsCache() { + // do not set if multiple selection. + if (m_Materials.hasMultipleDifferentValues) + return; + m_MaterialsCache.Clear(); for (int materialIdx = 0; materialIdx < m_Materials.arraySize; ++materialIdx) { @@ -204,6 +208,10 @@ private void BuildMaterialsCache() private void BuildExternalObjectsCache() { + // do not set if multiple selection. + if (m_ExternalObjects.hasMultipleDifferentValues) + return; + m_ExternalObjectsCache.Clear(); for (int externalObjectIdx = 0, count = m_ExternalObjects.arraySize; externalObjectIdx < count; ++externalObjectIdx) { @@ -483,7 +491,7 @@ void DoMaterialsGUI() } // hidden for multi-selection - if (m_ImportMaterials.boolValue && targets.Length == 1 && m_Materials.arraySize > 0 && m_MaterialLocation.intValue != 0 && !m_MaterialLocation.hasMultipleDifferentValues) + if (m_ImportMaterials.boolValue && targets.Length == 1 && m_Materials.arraySize > 0 && m_MaterialLocation.intValue != 0 && !m_MaterialLocation.hasMultipleDifferentValues && !m_Materials.hasMultipleDifferentValues && !m_ExternalObjects.hasMultipleDifferentValues) { GUILayout.Label(Styles.ExternalMaterialMappings, EditorStyles.boldLabel); diff --git a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterModelEditor.cs b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterModelEditor.cs index e5199bd120..b9d589cb5c 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterModelEditor.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterModelEditor.cs @@ -119,7 +119,7 @@ protected static class Styles public static GUIContent NormalsLabel = EditorGUIUtility.TrTextContent("Normals", "Source of mesh normals. If Import is selected and a mesh has no normals, they will be calculated instead."); public static GUIContent RecalculateNormalsLabel = EditorGUIUtility.TrTextContent("Normals Mode", "How to weight faces when calculating normals."); - public static GUIContent SmoothingAngle = EditorGUIUtility.TrTextContent("Smoothing Angle", "When calculating normals on a mesh that doesn’t have smoothing groups, edges between faces will be smooth if this value is greater than the angle between the faces."); + public static GUIContent SmoothingAngle = EditorGUIUtility.TrTextContent("Smoothing Angle", "When calculating normals on a mesh that doesn't have smoothing groups, edges between faces will be smooth if this value is greater than the angle between the faces."); public static GUIContent TangentsLabel = EditorGUIUtility.TrTextContent("Tangents", "Source of mesh tangents. If Import is selected and a mesh has no tangents, they will be calculated instead."); @@ -134,8 +134,7 @@ protected static class Styles public static GUIContent secondaryUVHardAngle = EditorGUIUtility.TrTextContent("Hard Angle", "Angle between neighbor triangles that will generate seam."); public static GUIContent secondaryUVPackMargin = EditorGUIUtility.TrTextContent("Pack Margin", "Measured in pixels, assuming mesh will cover an entire 1024x1024 lightmap."); - public static GUIContent LegacyBlendShapeNormalsWarning = EditorGUIUtility.TrTextContent("This Model was originally imported in an earlier version of Unity. If your Mesh has Blend Shapes, you may notice some artifacts or missing normals, and options for Blend Shape Normals and Smoothness Source will not be shown."); - public static GUIContent UpgradeButtonLabel = EditorGUIUtility.TrTextContent("Fix Now"); + public static GUIContent LegacyComputeNormalsFromSmoothingGroupsWhenMeshHasBlendShapes = EditorGUIUtility.TrTextContent("Legacy Blend Shape Normals", "Compute normals from smoothing groups when the mesh has BlendShapes."); } public override void OnInspectorGUI() @@ -145,26 +144,6 @@ public override void OnInspectorGUI() GeometryGUI(); } - bool HelpBoxWithButton(GUIContent messageContent, GUIContent buttonContent, MessageType type) - { - const float kButtonWidth = 60f; - const float kSpacing = 5f; - const float kButtonHeight = 20f; - - // Reserve size of wrapped text - Rect contentRect = GUILayoutUtility.GetRect(messageContent, EditorStyles.helpBox); - // Reserve size of button - GUILayoutUtility.GetRect(1, kButtonHeight + kSpacing); - - // Render background box with text at full height - contentRect.height += kButtonHeight + kSpacing; - GUI.Label(contentRect, EditorGUIUtility.TempContent(messageContent.text, EditorGUIUtility.GetHelpIcon(type)), EditorStyles.helpBox); - - // Button (align lower right) - Rect buttonRect = new Rect(contentRect.xMax - kButtonWidth - 4f, contentRect.yMax - kButtonHeight - 4f, kButtonWidth, kButtonHeight); - return GUI.Button(buttonRect, buttonContent); - } - protected void MeshesGUI() { GUILayout.Label(Styles.Meshes, EditorStyles.boldLabel); @@ -263,16 +242,27 @@ protected void GeometryGUI() void NormalsTangentsGUI() { + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = m_LegacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes.hasMultipleDifferentValues; + var legacyComputeFromSmoothingGroups = EditorGUILayout.Toggle(Styles.LegacyComputeNormalsFromSmoothingGroupsWhenMeshHasBlendShapes, m_LegacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes.boolValue); + EditorGUI.showMixedValue = false; + if (EditorGUI.EndChangeCheck()) + { + m_LegacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes.boolValue = legacyComputeFromSmoothingGroups; + } + using (var horizontal = new EditorGUILayout.HorizontalScope()) { using (var property = new EditorGUI.PropertyScope(horizontal.rect, Styles.NormalsLabel, m_NormalImportMode)) { EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = m_NormalImportMode.hasMultipleDifferentValues; var newValue = (int)(ModelImporterNormals)EditorGUILayout.EnumPopup(property.content, (ModelImporterNormals)m_NormalImportMode.intValue); + EditorGUI.showMixedValue = false; if (EditorGUI.EndChangeCheck()) { m_NormalImportMode.intValue = newValue; - // This check is made in CheckConcistency, but because AssetImporterEditor does not serialize the object each update, + // This check is made in CheckConsistency, but because AssetImporterEditor does not serialize the object each update, // We need to double check here for UI consistency. if (m_NormalImportMode.intValue == (int)ModelImporterNormals.None) m_TangentImportMode.intValue = (int)ModelImporterTangents.None; @@ -295,7 +285,14 @@ void NormalsTangentsGUI() { using (new EditorGUI.DisabledScope(m_NormalImportMode.intValue == (int)ModelImporterNormals.None)) { - m_BlendShapeNormalCalculationMode.intValue = (int)(ModelImporterNormals)EditorGUILayout.EnumPopup(Styles.BlendShapeNormalsLabel, (ModelImporterNormals)m_BlendShapeNormalCalculationMode.intValue); + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = m_BlendShapeNormalCalculationMode.hasMultipleDifferentValues; + var blendShapeNormalCalculationMode = (int)(ModelImporterNormals)EditorGUILayout.EnumPopup(Styles.BlendShapeNormalsLabel, (ModelImporterNormals)m_BlendShapeNormalCalculationMode.intValue); + EditorGUI.showMixedValue = false; + if (EditorGUI.EndChangeCheck()) + { + m_BlendShapeNormalCalculationMode.intValue = blendShapeNormalCalculationMode; + } } } @@ -306,7 +303,14 @@ void NormalsTangentsGUI() { using (var property = new EditorGUI.PropertyScope(horizontal.rect, Styles.RecalculateNormalsLabel, m_NormalCalculationMode)) { - m_NormalCalculationMode.intValue = (int)(ModelImporterNormalCalculationMode)EditorGUILayout.EnumPopup(property.content, (ModelImporterNormalCalculationMode)m_NormalCalculationMode.intValue); + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = m_NormalCalculationMode.hasMultipleDifferentValues; + var normalCalculationMode = (int)(ModelImporterNormalCalculationMode)EditorGUILayout.EnumPopup(property.content, (ModelImporterNormalCalculationMode)m_NormalCalculationMode.intValue); + EditorGUI.showMixedValue = false; + if (EditorGUI.EndChangeCheck()) + { + m_NormalCalculationMode.intValue = normalCalculationMode; + } } } @@ -315,7 +319,16 @@ void NormalsTangentsGUI() { using (var horizontal = new EditorGUILayout.HorizontalScope()) using (var property = new EditorGUI.PropertyScope(horizontal.rect, Styles.NormalSmoothingSourceLabel, m_NormalSmoothingSource)) - m_NormalSmoothingSource.intValue = (int)(ModelImporterNormalSmoothingSource)EditorGUILayout.EnumPopup(property.content, (ModelImporterNormalSmoothingSource)m_NormalSmoothingSource.intValue); + { + EditorGUI.BeginChangeCheck(); + EditorGUI.showMixedValue = m_NormalSmoothingSource.hasMultipleDifferentValues; + var normalSmoothingSource = (int)(ModelImporterNormalSmoothingSource)EditorGUILayout.EnumPopup(property.content, (ModelImporterNormalSmoothingSource)m_NormalSmoothingSource.intValue); + EditorGUI.showMixedValue = false; + if (EditorGUI.EndChangeCheck()) + { + m_NormalSmoothingSource.intValue = normalSmoothingSource; + } + } } // Normal split angle @@ -328,14 +341,6 @@ void NormalsTangentsGUI() if (EditorGUI.EndChangeCheck()) m_NormalSmoothAngle.floatValue = Mathf.Round(m_NormalSmoothAngle.floatValue); } - - if (m_LegacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes.boolValue) - { - if (HelpBoxWithButton(Styles.LegacyBlendShapeNormalsWarning, Styles.UpgradeButtonLabel, MessageType.Warning)) - { - m_LegacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes.boolValue = false; - } - } } // Choose the option values and labels based on what the NormalImportMode is diff --git a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs index 0991b498b6..fa84a328ae 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs @@ -99,7 +99,7 @@ static class Styles public static GUIContent UpdateMuscleDefinitionFromSource = EditorGUIUtility.TrTextContent("Update", "Update the copy of the muscle definition from the source."); public static GUIContent RootNode = EditorGUIUtility.TrTextContent("Root node", "Specify the root node used to extract the animation translation."); - public static GUIContent AvatarDefinition = EditorGUIUtility.TrTextContent("Avatar Definition", "Choose between Create From This Model or Copy From Other Avatar. The first one create an Avatar for this file and the second one use an Avatar from another file to import animation."); + public static GUIContent AvatarDefinition = EditorGUIUtility.TrTextContent("Avatar Definition", "Choose between Create From This Model or Copy From Other Avatar. The first one creates an Avatar for this file and the second one uses an Avatar from another file to import animation."); public static GUIContent[] AvatarDefinitionOpt = { @@ -116,10 +116,10 @@ static class Styles public static GUIContent MaxBonesPerVertex = EditorGUIUtility.TrTextContent("Max Bones/Vertex", "Number of bones that can affect each vertex."); public static GUIContent MinBoneWeight = EditorGUIUtility.TrTextContent("Min Bone Weight", "Bone weights smaller than this value are rejected. The remaining weights are scaled to add up to 1.0."); - public static GUIContent UpdateReferenceClips = EditorGUIUtility.TrTextContent("Update reference clips", "Click on this button to update all the @convention file referencing this file. Should set all these files to Copy From Other Avatar, set the source Avatar to this one and reimport all these files."); + public static GUIContent UpdateReferenceClips = EditorGUIUtility.TrTextContent("Update reference clips", "Click on this button to update all the @convention files referencing this file. Should set all these files to Copy From Other Avatar, set the source Avatar to this one and reimport all these files."); public static GUIContent ImportMessages = EditorGUIUtility.TrTextContent("Import Messages"); - public static GUIContent ExtraExposedTransform = EditorGUIUtility.TrTextContent("Extra Transforms to Expose", "Select the list of transforms to expose in the optmized GameObject hierarchy."); + public static GUIContent ExtraExposedTransform = EditorGUIUtility.TrTextContent("Extra Transforms to Expose", "Select the list of transforms to expose in the optimized GameObject hierarchy."); } public ModelImporterRigEditor(AssetImporterEditor panelContainer) @@ -278,18 +278,27 @@ void GenericGUI() EditorGUI.BeginChangeCheck(); using (new EditorGUI.DisabledScope(!m_CanMultiEditTransformList)) { - rootIndex = EditorGUILayout.Popup(Styles.RootNode, rootIndex, m_RootMotionBoneList); - } - if (EditorGUI.EndChangeCheck()) - { - if (rootIndex > 0 && rootIndex < m_RootMotionBoneList.Length) + if (assetTarget == null) { m_RootMotionBoneName.stringValue = - FileUtil.GetLastPathNameComponent(m_RootMotionBoneList[rootIndex].text); + EditorGUILayout.TextField(Styles.RootNode, m_RootMotionBoneName.stringValue); } else + rootIndex = EditorGUILayout.Popup(Styles.RootNode, rootIndex, m_RootMotionBoneList); + } + if (EditorGUI.EndChangeCheck()) + { + if (assetTarget != null) { - m_RootMotionBoneName.stringValue = ""; + if (rootIndex > 0 && rootIndex < m_RootMotionBoneList.Length) + { + m_RootMotionBoneName.stringValue = + FileUtil.GetLastPathNameComponent(m_RootMotionBoneList[rootIndex].text); + } + else + { + m_RootMotionBoneName.stringValue = ""; + } } } } diff --git a/Modules/AssetPipelineEditor/ImportSettings/PluginImporterInspector.cs b/Modules/AssetPipelineEditor/ImportSettings/PluginImporterInspector.cs index ecf1ba71f1..cc87e0bbc3 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/PluginImporterInspector.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/PluginImporterInspector.cs @@ -47,8 +47,9 @@ internal enum Compatibility : int Compatible = 1 } - private Compatibility m_CompatibleWithAnyPlatform; private Compatibility m_AutoReferenced; + private Compatibility m_ValidateReferences; + private Compatibility m_CompatibleWithAnyPlatform; private Compatibility m_CompatibleWithEditor; private Compatibility[] m_CompatibleWithPlatform = new Compatibility[GetPlatformGroupArraySize()]; private List m_DefineConstraintState = new List(); @@ -314,6 +315,7 @@ protected override void ResetValues() ResetCompatability(ref m_CompatibleWithAnyPlatform, (imp => imp.GetCompatibleWithAnyPlatform())); ResetCompatability(ref m_CompatibleWithEditor, (imp => imp.GetCompatibleWithEditor())); ResetCompatability(ref m_AutoReferenced, (imp => !imp.IsExplicitlyReferenced)); + ResetCompatability(ref m_ValidateReferences, (imp => imp.ValidateReferences)); // If Any Platform is selected, initialize m_Compatible* variables using compatability function // If Any Platform is unselected, initialize m_Compatible* variables using exclude function // This gives correct initialization in case when plugin is imported for the first time, and only "Any Platform" is selected @@ -391,6 +393,9 @@ protected override void Apply() if (m_AutoReferenced > Compatibility.Mixed) imp.IsExplicitlyReferenced = m_AutoReferenced != Compatibility.Compatible; + if (m_ValidateReferences > Compatibility.Mixed) + imp.ValidateReferences = m_ValidateReferences == Compatibility.Compatible; + foreach (BuildTarget platform in GetValidBuildTargets()) { if (m_CompatibleWithPlatform[(int)platform] > Compatibility.Mixed) @@ -655,6 +660,8 @@ private void ShowReferenceOptions() EditorGUILayout.BeginVertical(GUI.skin.box); EditorGUI.BeginChangeCheck(); m_AutoReferenced = ToggleWithMixedValue(m_AutoReferenced, "Auto Reference"); + m_ValidateReferences = ToggleWithMixedValue(m_ValidateReferences, "Validate References"); + if (EditorGUI.EndChangeCheck()) { m_HasModified = true; @@ -666,7 +673,8 @@ public override void OnInspectorGUI() { using (new EditorGUI.DisabledScope(false)) { - if (!importer.isNativePlugin) + var isManagedPlugin = importers.All(x => x.dllType == DllType.ManagedNET35 || x.dllType == DllType.ManagedNET40); + if (isManagedPlugin) { ShowReferenceOptions(); GUILayout.Space(10f); @@ -681,8 +689,11 @@ public override void OnInspectorGUI() if (IsEditingPlatformSettingsSupported()) ShowPlatformSettings(); - GUILayout.Label(defineConstraints, EditorStyles.boldLabel); - m_DefineConstraints.DoLayoutList(); + if (isManagedPlugin) + { + GUILayout.Label(defineConstraints, EditorStyles.boldLabel); + m_DefineConstraints.DoLayoutList(); + } if (importers.All(imp => imp.isNativePlugin)) { diff --git a/Modules/AssetPipelineEditor/Public/ModelImporting/ModelImporter.bindings.cs b/Modules/AssetPipelineEditor/Public/ModelImporting/ModelImporter.bindings.cs index 7aaf33f0c8..845871b1fe 100644 --- a/Modules/AssetPipelineEditor/Public/ModelImporting/ModelImporter.bindings.cs +++ b/Modules/AssetPipelineEditor/Public/ModelImporting/ModelImporter.bindings.cs @@ -6,7 +6,6 @@ using System.Runtime.InteropServices; using UnityEngine; using UnityEngine.Bindings; -using DescriptionAttribute = System.ComponentModel.DescriptionAttribute; using Object = UnityEngine.Object; using UsedByNativeCodeAttribute = UnityEngine.Scripting.UsedByNativeCodeAttribute; @@ -89,6 +88,8 @@ public sealed partial class ModelImporterClipAnimation bool m_MaskNeedsUpdating; + long internalID; + public string takeName { get { return m_TakeName; } set { m_TakeName = value; } } public string name { get { return m_Name; } set { m_Name = value; } } public float firstFrame { get { return m_FirstFrame; } set { m_FirstFrame = value; } } @@ -246,7 +247,7 @@ public enum ModelImporterNormals [NativeType(Header = "Modules/AssetPipelineEditor/Public/ModelImporting/ImportMesh.h")] public enum ModelImporterNormalCalculationMode { - [Description("Unweighted (Legacy)")] + [InspectorName("Unweighted (Legacy)")] Unweighted_Legacy, Unweighted, @@ -272,7 +273,7 @@ public enum ModelImporterTangents CalculateLegacy = 1, CalculateLegacyWithSplitTangents = 4, - [Description("Calculate Mikktspace")] + [InspectorName("Calculate Mikktspace")] CalculateMikk = 3, None = 2, @@ -289,9 +290,9 @@ public enum ModelImporterMeshCompression public enum ModelImporterIndexFormat { Auto = 0, - [Description("16 bits")] + [InspectorName("16 bits")] UInt16 = 1, - [Description("32 bits")] + [InspectorName("32 bits")] UInt32 = 2, } @@ -445,6 +446,11 @@ public extern bool useFileUnits set; } + public extern float fileScale + { + get; + } + public extern bool useFileScale { get; diff --git a/Modules/AssetPipelineEditor/Public/PluginImporter.bindings.cs b/Modules/AssetPipelineEditor/Public/PluginImporter.bindings.cs index a845f32941..9cc8288485 100644 --- a/Modules/AssetPipelineEditor/Public/PluginImporter.bindings.cs +++ b/Modules/AssetPipelineEditor/Public/PluginImporter.bindings.cs @@ -27,6 +27,9 @@ public sealed partial class PluginImporter : AssetImporter [NativeProperty("IsExplicitlyReferenced")] internal extern bool IsExplicitlyReferenced { get; set; } + [NativeProperty("ValidateReferences")] + internal extern bool ValidateReferences { get; set;} + [NativeProperty("DefineConstraints")] public extern string[] DefineConstraints { get; set; } diff --git a/Modules/AssetPipelineEditor/Public/ScriptedImporter.cs b/Modules/AssetPipelineEditor/Public/ScriptedImporter.cs index 2c8e929b89..cf02c4cfb1 100644 --- a/Modules/AssetPipelineEditor/Public/ScriptedImporter.cs +++ b/Modules/AssetPipelineEditor/Public/ScriptedImporter.cs @@ -70,11 +70,12 @@ internal static void RegisterScriptedImporters() } } - MethodInfo getImportDependencyHintMethod = importerType.GetMethod("GetHashOfImportedAssetDependencyHintsForTesting", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + var supportsImportDependencyHinting = importerType.GetMethod("GetHashOfImportedAssetDependencyHintsForTesting", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) != null + || importerType.GetMethod("GatherDependenciesFromSourceFile", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) != null; // Register the importer foreach (var ext in handledExts) - AssetImporter.RegisterImporter(importerType, attribute.version, attribute.importQueuePriority, ext.Key, getImportDependencyHintMethod != null); + AssetImporter.RegisterImporter(importerType, attribute.version, attribute.importQueuePriority, ext.Key, supportsImportDependencyHinting); } } diff --git a/Modules/AssetPipelineEditor/Public/VideoImporter.bindings.cs b/Modules/AssetPipelineEditor/Public/VideoImporter.bindings.cs index 6199e4366d..df35fe4aef 100644 --- a/Modules/AssetPipelineEditor/Public/VideoImporter.bindings.cs +++ b/Modules/AssetPipelineEditor/Public/VideoImporter.bindings.cs @@ -131,13 +131,7 @@ public VideoImporterTargetSettings defaultTargetSettings public VideoImporterTargetSettings GetTargetSettings(string platform) { - BuildTargetGroup platformGroup = BuildPipeline.GetBuildTargetGroupByName(platform); - if (!platform.Equals(VideoClipImporter.defaultTargetName, StringComparison.OrdinalIgnoreCase) && platformGroup == BuildTargetGroup.Unknown) - { - throw new ArgumentException("Unknown platform passed to AudioImporter.GetOverrideSampleSettings (" + platform + "), please use one of " + - "'Default', 'Web', 'Standalone', 'iOS', 'Android', 'WebGL', 'PS4', 'XBox360', 'XboxOne', 'WP8', or 'WSA'"); - } - + BuildTargetGroup platformGroup = GetBuildTargetGroup("GetTargetSetting", platform); return Internal_GetTargetSettings(platformGroup); } @@ -151,13 +145,7 @@ internal VideoImporterTargetSettings Internal_GetTargetSettings(BuildTargetGroup public void SetTargetSettings(string platform, VideoImporterTargetSettings settings) { - BuildTargetGroup platformGroup = BuildPipeline.GetBuildTargetGroupByName(platform); - if (!platform.Equals(VideoClipImporter.defaultTargetName, StringComparison.OrdinalIgnoreCase) && platformGroup == BuildTargetGroup.Unknown) - { - throw new ArgumentException("Unknown platform passed to AudioImporter.GetOverrideSampleSettings (" + platform + "), please use one of " + - "'Default', 'Web', 'Standalone', 'iOS', 'Android', 'WebGL', 'PS4', 'XBox360', 'XboxOne', 'WP8', or 'WSA'"); - } - + var platformGroup = GetBuildTargetGroup("SetTargetSettings", platform); Internal_SetTargetSettings(platformGroup, settings); } @@ -166,17 +154,29 @@ public void SetTargetSettings(string platform, VideoImporterTargetSettings setti public void ClearTargetSettings(string platform) { - if (platform.Equals(VideoClipImporter.defaultTargetName, StringComparison.OrdinalIgnoreCase)) - throw new ArgumentException("Cannot clear the Default VideoClipTargetSettings."); + var platformGroup = GetBuildTargetGroup("ClearTargetSettings", platform, false); + Internal_ClearTargetSettings(platformGroup); + } + + private BuildTargetGroup GetBuildTargetGroup(string methodName, string platform, bool acceptDefault = true) + { + if (!acceptDefault && + platform.Equals(VideoClipImporter.defaultTargetName, StringComparison.OrdinalIgnoreCase)) + throw new ArgumentException("Cannot call VideoClipImporter." + methodName + " for the default VideoImporterTargetSettings."); BuildTargetGroup platformGroup = BuildPipeline.GetBuildTargetGroupByName(platform); - if (platformGroup == BuildTargetGroup.Unknown) + if (!platform.Equals(VideoClipImporter.defaultTargetName, StringComparison.OrdinalIgnoreCase) && platformGroup == BuildTargetGroup.Unknown) { - throw new ArgumentException("Unknown platform passed to AudioImporter.GetOverrideSampleSettings (" + platform + "), please use one of " + - "'Web', 'Standalone', 'iOS', 'Android', 'WebGL', 'PS4', 'XBox360', 'XboxOne', 'WP8', or 'WSA'"); + var platformList = "'Standalone', 'Android', 'iOS', 'Lumin', 'PS4', 'Switch', 'tvOS', 'WebGL', 'WSA', 'WebGL' or 'XboxOne'"; + if (acceptDefault) + platformList = "'Default', " + platformList; + + throw new ArgumentException( + "Unknown platform passed to VideoClipImporter." + methodName + " (" + platform + "), please use one of " + + platformList + "."); } - Internal_ClearTargetSettings(platformGroup); + return platformGroup; } [NativeName("ClearTargetSettings")] diff --git a/Modules/Audio/Public/ScriptBindings/AudioClipExtensions.bindings.cs b/Modules/Audio/Public/ScriptBindings/AudioClipExtensions.bindings.cs index f7a9ed54c7..1e003d4020 100644 --- a/Modules/Audio/Public/ScriptBindings/AudioClipExtensions.bindings.cs +++ b/Modules/Audio/Public/ScriptBindings/AudioClipExtensions.bindings.cs @@ -21,16 +21,17 @@ internal static class AudioClipExtensions { public static AudioSampleProvider CreateAudioSampleProvider( this AudioClip audioClip, ulong startSampleFrameIndex = 0, - long endSampleFrameIndex = 0, bool loop = false) + long endSampleFrameIndex = 0, bool loop = false, bool allowDrop = false) { return AudioSampleProvider.Lookup( Internal_CreateAudioClipSampleProvider( - audioClip, startSampleFrameIndex, endSampleFrameIndex, loop), null, 0); + audioClip, startSampleFrameIndex, endSampleFrameIndex, loop, allowDrop), + null, 0); } [NativeMethod(IsFreeFunction = true, ThrowsException = true)] extern private static uint Internal_CreateAudioClipSampleProvider( - AudioClip audioClip, ulong start, long end, bool loop); + AudioClip audioClip, ulong start, long end, bool loop, bool allowDrop); } } diff --git a/Modules/Audio/Public/ScriptBindings/AudioSourceExtensions.bindings.cs b/Modules/Audio/Public/ScriptBindings/AudioSourceExtensions.bindings.cs new file mode 100644 index 0000000000..8bce8dca0a --- /dev/null +++ b/Modules/Audio/Public/ScriptBindings/AudioSourceExtensions.bindings.cs @@ -0,0 +1,37 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + + +using System; +using System.Runtime.CompilerServices; +using UnityEngine.Bindings; +using UnityEngine; + +[assembly: InternalsVisibleTo("Unity.Audio.Tests")] + +namespace UnityEngine.Experimental.Audio +{ + [NativeHeader("Modules/Audio/Public/ScriptBindings/AudioSourceExtensions.bindings.h")] + [NativeHeader("Modules/Audio/Public/AudioSource.h")] + [NativeHeader("AudioScriptingClasses.h")] + internal static class AudioSourceExtensionsInternal + { + public static void RegisterSampleProvider(this AudioSource source, AudioSampleProvider provider) + { + Internal_RegisterSampleProviderWithAudioSource(source, provider.id); + } + + public static void UnregisterSampleProvider(this AudioSource source, AudioSampleProvider provider) + { + Internal_UnregisterSampleProviderFromAudioSource(source, provider.id); + } + + [NativeMethod(IsFreeFunction = true, ThrowsException = true)] + private extern static void Internal_RegisterSampleProviderWithAudioSource(AudioSource source, uint providerId); + + [NativeMethod(IsFreeFunction = true, ThrowsException = true)] + private extern static void Internal_UnregisterSampleProviderFromAudioSource(AudioSource source, uint providerId); + } +} + diff --git a/Modules/Audio/Public/csas/Managed/DSPCommandBlock.cs b/Modules/Audio/Public/csas/Managed/DSPCommandBlock.cs index 4af753da58..95f488a76c 100644 --- a/Modules/Audio/Public/csas/Managed/DSPCommandBlock.cs +++ b/Modules/Audio/Public/csas/Managed/DSPCommandBlock.cs @@ -7,6 +7,7 @@ using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using UnityEngine.Experimental.Audio; +using UnityEngine; [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Unity.UNode.Audio")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Unity.UNode.Audio.Tests")] @@ -161,12 +162,100 @@ public void Disconnect(DSPNode output, int outputPort, DSPNode input, int inputP public void SetAttenuation(DSPConnection connection, float value, uint interpolationLength = 0) { - Internal_SetAttenuation(ref this, ref connection, value, interpolationLength); + unsafe + { + Internal_SetAttenuation(ref this, ref connection, (void*)&value, 1, interpolationLength); + } + } + + public void SetAttenuation(DSPConnection connection, float value1, float value2, uint interpolationLength = 0) + { + unsafe + { + float* buffer = stackalloc float[2]; + buffer[0] = value1; + buffer[1] = value2; + Internal_SetAttenuation(ref this, ref connection, buffer, 2, interpolationLength); + } + } + + public void SetAttenuation(DSPConnection connection, float value1, float value2, float value3, uint interpolationLength = 0) + { + unsafe + { + float* buffer = stackalloc float[3]; + buffer[0] = value1; + buffer[1] = value2; + buffer[2] = value3; + Internal_SetAttenuation(ref this, ref connection, buffer, 3, interpolationLength); + } + } + + public void SetAttenuation(DSPConnection connection, float value1, float value2, float value3, float value4, uint interpolationLength = 0) + { + unsafe + { + float* buffer = stackalloc float[4]; + buffer[0] = value1; + buffer[1] = value2; + buffer[2] = value3; + buffer[3] = value4; + Internal_SetAttenuation(ref this, ref connection, buffer, 4, interpolationLength); + } + } + + public unsafe void SetAttenuation(DSPConnection connection, float* value, byte dimension, uint interpolationLength = 0) + { + Internal_SetAttenuation(ref this, ref connection, value, dimension, interpolationLength); } public void AddAttenuationKey(DSPConnection connection, ulong dspClock, float value) { - Internal_AddAttenuationKey(ref this, ref connection, dspClock, value); + unsafe + { + Internal_AddAttenuationKey(ref this, ref connection, dspClock, &value, 1); + } + } + + public void AddAttenuationKey(DSPConnection connection, ulong dspClock, float value1, float value2) + { + unsafe + { + float* buffer = stackalloc float[2]; + buffer[0] = value1; + buffer[1] = value2; + Internal_AddAttenuationKey(ref this, ref connection, dspClock, buffer, 2); + } + } + + public void AddAttenuationKey(DSPConnection connection, ulong dspClock, float value1, float value2, float value3) + { + unsafe + { + float* buffer = stackalloc float[3]; + buffer[0] = value1; + buffer[1] = value2; + buffer[2] = value3; + Internal_AddAttenuationKey(ref this, ref connection, dspClock, buffer, 3); + } + } + + public void AddAttenuationKey(DSPConnection connection, ulong dspClock, float value1, float value2, float value3, float value4) + { + unsafe + { + float* buffer = stackalloc float[4]; + buffer[0] = value1; + buffer[1] = value2; + buffer[2] = value3; + buffer[3] = value4; + Internal_AddAttenuationKey(ref this, ref connection, dspClock, buffer, 4); + } + } + + public unsafe void AddAttenuationKey(DSPConnection connection, ulong dspClock, float* value, byte dimension) + { + Internal_AddAttenuationKey(ref this, ref connection, dspClock, value, dimension); } public void SustainAttenuation(DSPConnection connection, ulong dspClock) diff --git a/Modules/Audio/Public/csas/Managed/DSPGraph.cs b/Modules/Audio/Public/csas/Managed/DSPGraph.cs index 0c52a2d1c9..411bb62c00 100644 --- a/Modules/Audio/Public/csas/Managed/DSPGraph.cs +++ b/Modules/Audio/Public/csas/Managed/DSPGraph.cs @@ -108,7 +108,14 @@ public unsafe void ReadMix(NativeArray buffer) public unsafe uint AddNodeEventHandler(Action handler) where TNodeEvent : struct { - return Internal_AddNodeEventHandler(ref this, GetTypeHashCode(), handler); + return AddNodeEventHandler(GetTypeHashCode(), handler); + } + + // FIXME: Temporarily exposed until BurstRuntime.GetHashCode64 has a Unity-core + // equivalent, or DSPGraph's C# code is moved to a package. + public unsafe uint AddNodeEventHandler(long eventTypeHash, Action handler) where TNodeEvent : struct + { + return Internal_AddNodeEventHandler(ref this, eventTypeHash, handler); } public unsafe bool RemoveNodeEventHandler(uint handlerId) diff --git a/Modules/Audio/Public/csas/Managed/ExecuteContext.cs b/Modules/Audio/Public/csas/Managed/ExecuteContext.cs index 0bbafdd64c..156bd8a6a0 100644 --- a/Modules/Audio/Public/csas/Managed/ExecuteContext.cs +++ b/Modules/Audio/Public/csas/Managed/ExecuteContext.cs @@ -21,9 +21,18 @@ internal unsafe struct ExecuteContext public ulong DSPClock { get { return m_DSPClock; } } public uint DSPBufferSize { get { return m_DSPBufferSize; } } public uint SampleRate { get { return m_SampleRate; } } - public void PostEvent(T eventMsg) where T : struct + public void PostEvent(TNodeEvent eventMsg) where TNodeEvent : struct { - ExecuteContextInternal.Internal_PostEvent(m_DSPNodePtr, DSPGraph.GetTypeHashCode(), UnsafeUtility.AddressOf(ref eventMsg), UnsafeUtility.SizeOf()); + PostEvent(DSPGraph.GetTypeHashCode(), eventMsg); + } + + // FIXME: Temporarily exposed until BurstRuntime.GetHashCode64 has a Unity-core + // equivalent, or DSPGraph's C# code is moved to a package. + public void PostEvent(long eventTypeHash, TNodeEvent eventMsg) where TNodeEvent : struct + { + ExecuteContextInternal.Internal_PostEvent( + m_DSPNodePtr, eventTypeHash, UnsafeUtility.AddressOf(ref eventMsg), + UnsafeUtility.SizeOf()); } internal ulong m_DSPClock; diff --git a/Modules/Audio/Public/csas/Managed/ResourceContext.cs b/Modules/Audio/Public/csas/Managed/ResourceContext.cs index bf2b88db69..79248a325a 100644 --- a/Modules/Audio/Public/csas/Managed/ResourceContext.cs +++ b/Modules/Audio/Public/csas/Managed/ResourceContext.cs @@ -24,6 +24,8 @@ public NativeArray AllocateArray(int length) where T : struct var memory = Internal_AllocateArray(m_DSPNodePtr, size); var nBuffer = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(memory, length, Allocator.Invalid); + NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref nBuffer, AtomicSafetyHandle.Create()); + return nBuffer; } diff --git a/Modules/Audio/Public/csas/Managed/SampleBufferArray.cs b/Modules/Audio/Public/csas/Managed/SampleBufferArray.cs index 656a858a91..2980aea888 100644 --- a/Modules/Audio/Public/csas/Managed/SampleBufferArray.cs +++ b/Modules/Audio/Public/csas/Managed/SampleBufferArray.cs @@ -22,6 +22,7 @@ unsafe struct NativeSampleBuffer public uint m_Channels; public SoundFormat m_Format; public float* m_Buffer; + private bool m_Initialized; } internal enum SoundFormat diff --git a/Modules/Audio/Public/csas/ScriptBindings/DSPCommandBlock.bindings.cs b/Modules/Audio/Public/csas/ScriptBindings/DSPCommandBlock.bindings.cs index 353330644b..01cd9cc3a7 100644 --- a/Modules/Audio/Public/csas/ScriptBindings/DSPCommandBlock.bindings.cs +++ b/Modules/Audio/Public/csas/ScriptBindings/DSPCommandBlock.bindings.cs @@ -44,10 +44,10 @@ static extern unsafe void Internal_CreateUpdateRequest( static extern void Internal_DisconnectByHandle(ref DSPCommandBlock block, ref DSPConnection connection); [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - static extern void Internal_SetAttenuation(ref DSPCommandBlock block, ref DSPConnection connection, float value, uint interpolationLength); + static extern unsafe void Internal_SetAttenuation(ref DSPCommandBlock block, ref DSPConnection connection, void* value, byte dimension, uint interpolationLength); [NativeMethod(IsFreeFunction = true, ThrowsException = true)] - static extern void Internal_AddAttenuationKey(ref DSPCommandBlock block, ref DSPConnection connection, ulong dspClock, float value); + static extern unsafe void Internal_AddAttenuationKey(ref DSPCommandBlock block, ref DSPConnection connection, ulong dspClock, void* value, byte dimension); [NativeMethod(IsFreeFunction = true, ThrowsException = true)] static extern void Internal_SustainAttenuation(ref DSPCommandBlock block, ref DSPConnection connection, ulong dspClock); diff --git a/Modules/BuildPipeline/Editor/Managed/ContentBuildInterface.bindings.cs b/Modules/BuildPipeline/Editor/Managed/ContentBuildInterface.bindings.cs index 50f64d1973..301e99aaf5 100644 --- a/Modules/BuildPipeline/Editor/Managed/ContentBuildInterface.bindings.cs +++ b/Modules/BuildPipeline/Editor/Managed/ContentBuildInterface.bindings.cs @@ -94,10 +94,6 @@ public static WriteResult WriteSceneSerializedFile(string outputFolder, string s throw new ArgumentException("String is null or empty.", "outputFolder"); if (string.IsNullOrEmpty(scenePath)) throw new ArgumentException("String is null or empty.", "scenePath"); - if (string.IsNullOrEmpty(processedScene)) - throw new ArgumentException("String is null or empty.", "processedScene"); - if (!File.Exists(processedScene)) - throw new ArgumentException(string.Format("File '{0}' does not exist.", processedScene), "processedScene"); if (writeCommand == null) throw new ArgumentNullException("writeCommand"); if (referenceMap == null) @@ -113,10 +109,6 @@ public static WriteResult WriteSceneSerializedFile(string outputFolder, string s throw new ArgumentException("String is null or empty.", "outputFolder"); if (string.IsNullOrEmpty(scenePath)) throw new ArgumentException("String is null or empty.", "scenePath"); - if (string.IsNullOrEmpty(processedScene)) - throw new ArgumentException("String is null or empty.", "processedScene"); - if (!File.Exists(processedScene)) - throw new ArgumentException(string.Format("File '{0}' does not exist.", processedScene), "processedScene"); if (writeCommand == null) throw new ArgumentNullException("writeCommand"); if (referenceMap == null) @@ -134,10 +126,6 @@ public static WriteResult WriteSceneSerializedFile(string outputFolder, string s throw new ArgumentException("String is null or empty.", "outputFolder"); if (string.IsNullOrEmpty(scenePath)) throw new ArgumentException("String is null or empty.", "scenePath"); - if (string.IsNullOrEmpty(processedScene)) - throw new ArgumentException("String is null or empty.", "processedScene"); - if (!File.Exists(processedScene)) - throw new ArgumentException(string.Format("File '{0}' does not exist.", processedScene), "processedScene"); if (writeCommand == null) throw new ArgumentNullException("writeCommand"); if (referenceMap == null) diff --git a/Modules/BuildReportingEditor/Managed/BuildReport.bindings.cs b/Modules/BuildReportingEditor/Managed/BuildReport.bindings.cs index 19be0e3f49..51f39c2419 100644 --- a/Modules/BuildReportingEditor/Managed/BuildReport.bindings.cs +++ b/Modules/BuildReportingEditor/Managed/BuildReport.bindings.cs @@ -49,7 +49,7 @@ public StrippingInfo strippingInfo [FreeFunction("BuildReporting::SummarizeErrors", HasExplicitThis = true)] internal extern string SummarizeErrors(); - internal extern void AddMessage(LogType messageType, string message); + internal extern void AddMessage(LogType messageType, string message, string exceptionType); internal extern int BeginBuildStep(string stepName); internal extern void ResumeBuildStep(int depth); diff --git a/Modules/CloudServicesSettingsEditor/CrashReporting/Managed/CrashReporting.cs b/Modules/CloudServicesSettingsEditor/CrashReporting/Managed/CrashReporting.cs index 23895f2e73..7ccf1143f0 100644 --- a/Modules/CloudServicesSettingsEditor/CrashReporting/Managed/CrashReporting.cs +++ b/Modules/CloudServicesSettingsEditor/CrashReporting/Managed/CrashReporting.cs @@ -21,7 +21,7 @@ public static string ServiceBaseUrl { get { - string configUrl = UnityConnect.instance.GetConfigurationURL(CloudConfigUrl.CloudPerfEvents); + string configUrl = CrashReportingSettings.GetEventUrl(); if (!string.IsNullOrEmpty(configUrl)) { return configUrl; @@ -70,6 +70,8 @@ public static string GetUsymUploadAuthToken() return environmentValue; } + CrashReportingSettings.EnsureConnectReady(); + string accessToken = UnityConnect.instance.GetAccessToken(); if (string.IsNullOrEmpty(accessToken)) { diff --git a/Modules/CloudServicesSettingsEditor/CrashReporting/ScriptBindings/CrashReportingSettings.bindings.cs b/Modules/CloudServicesSettingsEditor/CrashReporting/ScriptBindings/CrashReportingSettings.bindings.cs index a0ad1438a3..f9dd7337ac 100644 --- a/Modules/CloudServicesSettingsEditor/CrashReporting/ScriptBindings/CrashReportingSettings.bindings.cs +++ b/Modules/CloudServicesSettingsEditor/CrashReporting/ScriptBindings/CrashReportingSettings.bindings.cs @@ -25,6 +25,8 @@ public static partial class CrashReportingSettings internal static extern string GetEventUrl(); internal static extern void SetEventUrl(string eventUrl); + + internal static extern void EnsureConnectReady(); } } diff --git a/Modules/GraphViewEditor/EdgeControl.cs b/Modules/GraphViewEditor/EdgeControl.cs index fc3c4d1b62..e7b2c481f7 100644 --- a/Modules/GraphViewEditor/EdgeControl.cs +++ b/Modules/GraphViewEditor/EdgeControl.cs @@ -309,19 +309,20 @@ void UpdateEdgeCaps() if (m_FromCap != null) { Vector2 size = m_FromCap.layout.size; - m_FromCap.layout = new Rect(parent.ChangeCoordinatesTo(this, m_From) - (size / 2), size); + if ((size.x > 0) && (size.y > 0)) + m_FromCap.layout = new Rect(parent.ChangeCoordinatesTo(this, m_From) - (size / 2), size); } if (m_ToCap != null) { Vector2 size = m_ToCap.layout.size; - m_ToCap.layout = new Rect(parent.ChangeCoordinatesTo(this, m_To) - (size / 2), size); + if ((size.x > 0) && (size.y > 0)) + m_ToCap.layout = new Rect(parent.ChangeCoordinatesTo(this, m_To) - (size / 2), size); } } internal override void DoRepaint(IStylePainter painter) { UnityEngine.Profiling.Profiler.BeginSample("DrawEdge"); - UpdateEdgeCaps(); // Edges do NOT call base.DoRepaint. It would create a visual artifact. DrawEdge(painter); @@ -415,12 +416,13 @@ static bool Approximately(Vector2 v1, Vector2 v2) public virtual void UpdateLayout() { if (parent == null) return; - if (m_ControlPointsDirty == false) return; - - - ComputeControlPoints(); // Computes the control points in parent ( graph ) coordinates - ComputeLayout(); // Update the element layout based on the control points. - m_ControlPointsDirty = false; + if (m_ControlPointsDirty) + { + ComputeControlPoints(); // Computes the control points in parent ( graph ) coordinates + ComputeLayout(); // Update the element layout based on the control points. + m_ControlPointsDirty = false; + } + UpdateEdgeCaps(); } private List lastLocalControlPoints = new List(); diff --git a/Modules/GraphViewEditor/Elements/Blackboard/BlackboardField.cs b/Modules/GraphViewEditor/Elements/Blackboard/BlackboardField.cs index f29dd66664..978464f20d 100644 --- a/Modules/GraphViewEditor/Elements/Blackboard/BlackboardField.cs +++ b/Modules/GraphViewEditor/Elements/Blackboard/BlackboardField.cs @@ -89,7 +89,8 @@ protected internal override void ExecuteDefaultAction(EventBase evt) if (evt.eventTypeId == AttachToPanelEvent.TypeId()) { var graphView = GetFirstAncestorOfType(); - graphView.RestorePersitentSelectionForElement(this); + if (graphView != null) + graphView.RestorePersitentSelectionForElement(this); } } diff --git a/Modules/GraphViewEditor/Elements/Edge.cs b/Modules/GraphViewEditor/Elements/Edge.cs index 6c75cd5fc0..64e2676f7d 100644 --- a/Modules/GraphViewEditor/Elements/Edge.cs +++ b/Modules/GraphViewEditor/Elements/Edge.cs @@ -356,8 +356,8 @@ void DoTrackGraphElement(Port port) current = current.hierarchy.parent; } - - port.node.RegisterCallback(OnGeometryChanged); + if (port.node != null) + port.node.RegisterCallback(OnGeometryChanged); } void DoUntrackGraphElement(Port port) @@ -378,7 +378,8 @@ void DoUntrackGraphElement(Port port) current = current.hierarchy.parent; } - port.node.UnregisterCallback(OnGeometryChanged); + if (port.node != null) + port.node.UnregisterCallback(OnGeometryChanged); } private void OnPortGeometryChanged(GeometryChangedEvent evt) diff --git a/Modules/GraphViewEditor/Elements/StackNode.cs b/Modules/GraphViewEditor/Elements/StackNode.cs index 6b5e01e77a..77d3eff9e9 100644 --- a/Modules/GraphViewEditor/Elements/StackNode.cs +++ b/Modules/GraphViewEditor/Elements/StackNode.cs @@ -65,10 +65,13 @@ protected internal override void ExecuteDefaultAction(EventBase evt) { graphView = GetFirstAncestorOfType(); - // Restore selections on children. - foreach (var child in Children().OfType()) + if (graphView != null) { - graphView.RestorePersitentSelectionForElement(child); + // Restore selections on children. + foreach (var child in Children().OfType()) + { + graphView.RestorePersitentSelectionForElement(child); + } } } } diff --git a/Modules/GraphViewEditor/ExperimentalNamespaceRelic.cs b/Modules/GraphViewEditor/ExperimentalNamespaceRelic.cs new file mode 100644 index 0000000000..6a417bff61 --- /dev/null +++ b/Modules/GraphViewEditor/ExperimentalNamespaceRelic.cs @@ -0,0 +1,10 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEditor.Experimental.UIElements.GraphView +{ + // We cannot delete the whole namespace just yet as there are left-over using statement in some packages + // However expect this using statement no visible types exist anymore + internal class Empty {} +} diff --git a/Modules/GraphViewEditor/ExperimentalUIElements/Capabilities.cs b/Modules/GraphViewEditor/ExperimentalUIElements/Capabilities.cs deleted file mode 100644 index 2fd3b7da0a..0000000000 --- a/Modules/GraphViewEditor/ExperimentalUIElements/Capabilities.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; - -namespace UnityEditor.Experimental.UIElements.GraphView -{ - [Flags] - public enum Capabilities - { - Selectable = 1 << 0, - Collapsible = 1 << 1, - Resizable = 1 << 2, - Movable = 1 << 3, - Deletable = 1 << 4, - Droppable = 1 << 5, - Ascendable = 1 << 6, - Renamable = 1 << 7, - } -} diff --git a/Modules/GraphViewEditor/ExperimentalUIElements/Decorators/GridBackground.cs b/Modules/GraphViewEditor/ExperimentalUIElements/Decorators/GridBackground.cs deleted file mode 100644 index c7df705cc0..0000000000 --- a/Modules/GraphViewEditor/ExperimentalUIElements/Decorators/GridBackground.cs +++ /dev/null @@ -1,235 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine; -using UnityEngine.Experimental.UIElements; -using UnityEngine.Experimental.UIElements.StyleSheets; - -namespace UnityEditor.Experimental.UIElements.GraphView -{ - public class GridBackground : VisualElement - { - const string k_SpacingProperty = "spacing"; - const string k_ThickLinesProperty = "thick-lines"; - const string k_LineColorProperty = "line-color"; - const string k_ThickLineColorProperty = "thick-line-color"; - const string k_GridBackgroundColorProperty = "grid-background-color"; - - StyleValue m_Spacing; - float spacing - { - get - { - return m_Spacing.GetSpecifiedValueOrDefault(50.0f); - } - } - - StyleValue m_ThickLines; - int thickLines - { - get - { - return m_ThickLines.GetSpecifiedValueOrDefault(10); - } - } - - StyleValue m_LineColor; - Color lineColor - { - get - { - return m_LineColor.GetSpecifiedValueOrDefault(new Color(0f, 0f, 0f, 0.18f)); - } - } - - StyleValue m_ThickLineColor; - Color thickLineColor - { - get - { - return m_ThickLineColor.GetSpecifiedValueOrDefault(new Color(0f, 0f, 0f, 0.38f)); - } - } - - StyleValue m_GridBackgroundColor; - Color gridBackgroundColor - { - get - { - return m_GridBackgroundColor.GetSpecifiedValueOrDefault(new Color(0.17f, 0.17f, 0.17f, 1.0f)); - } - } - - private VisualElement m_Container; - - public GridBackground() - { - pickingMode = PickingMode.Ignore; - - this.StretchToParentSize(); - } - - private Vector3 Clip(Rect clipRect, Vector3 _in) - { - if (_in.x < clipRect.xMin) - _in.x = clipRect.xMin; - if (_in.x > clipRect.xMax) - _in.x = clipRect.xMax; - - if (_in.y < clipRect.yMin) - _in.y = clipRect.yMin; - if (_in.y > clipRect.yMax) - _in.y = clipRect.yMax; - - return _in; - } - - protected override void OnStyleResolved(ICustomStyle elementStyle) - { - base.OnStyleResolved(elementStyle); - elementStyle.ApplyCustomProperty(k_SpacingProperty, ref m_Spacing); - elementStyle.ApplyCustomProperty(k_ThickLinesProperty, ref m_ThickLines); - elementStyle.ApplyCustomProperty(k_ThickLineColorProperty, ref m_ThickLineColor); - elementStyle.ApplyCustomProperty(k_LineColorProperty, ref m_LineColor); - elementStyle.ApplyCustomProperty(k_GridBackgroundColorProperty, ref m_GridBackgroundColor); - } - - protected override void DoRepaint(IStylePainter painter) - { - var stylePainter = (IStylePainterInternal)painter; - stylePainter.DrawImmediate(Draw); - } - - void Draw() - { - VisualElement target = parent; - - var graphView = target as GraphView; - if (graphView == null) - { - throw new InvalidOperationException("GridBackground can only be added to a GraphView"); - } - m_Container = graphView.contentViewContainer; - Rect clientRect = graphView.layout; - - // Since we're always stretch to parent size, we will use (0,0) as (x,y) coordinates - clientRect.x = 0; - clientRect.y = 0; - - var containerScale = new Vector3(m_Container.transform.matrix.GetColumn(0).magnitude, - m_Container.transform.matrix.GetColumn(1).magnitude, - m_Container.transform.matrix.GetColumn(2).magnitude); - var containerTranslation = m_Container.transform.matrix.GetColumn(3); - var containerPosition = m_Container.layout; - - // background - HandleUtility.ApplyWireMaterial(); - - GL.Begin(GL.QUADS); - GL.Color(gridBackgroundColor); - GL.Vertex(new Vector3(clientRect.x, clientRect.y)); - GL.Vertex(new Vector3(clientRect.xMax, clientRect.y)); - GL.Vertex(new Vector3(clientRect.xMax, clientRect.yMax)); - GL.Vertex(new Vector3(clientRect.x, clientRect.yMax)); - GL.End(); - - // vertical lines - Vector3 from = new Vector3(clientRect.x, clientRect.y, 0.0f); - Vector3 to = new Vector3(clientRect.x, clientRect.height, 0.0f); - - var tx = Matrix4x4.TRS(containerTranslation, Quaternion.identity, Vector3.one); - - from = tx.MultiplyPoint(from); - to = tx.MultiplyPoint(to); - - from.x += (containerPosition.x * containerScale.x); - from.y += (containerPosition.y * containerScale.y); - to.x += (containerPosition.x * containerScale.x); - to.y += (containerPosition.y * containerScale.y); - - Handles.DrawWireDisc(from, new Vector3(0.0f, 0.0f, -1.0f), 6f); - - float thickGridLineX = from.x; - float thickGridLineY = from.y; - - // Update from/to to start at beginning of clientRect - from.x = (from.x % (spacing * (containerScale.x)) - (spacing * (containerScale.x))); - to.x = from.x; - - from.y = clientRect.y; - to.y = clientRect.y + clientRect.height; - - while (from.x < clientRect.width) - { - from.x += spacing * containerScale.x; - to.x += spacing * containerScale.x; - - GL.Begin(GL.LINES); - GL.Color(lineColor); - GL.Vertex(Clip(clientRect, from)); - GL.Vertex(Clip(clientRect, to)); - GL.End(); - } - - float thickLineSpacing = (spacing * thickLines); - from.x = to.x = (thickGridLineX % (thickLineSpacing * (containerScale.x)) - (thickLineSpacing * (containerScale.x))); - - while (from.x < clientRect.width + thickLineSpacing) - { - GL.Begin(GL.LINES); - GL.Color(thickLineColor); - GL.Vertex(Clip(clientRect, from)); - GL.Vertex(Clip(clientRect, to)); - GL.End(); - - from.x += (spacing * containerScale.x * thickLines); - to.x += (spacing * containerScale.x * thickLines); - } - - // horizontal lines - from = new Vector3(clientRect.x, clientRect.y, 0.0f); - to = new Vector3(clientRect.x + clientRect.width, clientRect.y, 0.0f); - - from.x += (containerPosition.x * containerScale.x); - from.y += (containerPosition.y * containerScale.y); - to.x += (containerPosition.x * containerScale.x); - to.y += (containerPosition.y * containerScale.y); - - from = tx.MultiplyPoint(from); - to = tx.MultiplyPoint(to); - - from.y = to.y = (from.y % (spacing * (containerScale.y)) - (spacing * (containerScale.y))); - from.x = clientRect.x; - to.x = clientRect.width; - - while (from.y < clientRect.height) - { - from.y += spacing * containerScale.y; - to.y += spacing * containerScale.y; - - GL.Begin(GL.LINES); - GL.Color(lineColor); - GL.Vertex(Clip(clientRect, from)); - GL.Vertex(Clip(clientRect, to)); - GL.End(); - } - - thickLineSpacing = spacing * thickLines; - from.y = to.y = (thickGridLineY % (thickLineSpacing * (containerScale.y)) - (thickLineSpacing * (containerScale.y))); - - while (from.y < clientRect.height + thickLineSpacing) - { - GL.Begin(GL.LINES); - GL.Color(thickLineColor); - GL.Vertex(Clip(clientRect, from)); - GL.Vertex(Clip(clientRect, to)); - GL.End(); - - from.y += spacing * containerScale.y * thickLines; - to.y += spacing * containerScale.y * thickLines; - } - } - } -} diff --git a/Modules/GraphViewEditor/ExperimentalUIElements/EdgeControl.cs b/Modules/GraphViewEditor/ExperimentalUIElements/EdgeControl.cs deleted file mode 100644 index 8238e220c7..0000000000 --- a/Modules/GraphViewEditor/ExperimentalUIElements/EdgeControl.cs +++ /dev/null @@ -1,993 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine; -using UnityEngine.Experimental.UIElements; -using System.Collections.Generic; -using UnityEngine.Profiling; - -namespace UnityEditor.Experimental.UIElements.GraphView -{ - public class EdgeControl : VisualElement - { - private struct EdgeCornerSweepValues - { - public Vector2 circleCenter; - public double sweepAngle; - public double startAngle; - public double endAngle; - public Vector2 crossPoint1; - public Vector2 crossPoint2; - public float radius; - } - - private VisualElement m_FromCap; - private VisualElement m_ToCap; - private GraphView m_GraphView; - - private static Stack capPool = new Stack(); - - private static VisualElement GetCap() - { - VisualElement result = null; - if (capPool.Count > 0) - { - result = capPool.Pop(); - } - else - { - result = new VisualElement(); - result.AddToClassList("edgeCap"); - } - - return result; - } - - private static void RecycleCap(VisualElement cap) - { - capPool.Push(cap); - } - - public EdgeControl() - { - RegisterCallback(OnLeavePanel); - - m_FromCap = null; - m_ToCap = null; - - pickingMode = PickingMode.Ignore; - } - - private bool m_ControlPointsDirty = true; - private bool m_RenderPointsDirty = true; - private bool m_MeshDirty = true; - - Mesh m_Mesh; - public const float k_MinEdgeWidth = 1.75f; - - private const float k_EdgeLengthFromPort = 12.0f; - private const float k_EdgeTurnDiameter = 16.0f; - private const float k_EdgeSweepResampleRatio = 4.0f; - private const int k_EdgeStraightLineSegmentDivisor = 5; - - private Orientation m_InputOrientation; - public Orientation inputOrientation - { - get { return m_InputOrientation; } - set - { - if (m_InputOrientation == value) - return; - m_InputOrientation = value; - MarkDirtyRepaint(); - } - } - - private Orientation m_OutputOrientation; - public Orientation outputOrientation - { - get { return m_OutputOrientation; } - set - { - if (m_OutputOrientation == value) - return; - m_OutputOrientation = value; - MarkDirtyRepaint(); - } - } - - [Obsolete("Use inputColor and/or outputColor")] - public Color edgeColor - { - get { return m_InputColor; } - set - { - if (m_InputColor == value && m_OutputColor == value) - return; - m_InputColor = value; - m_OutputColor = value; - MarkDirtyRepaint(); - } - } - - Color m_InputColor = Color.grey; - public Color inputColor - { - get { return m_InputColor; } - set - { - if (m_InputColor != value) - { - m_InputColor = value; - MarkDirtyRepaint(); - } - } - } - - Color m_OutputColor = Color.grey; - public Color outputColor - { - get { return m_OutputColor; } - set - { - if (m_OutputColor != value) - { - m_OutputColor = value; - MarkDirtyRepaint(); - } - } - } - - private Color m_FromCapColor; - public Color fromCapColor - { - get { return m_FromCapColor; } - set - { - if (m_FromCapColor == value) - return; - m_FromCapColor = value; - - if (m_FromCap != null) - { - m_FromCap.style.backgroundColor = m_FromCapColor; - } - } - } - - private Color m_ToCapColor; - public Color toCapColor - { - get { return m_ToCapColor; } - set - { - if (m_ToCapColor == value) - return; - m_ToCapColor = value; - - if (m_ToCap != null) - { - m_ToCap.style.backgroundColor = m_ToCapColor; - } - } - } - - private float m_CapRadius = 5; - public float capRadius - { - get { return m_CapRadius; } - set - { - if (m_CapRadius == value) - return; - m_CapRadius = value; - MarkDirtyRepaint(); - } - } - - private int m_EdgeWidth = 2; - public int edgeWidth - { - get { return m_EdgeWidth; } - set - { - if (m_EdgeWidth == value) - return; - m_EdgeWidth = value; - m_MeshDirty = true; - UpdateLayout(); // The layout depends on the edges width - MarkDirtyRepaint(); - } - } - - private float m_InterceptWidth = 5; - public float interceptWidth - { - get { return m_InterceptWidth; } - set { m_InterceptWidth = value; } - } - - // The start of the edge in graph coordinates. - private Vector2 m_From; - public Vector2 from - { - get { return m_From; } - set - { - if ((m_From - value).sqrMagnitude > 0.25f) - { - m_From = value; - PointsChanged(); - } - } - } - - // The end of the edge in graph coordinates. - private Vector2 m_To; - public Vector2 to - { - get { return m_To; } - set - { - if ((m_To - value).sqrMagnitude > 0.25f) - { - m_To = value; - PointsChanged(); - } - } - } - - // The control points in graph coordinates. - private Vector2[] m_ControlPoints; - public Vector2[] controlPoints - { - get - { - return m_ControlPoints; - } - } - - - public bool drawFromCap - { - get { return m_FromCap != null; } - set - { - if (!value) - { - if (m_FromCap != null) - { - m_FromCap.RemoveFromHierarchy(); - RecycleCap(m_FromCap); - m_FromCap = null; - } - } - else - { - if (m_FromCap == null) - { - m_FromCap = GetCap(); - m_FromCap.style.backgroundColor = m_FromCapColor; - Add(m_FromCap); - } - } - } - } - - public bool drawToCap - { - get { return m_ToCap != null; } - set - { - if (!value) - { - if (m_ToCap != null) - { - m_ToCap.RemoveFromHierarchy(); - RecycleCap(m_ToCap); - m_ToCap = null; - } - } - else - { - if (m_ToCap == null) - { - m_ToCap = GetCap(); - m_ToCap.style.backgroundColor = m_ToCapColor; - Add(m_ToCap); - } - } - } - } - - void UpdateEdgeCaps() - { - if (m_FromCap != null) - { - Vector2 size = m_FromCap.layout.size; - m_FromCap.layout = new Rect(parent.ChangeCoordinatesTo(this, m_From) - (size / 2), size); - } - if (m_ToCap != null) - { - Vector2 size = m_ToCap.layout.size; - m_ToCap.layout = new Rect(parent.ChangeCoordinatesTo(this, m_To) - (size / 2), size); - } - } - - protected override void DoRepaint(IStylePainter painter) - { - UnityEngine.Profiling.Profiler.BeginSample("DrawEdge"); - UpdateEdgeCaps(); - // Edges do NOT call base.DoRepaint. It would create a visual artifact. - DrawEdge(painter); - - UnityEngine.Profiling.Profiler.EndSample(); - } - - public override bool ContainsPoint(Vector2 localPoint) - { - Profiler.BeginSample("EdgeControl.ContainsPoint"); - - if (!base.ContainsPoint(localPoint)) - { - Profiler.EndSample(); - return false; - } - - // bounding box check succeeded, do more fine grained check by measuring distance to bezier points - // exclude endpoints - - float capMaxDist = 4 * capRadius * capRadius; //(2 * CapRadius)^2 - - if ((from - localPoint).sqrMagnitude <= capMaxDist || - (to - localPoint).sqrMagnitude <= capMaxDist) - { - Profiler.EndSample(); - return false; - } - - var allPoints = m_RenderPoints; - - if (allPoints.Count > 0) - { - //we use squareDistance to avoid sqrts - float distance = (allPoints[0] - localPoint).sqrMagnitude; - for (var i = 0; i < allPoints.Count - 1; i++) - { - Vector2 currentPoint = allPoints[i]; - Vector2 nextPoint = allPoints[i + 1]; - - float distanceNext = (nextPoint - localPoint).sqrMagnitude; - float distanceLine = (currentPoint - nextPoint).sqrMagnitude; - if (distance < distanceLine && distanceNext < distanceLine - ) // the point is somewhere between the two points - { - //https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line - if (Mathf.Abs((nextPoint.y - currentPoint.y) * localPoint.x - - (nextPoint.x - currentPoint.x) * localPoint.y + nextPoint.x * currentPoint.y - - nextPoint.y * currentPoint.x) / Mathf.Sqrt(distanceLine) < interceptWidth) - { - Profiler.EndSample(); - return true; - } - } - - distance = distanceNext; - } - } - - Profiler.EndSample(); - return false; - } - - public override bool Overlaps(Rect rect) - { - if (base.Overlaps(rect)) - { - for (int a = 0; a < m_RenderPoints.Count - 1; a++) - { - if (RectUtils.IntersectsSegment(rect, m_RenderPoints[a], m_RenderPoints[a + 1])) - return true; - } - } - - return false; - } - - protected virtual void PointsChanged() - { - m_ControlPointsDirty = true; - MarkDirtyRepaint(); - } - - // The points that will be rendered. Expressed in coordinates local to the element. - List m_RenderPoints = new List(); - - static bool Approximately(Vector2 v1, Vector2 v2) - { - return Mathf.Approximately(v1.x, v2.x) && Mathf.Approximately(v1.y, v2.y); - } - - public virtual void UpdateLayout() - { - if (parent == null) return; - if (m_ControlPointsDirty == false) return; - - - ComputeControlPoints(); // Computes the control points in parent ( graph ) coordinates - ComputeLayout(); // Update the element layout based on the control points. - m_ControlPointsDirty = false; - } - - private List lastLocalControlPoints = new List(); - - void RenderStraightLines(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4) - { - float safeSpan = outputOrientation == Orientation.Horizontal - ? Mathf.Abs((p1.x + k_EdgeLengthFromPort) - (p4.x - k_EdgeLengthFromPort)) - : Mathf.Abs((p1.y + k_EdgeLengthFromPort) - (p4.y - k_EdgeLengthFromPort)); - - float safeSpan3 = safeSpan / k_EdgeStraightLineSegmentDivisor; - float nodeToP2Dist = Mathf.Min(safeSpan3, k_EdgeTurnDiameter); - nodeToP2Dist = Mathf.Max(0, nodeToP2Dist); - - var offset = outputOrientation == Orientation.Horizontal - ? new Vector2(k_EdgeTurnDiameter - nodeToP2Dist, 0) - : new Vector2(0, k_EdgeTurnDiameter - nodeToP2Dist); - - m_RenderPoints.Add(p1); - m_RenderPoints.Add(p2 - offset); - m_RenderPoints.Add(p3 + offset); - m_RenderPoints.Add(p4); - } - - protected virtual void UpdateRenderPoints() - { - ComputeControlPoints(); // This should have been updated before : make sure anyway. - - if (m_RenderPointsDirty == false && m_ControlPoints != null) - { - return; - } - - Vector2 p1 = parent.ChangeCoordinatesTo(this, m_ControlPoints[0]); - Vector2 p2 = parent.ChangeCoordinatesTo(this, m_ControlPoints[1]); - Vector2 p3 = parent.ChangeCoordinatesTo(this, m_ControlPoints[2]); - Vector2 p4 = parent.ChangeCoordinatesTo(this, m_ControlPoints[3]); - - // Only compute this when the "local" points have actually changed - if (lastLocalControlPoints.Count == 4) - { - if (Approximately(p1, lastLocalControlPoints[0]) && - Approximately(p2, lastLocalControlPoints[1]) && - Approximately(p3, lastLocalControlPoints[2]) && - Approximately(p4, lastLocalControlPoints[3])) - { - m_RenderPointsDirty = false; - return; - } - } - - Profiler.BeginSample("EdgeControl.UpdateRenderPoints"); - lastLocalControlPoints.Clear(); - lastLocalControlPoints.Add(p1); - lastLocalControlPoints.Add(p2); - lastLocalControlPoints.Add(p3); - lastLocalControlPoints.Add(p4); - m_RenderPointsDirty = false; - m_MeshDirty = true; - - m_RenderPoints.Clear(); - - float diameter = k_EdgeTurnDiameter; - - // We have to handle a special case of the edge when it is a straight line, but not - // when going backwards in space (where the start point is in front in y to the end point). - // We do this by turning the line into 3 linear segments with no curves. This also - // avoids possible NANs in later angle calculations. - bool sameOrientations = outputOrientation == inputOrientation; - if (sameOrientations && - ((outputOrientation == Orientation.Horizontal && Mathf.Abs(p1.y - p4.y) < 2 && p1.x + k_EdgeLengthFromPort < p4.x - k_EdgeLengthFromPort) || - (outputOrientation == Orientation.Vertical && Mathf.Abs(p1.x - p4.x) < 2 && p1.y + k_EdgeLengthFromPort < p4.y - k_EdgeLengthFromPort))) - { - RenderStraightLines(p1, p2, p3, p4); - Profiler.EndSample(); - return; - } - - bool renderBothCorners = true; - - EdgeCornerSweepValues corner1 = GetCornerSweepValues(p1, p2, p3, diameter, Direction.Output); - EdgeCornerSweepValues corner2 = GetCornerSweepValues(p2, p3, p4, diameter, Direction.Input); - - if (!ValidateCornerSweepValues(ref corner1, ref corner2)) - { - if (sameOrientations) - { - RenderStraightLines(p1, p2, p3, p4); - Profiler.EndSample(); - return; - } - - renderBothCorners = false; - - //we try to do it with a single corner instead - Vector2 px = (outputOrientation == Orientation.Horizontal) ? new Vector2(p4.x, p1.y) : new Vector2(p1.x, p4.y); - - corner1 = GetCornerSweepValues(p1, px, p4, diameter, Direction.Output); - } - - m_RenderPoints.Add(p1); - - if (!sameOrientations && renderBothCorners) - { - //if the 2 corners or endpoints are too close, the corner sweep angle calculations can't handle different orientations - float minDistance = 2 * diameter * diameter; - if ((p3 - p2).sqrMagnitude < minDistance || - (p4 - p1).sqrMagnitude < minDistance) - { - Vector2 px = (p2 + p3) * 0.5f; - corner1 = GetCornerSweepValues(p1, px, p4, diameter, Direction.Output); - renderBothCorners = false; - } - } - - GetRoundedCornerPoints(m_RenderPoints, corner1, Direction.Output); - if (renderBothCorners) - GetRoundedCornerPoints(m_RenderPoints, corner2, Direction.Input); - - m_RenderPoints.Add(p4); - Profiler.EndSample(); - } - - private bool ValidateCornerSweepValues(ref EdgeCornerSweepValues corner1, ref EdgeCornerSweepValues corner2) - { - // Get the midpoint between the two corner circle centers. - Vector2 circlesMidpoint = (corner1.circleCenter + corner2.circleCenter) / 2; - - // Find the angle to the corner circles midpoint so we can compare it to the sweep angles of each corner. - Vector2 p2CenterToCross1 = corner1.circleCenter - corner1.crossPoint1; - Vector2 p2CenterToCirclesMid = corner1.circleCenter - circlesMidpoint; - double angleToCirclesMid = outputOrientation == Orientation.Horizontal - ? Math.Atan2(p2CenterToCross1.y, p2CenterToCross1.x) - Math.Atan2(p2CenterToCirclesMid.y, p2CenterToCirclesMid.x) - : Math.Atan2(p2CenterToCross1.x, p2CenterToCross1.y) - Math.Atan2(p2CenterToCirclesMid.x, p2CenterToCirclesMid.y); - - if (double.IsNaN(angleToCirclesMid)) - return false; - - // We need the angle to the circles midpoint to match the turn direction of the first corner's sweep angle. - angleToCirclesMid = Math.Sign(angleToCirclesMid) * 2 * Mathf.PI - angleToCirclesMid; - if (Mathf.Abs((float)angleToCirclesMid) > 1.5 * Mathf.PI) - angleToCirclesMid = -1 * Math.Sign(angleToCirclesMid) * 2 * Mathf.PI + angleToCirclesMid; - - // Calculate the maximum sweep angle so that both corner sweeps and with the tangents of the 2 circles meeting each other. - float h = p2CenterToCirclesMid.magnitude; - float p2AngleToMidTangent = Mathf.Acos(corner1.radius / h); - - if (double.IsNaN(p2AngleToMidTangent)) - return false; - - float maxSweepAngle = Mathf.Abs((float)corner1.sweepAngle) - p2AngleToMidTangent * 2; - - // If the angle to the circles midpoint is within the sweep angle, we need to apply our maximum sweep angle - // calculated above, otherwise the maximum sweep angle is irrelevant. - if (Mathf.Abs((float)angleToCirclesMid) < Mathf.Abs((float)corner1.sweepAngle)) - { - corner1.sweepAngle = Math.Sign(corner1.sweepAngle) * Mathf.Min(maxSweepAngle, Mathf.Abs((float)corner1.sweepAngle)); - corner2.sweepAngle = Math.Sign(corner2.sweepAngle) * Mathf.Min(maxSweepAngle, Mathf.Abs((float)corner2.sweepAngle)); - } - - return true; - } - - private EdgeCornerSweepValues GetCornerSweepValues( - Vector2 p1, Vector2 cornerPoint, Vector2 p2, float diameter, Direction closestPortDirection) - { - EdgeCornerSweepValues corner = new EdgeCornerSweepValues(); - - // Calculate initial radius. This radius can change depending on the sharpness of the corner. - corner.radius = diameter / 2; - - // Calculate vectors from p1 to cornerPoint. - Vector2 d1Corner = (cornerPoint - p1).normalized; - Vector2 d1 = d1Corner * diameter; - float dx1 = d1.x; - float dy1 = d1.y; - - // Calculate vectors from p2 to cornerPoint. - Vector2 d2Corner = (cornerPoint - p2).normalized; - Vector2 d2 = d2Corner * diameter; - float dx2 = d2.x; - float dy2 = d2.y; - - // Calculate the angle of the corner (divided by 2). - float angle = (float)(Math.Atan2(dy1, dx1) - Math.Atan2(dy2, dx2)) / 2; - - // Calculate the length of the segment between the cornerPoint and where - // the corner circle with given radius meets the line. - float tan = (float)Math.Abs(Math.Tan(angle)); - float segment = corner.radius / tan; - - // If the segment is larger than the diameter, we need to cap the segment - // to the diameter and reduce the radius to match the segment. This is what - // makes the corner turn radii get smaller as the edge corners get tighter. - if (segment > diameter) - { - segment = diameter; - corner.radius = diameter * tan; - } - - // Calculate both cross points (where the circle touches the p1-cornerPoint line - // and the p2-cornerPoint line). - corner.crossPoint1 = cornerPoint - (d1Corner * segment); - corner.crossPoint2 = cornerPoint - (d2Corner * segment); - - // Calculation of the coordinates of the circle center. - corner.circleCenter = GetCornerCircleCenter(cornerPoint, corner.crossPoint1, corner.crossPoint2, segment, corner.radius); - - // Calculate the starting and ending angles. - corner.startAngle = Math.Atan2(corner.crossPoint1.y - corner.circleCenter.y, corner.crossPoint1.x - corner.circleCenter.x); - corner.endAngle = Math.Atan2(corner.crossPoint2.y - corner.circleCenter.y, corner.crossPoint2.x - corner.circleCenter.x); - - // Get the full sweep angle from the starting and ending angles. - corner.sweepAngle = corner.endAngle - corner.startAngle; - - // If we are computing the second corner (into the input port), we want to start - // the sweep going backwards. - if (closestPortDirection == Direction.Input) - { - double endAngle = corner.endAngle; - corner.endAngle = corner.startAngle; - corner.startAngle = endAngle; - } - - // Validate the sweep angle so it turns into the correct direction. - if (corner.sweepAngle > Math.PI) - corner.sweepAngle = -2 * Math.PI + corner.sweepAngle; - else if (corner.sweepAngle < -Math.PI) - corner.sweepAngle = 2 * Math.PI + corner.sweepAngle; - - return corner; - } - - private Vector2 GetCornerCircleCenter(Vector2 cornerPoint, Vector2 crossPoint1, Vector2 crossPoint2, float segment, float radius) - { - float dx = cornerPoint.x * 2 - crossPoint1.x - crossPoint2.x; - float dy = cornerPoint.y * 2 - crossPoint1.y - crossPoint2.y; - - var cornerToCenterVector = new Vector2(dx, dy); - - float L = cornerToCenterVector.magnitude; - - if (Mathf.Approximately(L, 0)) - { - return cornerPoint; - } - - float d = new Vector2(segment, radius).magnitude; - float factor = d / L; - - return new Vector2(cornerPoint.x - cornerToCenterVector.x * factor, cornerPoint.y - cornerToCenterVector.y * factor); - } - - private void GetRoundedCornerPoints(List points, EdgeCornerSweepValues corner, Direction closestPortDirection) - { - // Calculate the number of points that will sample the arc from the sweep angle. - int pointsCount = Mathf.CeilToInt((float)Math.Abs(corner.sweepAngle * k_EdgeSweepResampleRatio)); - int sign = Math.Sign(corner.sweepAngle); - bool backwards = (closestPortDirection == Direction.Input); - - for (int i = 0; i < pointsCount; ++i) - { - // If we are computing the second corner (into the input port), the sweep is going backwards - // but we still need to add the points to the list in the correct order. - float sweepIndex = backwards ? i - pointsCount : i; - - double sweepedAngle = corner.startAngle + sign * sweepIndex / k_EdgeSweepResampleRatio; - - var pointX = (float)(corner.circleCenter.x + Math.Cos(sweepedAngle) * corner.radius); - var pointY = (float)(corner.circleCenter.y + Math.Sin(sweepedAngle) * corner.radius); - - // Check if we overlap the previous point. If we do, we skip this point so that we - // don't cause the edge polygons to twist. - if (i == 0 && backwards) - { - if (outputOrientation == Orientation.Horizontal) - { - if (corner.sweepAngle < 0 && points[points.Count - 1].y > pointY) - continue; - else if (corner.sweepAngle >= 0 && points[points.Count - 1].y < pointY) - continue; - } - else - { - if (corner.sweepAngle < 0 && points[points.Count - 1].x < pointX) - continue; - else if (corner.sweepAngle >= 0 && points[points.Count - 1].x > pointX) - continue; - } - } - - points.Add(new Vector2(pointX, pointY)); - } - } - - private void AssignControlPoint(ref Vector2 destination, Vector2 newValue) - { - if (!Approximately(destination, newValue)) - { - destination = newValue; - m_RenderPointsDirty = true; - } - } - - protected virtual void ComputeControlPoints() - { - if (m_ControlPointsDirty == false) return; - - Profiler.BeginSample("EdgeControl.ComputeControlPoints"); - - float offset = k_EdgeLengthFromPort + k_EdgeTurnDiameter; - - // This is to ensure we don't have the edge extending - // left and right by the offset right when the `from` - // and `to` are on top of each other. - float fromToDistance = (to - from).magnitude; - offset = Mathf.Min(offset, fromToDistance * 2); - offset = Mathf.Max(offset, k_EdgeTurnDiameter); - - if (m_ControlPoints == null || m_ControlPoints.Length != 4) - m_ControlPoints = new Vector2[4]; - - AssignControlPoint(ref m_ControlPoints[0], from); - - if (outputOrientation == Orientation.Horizontal) - AssignControlPoint(ref m_ControlPoints[1], new Vector2(from.x + offset, from.y)); - else - AssignControlPoint(ref m_ControlPoints[1], new Vector2(from.x, from.y + offset)); - - if (inputOrientation == Orientation.Horizontal) - AssignControlPoint(ref m_ControlPoints[2], new Vector2(to.x - offset, to.y)); - else - AssignControlPoint(ref m_ControlPoints[2], new Vector2(to.x, to.y - offset)); - - AssignControlPoint(ref m_ControlPoints[3], to); - Profiler.EndSample(); - } - - void ComputeLayout() - { - Profiler.BeginSample("EdgeControl.ComputeLayout"); - Vector2 to = m_ControlPoints[m_ControlPoints.Length - 1]; - Vector2 from = m_ControlPoints[0]; - - Rect rect = new Rect(Vector2.Min(to, from), new Vector2(Mathf.Abs(from.x - to.x), Mathf.Abs(from.y - to.y))); - - // Make sure any control points (including tangents, are included in the rect) - for (int i = 1; i < m_ControlPoints.Length - 1; ++i) - { - if (!rect.Contains(m_ControlPoints[i])) - { - Vector2 pt = m_ControlPoints[i]; - rect.xMin = Math.Min(rect.xMin, pt.x); - rect.yMin = Math.Min(rect.yMin, pt.y); - rect.xMax = Math.Max(rect.xMax, pt.x); - rect.yMax = Math.Max(rect.yMax, pt.y); - } - } - - if (m_GraphView == null) - { - m_GraphView = GetFirstAncestorOfType(); - } - - //Make sure that we have the place to display Edges with EdgeControl.k_MinEdgeWidth at the lowest level of zoom. - float margin = Mathf.Max(edgeWidth * 0.5f + 1, EdgeControl.k_MinEdgeWidth / m_GraphView.minScale); - - rect.xMin -= margin; - rect.yMin -= margin; - rect.width += margin * 2; - rect.height += margin * 2; - - if (layout != rect) - { - layout = rect; - m_RenderPointsDirty = true; - } - Profiler.EndSample(); - } - - static Material s_LineMat; - - static Material lineMat - { - get - { - if (s_LineMat == null) - s_LineMat = new Material(EditorGUIUtility.LoadRequired("GraphView/AAEdge.shader") as Shader); - return s_LineMat; - } - } - - protected virtual void DrawEdge(IStylePainter painter) - { - var stylePainter = (IStylePainterInternal)painter; - stylePainter.DrawImmediate(Draw); - } - - void Draw() - { - if (edgeWidth <= 0) - return; - - UpdateRenderPoints(); - - Vector2[] points = controlPoints; - - Color inputColor = this.inputColor; - Color outputColor = this.outputColor; - - float realWidth = edgeWidth; - if (realWidth * m_GraphView.scale < k_MinEdgeWidth) - { - realWidth = k_MinEdgeWidth / m_GraphView.scale; - - // make up for bigger edge by fading it. - inputColor.a = outputColor.a = edgeWidth / realWidth; - } - - if (m_MeshDirty || m_Mesh == null) - { - m_MeshDirty = false; - - RecomputeMesh(); - } - - // Send the view zoom factor so that the antialias width do not grow when zooming in. - lineMat.SetFloat("_ZoomFactor", m_GraphView.scale * realWidth / edgeWidth * EditorGUIUtility.pixelsPerPoint); - - // Send the view zoom correction so that the vertex shader can scale the edge triangles when below m_MinWidth. - lineMat.SetFloat("_ZoomCorrection", realWidth / edgeWidth); - - lineMat.SetColor("_InputColor", (QualitySettings.activeColorSpace == ColorSpace.Linear) ? inputColor.gamma : inputColor); - lineMat.SetColor("_OutputColor", (QualitySettings.activeColorSpace == ColorSpace.Linear) ? outputColor.gamma : outputColor); - - lineMat.SetPass(0); - Graphics.DrawMeshNow(m_Mesh, Matrix4x4.identity); - } - - private void RecomputeMesh() - { - int cpt = m_RenderPoints.Count; - - float polyLineLength = 0; - - for (int i = 1; i < cpt; ++i) - { - polyLineLength += (m_RenderPoints[i - 1] - m_RenderPoints[i]).sqrMagnitude; - } - - if (m_Mesh == null) - { - m_Mesh = new Mesh(); - m_Mesh.hideFlags = HideFlags.HideAndDontSave; - } - - Vector3[] vertices = m_Mesh.vertices; - Vector2[] uvs = m_Mesh.uv; - Vector3[] normals = m_Mesh.normals; - bool newIndices = false; - int wantedLength = (cpt) * 2; - if (vertices == null || vertices.Length != wantedLength) - { - vertices = new Vector3[wantedLength]; - uvs = new Vector2[wantedLength]; - normals = new Vector3[wantedLength]; - newIndices = true; - m_Mesh.triangles = new int[] {}; - } - - float halfWidth = edgeWidth * 0.5f; - - float vertexHalfWidth = halfWidth + 2; - - float currentLength = 0; - - Vector2 unitPreviousSegment = Vector2.zero; - for (int i = 0; i < cpt; ++i) - { - Vector2 dir; - Vector2 unitNextSegment = Vector2.zero; - Vector2 nextSegment = Vector2.zero; - - if (i < cpt - 1) - { - nextSegment = (m_RenderPoints[i + 1] - m_RenderPoints[i]); - unitNextSegment = nextSegment.normalized; - } - - - if (i > 0 && i < cpt - 1) - { - dir = unitPreviousSegment + unitNextSegment; - dir.Normalize(); - } - else if (i > 0) - { - dir = unitPreviousSegment; - } - else - { - dir = unitNextSegment; - } - - Vector2 norm = new Vector3(dir.y, -dir.x, 0); - - Vector2 border = -norm * vertexHalfWidth; - - int index = i * 2; - uvs[index] = new Vector2(-vertexHalfWidth, halfWidth); - vertices[index] = m_RenderPoints[i]; - // normals store the Vector2 normal in x,y and the progress in the edge in z ( which drive the gradient ). - normals[index] = new Vector3(-border.x, -border.y, currentLength / polyLineLength); - - uvs[index + 1] = new Vector2(vertexHalfWidth, halfWidth); - vertices[index + 1] = m_RenderPoints[i]; - normals[index + 1] = new Vector3(border.x, border.y, currentLength / polyLineLength); - - if (i < cpt - 2) - { - currentLength += nextSegment.sqrMagnitude; - } - else - { - currentLength = polyLineLength; - } - - unitPreviousSegment = unitNextSegment; - } - - m_Mesh.vertices = vertices; - m_Mesh.normals = normals; - m_Mesh.uv = uvs; - - if (newIndices) - { - //fill triangle indices as it is a triangle strip - int[] indices = new int[(wantedLength - 2) * 3]; - - for (int i = 0; i < wantedLength - 2; ++i) - { - int index = i * 3; - if ((i & 0x01) == 0) - { - indices[index] = i; - indices[index + 1] = i + 1; - indices[index + 2] = i + 2; - } - else - { - indices[index] = i + 1; - indices[index + 1] = i; - indices[index + 2] = i + 2; - } - } - - m_Mesh.triangles = indices; - } - - m_Mesh.RecalculateBounds(); - } - - void OnLeavePanel(DetachFromPanelEvent e) - { - if (m_Mesh != null) - { - UnityEngine.Object.DestroyImmediate(m_Mesh); - m_Mesh = null; - } - } - } -} diff --git a/Modules/GraphViewEditor/ExperimentalUIElements/Elements/Blackboard/Blackboard.cs b/Modules/GraphViewEditor/ExperimentalUIElements/Elements/Blackboard/Blackboard.cs deleted file mode 100644 index e70e1bd9c9..0000000000 --- a/Modules/GraphViewEditor/ExperimentalUIElements/Elements/Blackboard/Blackboard.cs +++ /dev/null @@ -1,141 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Experimental.UIElements; -using UnityEngine.Experimental.UIElements.StyleEnums; - -namespace UnityEditor.Experimental.UIElements.GraphView -{ - public class Blackboard : GraphElement - { - private const int k_DefaultWidth = 200; - private const float k_DefaultHeight = 400; - private VisualElement m_MainContainer; - private VisualElement m_Root; - private Label m_TitleLabel; - private Label m_SubTitleLabel; - private ScrollView m_ScrollView; - private VisualElement m_ContentContainer; - private VisualElement m_HeaderItem; - private Button m_AddButton; - private bool m_Scrollable = true; - internal static readonly string StyleSheetPath = "StyleSheets/GraphViewExperimental/Blackboard.uss"; - - public Action addItemRequested { get; set; } - public Action moveItemRequested { get; set; } - public Action editTextRequested { get; set; } - - public override string title - { - get { return m_TitleLabel.text; } - set { m_TitleLabel.text = value; } - } - - public string subTitle - { - get { return m_SubTitleLabel.text; } - set { m_SubTitleLabel.text = value; } - } - - public override VisualElement contentContainer { get { return m_ContentContainer; } } - - public bool scrollable - { - get - { - return m_Scrollable; - } - set - { - if (m_Scrollable == value) - return; - - m_Scrollable = value; - - if (m_Scrollable) - { - if (m_ScrollView == null) - { - m_ScrollView = new ScrollView(); - } - - // Remove the sections container from the content item and add it to the scrollview - m_ContentContainer.RemoveFromHierarchy(); - m_Root.Add(m_ScrollView); - m_ScrollView.Add(m_ContentContainer); - style.positionType = PositionType.Manual; // As both the width and height can be changed by the user using a resizer - - // If the current the current geometry is invalid then set a default size - - if (layout.width == 0 || layout.height == 0) - { - layout = new Rect(layout.x, layout.y, layout.width == 0 ? k_DefaultWidth : layout.width, layout.height == 0 ? k_DefaultHeight : layout.height); - } - - AddToClassList("scrollable"); - } - else - { - if (m_ScrollView != null) - { - // Remove the sections container from the scrollview and add it to the content item - style.positionType = PositionType.Absolute; // As the height is automatically computed from the content but the width can be changed by the user using a resizer - m_ScrollView.RemoveFromHierarchy(); - m_ContentContainer.RemoveFromHierarchy(); - m_Root.Add(m_ContentContainer); - } - RemoveFromClassList("scrollable"); - } - } - } - - public Blackboard() - { - var tpl = EditorGUIUtility.Load("UXML/GraphViewExperimental/Blackboard.uxml") as VisualTreeAsset; - AddStyleSheetPath(StyleSheetPath); - - m_MainContainer = tpl.CloneTree(null); - m_MainContainer.AddToClassList("mainContainer"); - - m_Root = m_MainContainer.Q("content"); - - m_HeaderItem = m_MainContainer.Q("header"); - m_HeaderItem.AddToClassList("blackboardHeader"); - - m_AddButton = m_MainContainer.Q(name: "addButton") as Button; - m_AddButton.clickable.clicked += () => { - if (addItemRequested != null) - { - addItemRequested(this); - } - }; - - m_TitleLabel = m_MainContainer.Q