diff --git a/Editor/Mono/AssemblyInfo/AssemblyInfo.cs b/Editor/Mono/AssemblyInfo/AssemblyInfo.cs index 2682979939..2f5234fa6d 100644 --- a/Editor/Mono/AssemblyInfo/AssemblyInfo.cs +++ b/Editor/Mono/AssemblyInfo/AssemblyInfo.cs @@ -50,7 +50,6 @@ [assembly: InternalsVisibleTo("UnityEditor.WindowsStandalone.Extensions")] [assembly: InternalsVisibleTo("UnityEditor.OSXStandalone.Extensions")] [assembly: InternalsVisibleTo("UnityEditor.Lumin.Extensions")] -[assembly: InternalsVisibleTo("UnityEditor.Stadia.Extensions")] [assembly: InternalsVisibleTo("UnityEditor.GameCoreScarlett.Extensions")] [assembly: InternalsVisibleTo("UnityEditor.GameCoreXboxOne.Extensions")] [assembly: InternalsVisibleTo("UnityEditor.GameCoreCommon.Extensions")] diff --git a/Editor/Mono/AssetModificationProcessor.cs b/Editor/Mono/AssetModificationProcessor.cs index 7a58f06380..00bb9a5d37 100644 --- a/Editor/Mono/AssetModificationProcessor.cs +++ b/Editor/Mono/AssetModificationProcessor.cs @@ -390,7 +390,7 @@ static Editability GetPathEditability(string assetPath) { // read-only asset locations (e.g. shared packages) are considered not editable bool rootFolder, readOnly; - bool validPath = AssetDatabase.GetAssetFolderInfo(assetPath, out rootFolder, out readOnly); + bool validPath = AssetDatabase.TryGetAssetFolderInfo(assetPath, out rootFolder, out readOnly); if (validPath && readOnly) return Editability.Never; diff --git a/Editor/Mono/BuildPipeline/NamedBuildTarget.cs b/Editor/Mono/BuildPipeline/NamedBuildTarget.cs index d10a54e8bd..5d6e08be5e 100644 --- a/Editor/Mono/BuildPipeline/NamedBuildTarget.cs +++ b/Editor/Mono/BuildPipeline/NamedBuildTarget.cs @@ -45,6 +45,7 @@ namespace UnityEditor.Build public static readonly NamedBuildTarget XboxOne = new NamedBuildTarget("XboxOne"); public static readonly NamedBuildTarget tvOS = new NamedBuildTarget("tvOS"); public static readonly NamedBuildTarget NintendoSwitch = new NamedBuildTarget("Nintendo Switch"); + [System.Obsolete("Stadia has been removed in 2023.1")] public static readonly NamedBuildTarget Stadia = new NamedBuildTarget("Stadia"); public static readonly NamedBuildTarget LinuxHeadlessSimulation = new NamedBuildTarget("LinuxHeadlessSimulation"); [System.Obsolete("CloudRendering is deprecated, please use LinuxHeadlessSimulation (UnityUpgradable) -> LinuxHeadlessSimulation", false)] @@ -99,8 +100,6 @@ public static NamedBuildTarget FromBuildTargetGroup(BuildTargetGroup buildTarget return NamedBuildTarget.tvOS; case BuildTargetGroup.Switch: return NamedBuildTarget.NintendoSwitch; - case BuildTargetGroup.Stadia: - return NamedBuildTarget.Stadia; case BuildTargetGroup.LinuxHeadlessSimulation: return NamedBuildTarget.LinuxHeadlessSimulation; case BuildTargetGroup.EmbeddedLinux: diff --git a/Editor/Mono/BuildTarget.cs b/Editor/Mono/BuildTarget.cs index c54218c403..eed1434c7e 100644 --- a/Editor/Mono/BuildTarget.cs +++ b/Editor/Mono/BuildTarget.cs @@ -121,6 +121,7 @@ public enum BuildTarget [System.Obsolete("Lumin has been removed in 2022.2")] Lumin = 39, + [System.Obsolete("Stadia has been removed in 2023.1")] Stadia = 40, [System.Obsolete("CloudRendering is deprecated, please use LinuxHeadlessSimulation (UnityUpgradable) -> LinuxHeadlessSimulation", false)] diff --git a/Editor/Mono/BuildTargetConverter.cs b/Editor/Mono/BuildTargetConverter.cs index 1b71ce181e..7f32bd4a99 100644 --- a/Editor/Mono/BuildTargetConverter.cs +++ b/Editor/Mono/BuildTargetConverter.cs @@ -46,8 +46,6 @@ internal static class BuildTargetConverter return RuntimePlatform.GameCoreXboxSeries; case BuildTarget.GameCoreXboxOne: return RuntimePlatform.GameCoreXboxOne; - case BuildTarget.Stadia: - return RuntimePlatform.Stadia; case BuildTarget.EmbeddedLinux: return RuntimePlatform.EmbeddedLinuxArm64; case BuildTarget.QNX: diff --git a/Editor/Mono/BuildTargetGroup.cs b/Editor/Mono/BuildTargetGroup.cs index ccd4e6699c..6466bd45f0 100644 --- a/Editor/Mono/BuildTargetGroup.cs +++ b/Editor/Mono/BuildTargetGroup.cs @@ -98,6 +98,7 @@ public enum BuildTargetGroup [Obsolete("Lumin has been removed in 2022.2")] Lumin = 28, + [Obsolete("Stadia has been removed in 2023.1")] Stadia = 29, [System.Obsolete("CloudRendering is deprecated, please use LinuxHeadlessSimulation (UnityUpgradable) -> LinuxHeadlessSimulation", false)] diff --git a/Editor/Mono/Collab/Softlocks/SoftlockViewController.cs b/Editor/Mono/Collab/Softlocks/SoftlockViewController.cs index e4de3221f8..8dbac230b0 100644 --- a/Editor/Mono/Collab/Softlocks/SoftlockViewController.cs +++ b/Editor/Mono/Collab/Softlocks/SoftlockViewController.cs @@ -336,26 +336,6 @@ private static string GetDisplayCount(int count) return totalLocksText; } - // When the given 'text' exceeds the given 'width', out-of-bound characters - // are removed as well as a few more to display a trailing ellipsis. - // If 'text' does not exceed width, text is returned. - private string FitTextToWidth(string text, float width, GUIStyle style) - { - int characterCountVisible = style.GetNumCharactersThatFitWithinWidth(text, width); - if (characterCountVisible > 1 && characterCountVisible != text.Length) - { - string ellipsedText; - int characterLength = (characterCountVisible - 1); - if (!Instance.m_Cache.TryGetEllipsedNames(text, characterLength, out ellipsedText)) - { - ellipsedText = text.Substring(0, characterLength) + (" \u2026"); // 'horizontal ellipsis' (U+2026) is: ... - Instance.m_Cache.StoreEllipsedNames(text, ellipsedText, characterLength); - } - return ellipsedText; - } - return text; - } - #endregion #region GUI Content diff --git a/Editor/Mono/EditorApplication.cs b/Editor/Mono/EditorApplication.cs index 9a5e801c6b..ec5839d95d 100644 --- a/Editor/Mono/EditorApplication.cs +++ b/Editor/Mono/EditorApplication.cs @@ -344,7 +344,7 @@ internal static ApplicationTitleDescriptor GetApplicationTitleDescriptor() var desc = new ApplicationTitleDescriptor( isTemporaryProject ? PlayerSettings.productName : Path.GetFileName(Path.GetDirectoryName(Application.dataPath)), - InternalEditorUtility.GetUnityDisplayVersion(), + (Unsupported.IsSourceBuild() || Unsupported.IsDeveloperMode()) ? InternalEditorUtility.GetUnityDisplayVersion() : InternalEditorUtility.GetUnityVersionDigits(), activeSceneName, BuildPipeline.GetBuildTargetGroupDisplayName(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget)), Coverage.enabled diff --git a/Editor/Mono/EditorGUI.cs b/Editor/Mono/EditorGUI.cs index 3945a1fcf4..fc94bc6e3c 100644 --- a/Editor/Mono/EditorGUI.cs +++ b/Editor/Mono/EditorGUI.cs @@ -208,7 +208,8 @@ private enum DragCandidateState internal static SavedBool s_ShowRepaintDots = new SavedBool("ShowRepaintDots", true); - internal static readonly Regex s_HyperlinkRegex = new Regex(@"(?<=\b=')[^']*"); + internal static readonly Regex s_ATagRegex = new Regex(@"(?<=\b="")[^""]*"); + internal static readonly Regex s_LinkTagRegex = new Regex(@"(?<=\b=')[^']*"); static class Styles { @@ -1461,7 +1462,9 @@ private static bool HasClickedOnHyperlink(RecycledTextEditor editor, out Diction if (!editor.HasClickedOnLink(mousePosition, out string link)) return false; - MatchCollection matches = s_HyperlinkRegex.Matches(link); + MatchCollection matches = s_ATagRegex.Matches(link); + if (matches.Count == 0) + matches = s_LinkTagRegex.Matches(link); int endPreviousAttributeIndex = 0; // for each attribute we need to find the attribute name @@ -3906,15 +3909,8 @@ internal void SetEnumValueDelegate(object userData, string[] options, int select } } - internal static int DoPopup(Rect position, int controlID, int selected, GUIContent[] popupValues, GUIStyle style) - { - return DoPopup(position, controlID, selected, popupValues, null, style); - } - - internal static int DoPopup(Rect position, int controlID, int selected, GUIContent[] popupValues, Func checkEnabled, GUIStyle style) + internal static GUIContent GetPopupButtonContent(int selected, GUIContent[] popupValues) { - selected = PopupCallbackInfo.GetSelectedValueForControl(controlID, selected); - GUIContent buttonContent; if (showMixedValue) { @@ -3927,8 +3923,21 @@ internal static int DoPopup(Rect position, int controlID, int selected, GUIConte else { buttonContent = popupValues[selected]; + buttonContent.text = EditorUtility.ParseMenuName(popupValues[selected].text); } + return buttonContent; + } + + internal static int DoPopup(Rect position, int controlID, int selected, GUIContent[] popupValues, GUIStyle style) + { + return DoPopup(position, controlID, selected, popupValues, null, style); + } + + internal static int DoPopup(Rect position, int controlID, int selected, GUIContent[] popupValues, Func checkEnabled, GUIStyle style) + { + selected = PopupCallbackInfo.GetSelectedValueForControl(controlID, selected); + Event evt = Event.current; switch (evt.type) { @@ -3941,7 +3950,7 @@ internal static int DoPopup(Rect position, int controlID, int selected, GUIConte } BeginHandleMixedValueContentColor(); - style.Draw(position, buttonContent, controlID, false, position.Contains(Event.current.mousePosition)); + style.Draw(position, GetPopupButtonContent(selected, popupValues), controlID, false, position.Contains(Event.current.mousePosition)); EndHandleMixedValueContentColor(); style.font = originalFont; @@ -6064,7 +6073,7 @@ internal static void DoInspectorTitlebar(Rect position, int id, bool foldout, Ob } break; case EventType.Repaint: - textStyle.Draw(textRect, EditorGUIUtility.TempContent(ObjectNames.GetInspectorTitle(targetObjs[0])), hovered, pressed, foldout, hasFocus); + textStyle.Draw(textRect, EditorGUIUtility.TempContent(ObjectNames.GetInspectorTitle(targetObjs[0], targetObjs.Length > 1)), hovered, pressed, foldout, hasFocus); if (EditorGUIUtility.comparisonViewMode == EditorGUIUtility.ComparisonViewMode.None) { EditorStyles.optionsButtonStyle.Draw(settingsRect, GUIContent.none, id, foldout, settingsRect.Contains(Event.current.mousePosition)); diff --git a/Editor/Mono/EditorSettings.bindings.cs b/Editor/Mono/EditorSettings.bindings.cs index cbb847638d..e5ba1d9a2e 100644 --- a/Editor/Mono/EditorSettings.bindings.cs +++ b/Editor/Mono/EditorSettings.bindings.cs @@ -239,6 +239,7 @@ internal static extern string Internal_ProjectGenerationUserExtensions [StaticAccessor("GetEditorSettings()", StaticAccessorType.Dot)] internal static extern void SetEtcTextureCompressorDefaultBehavior(); + [Obsolete("EditorSettings.useLegacyProbeSampleCount is deprecated. The legacy method of selecting probe sample counts will be removed in a future release.", false)] [StaticAccessor("GetEditorSettings()", StaticAccessorType.Dot)] public static extern bool useLegacyProbeSampleCount { get; set; } diff --git a/Editor/Mono/GI/LightBaker.bindings.cs b/Editor/Mono/GI/LightBaker.bindings.cs index 46deaf1549..d5f19601a6 100644 --- a/Editor/Mono/GI/LightBaker.bindings.cs +++ b/Editor/Mono/GI/LightBaker.bindings.cs @@ -538,7 +538,6 @@ public Resolution lightmapResolution(UInt32 index) extern public void SetLightmapResolution(Resolution resolution); extern public void SetEnvironment(Vector4 color); - extern public void SetBackend(Backend backend); public extern ProbeRequest[] GetProbeRequests(); public extern void SetLightProbeRequests(ProbeRequest[] requests); public extern LightmapRequest[] GetLightmapRequests(); @@ -549,9 +548,52 @@ public void SetProbePositions(Vector3[] positions) SetProbePositions(positions.AsSpan()); } public extern void SetProbePositions(ReadOnlySpan positions); - + public extern Vector3[] GetProbePositions(); } - extern static public Result Bake(BakeInput input); + + [StructLayout(LayoutKind.Sequential)] + public class DeviceSettings : IDisposable + { + static extern IntPtr Internal_Create(); + [NativeMethod(IsThreadSafe = true)] + + public extern bool Initialize(Backend backend); + static extern void Internal_Destroy(IntPtr ptr); + + internal IntPtr m_Ptr; + internal bool m_OwnsPtr; + + public DeviceSettings() + { + m_Ptr = Internal_Create(); + m_OwnsPtr = true; + } + public DeviceSettings(IntPtr ptr) + { + m_Ptr = ptr; + m_OwnsPtr = false; + } + ~DeviceSettings() + { + Destroy(); + } + + public void Dispose() + { + Destroy(); + GC.SuppressFinalize(this); + } + + void Destroy() + { + if (m_OwnsPtr && m_Ptr != IntPtr.Zero) + { + Internal_Destroy(m_Ptr); + m_Ptr = IntPtr.Zero; + } + } + } + extern static public Result Bake(BakeInput input, DeviceSettings deviceSettings); } } diff --git a/Editor/Mono/GI/Lightmapping.bindings.cs b/Editor/Mono/GI/Lightmapping.bindings.cs index d269d1629d..55621c0296 100644 --- a/Editor/Mono/GI/Lightmapping.bindings.cs +++ b/Editor/Mono/GI/Lightmapping.bindings.cs @@ -69,6 +69,22 @@ internal struct LightProbesConvergence [NativeName("m_ConvergedProbeSetCount")] public int convergedProbeSetCount; } + [UsedByNativeCode] + [NativeHeader("Editor/Src/GI/Progressive/PVRData.h")] + internal struct LightmapSize + { + [NativeName("m_Width")] public int width; + [NativeName("m_Height")] public int height; + } + + [UsedByNativeCode] + [NativeHeader("Editor/Src/GI/Progressive/PVRData.h")] + internal struct RunningBakeInfo + { + [NativeName("m_LightmapSizes")] public LightmapSize[] lightmapSizes; + [NativeName("m_ProbePositions")] public UInt64 probePositions; + } + [UsedByNativeCode] [NativeHeader("Editor/Src/GI/Progressive/PVRData.h")] internal struct LightmapMemory @@ -233,6 +249,9 @@ internal static FilterMode filterMode [StaticAccessor("BakedGISceneManager::Get()", StaticAccessorType.Arrow)] internal static extern LightmapConvergence GetLightmapConvergence(int lightmapIndex); + [StaticAccessor("BakedGISceneManager::Get()", StaticAccessorType.Arrow)] + internal static extern RunningBakeInfo GetRunningBakeInfo(); + [StaticAccessor("BakedGISceneManager::Get()", StaticAccessorType.Arrow)] internal static extern LightProbesConvergence GetLightProbesConvergence(); diff --git a/Editor/Mono/GUI/AppStatusBar.cs b/Editor/Mono/GUI/AppStatusBar.cs index 733c2f2a00..e2cee3898e 100644 --- a/Editor/Mono/GUI/AppStatusBar.cs +++ b/Editor/Mono/GUI/AppStatusBar.cs @@ -61,11 +61,15 @@ static Styles() const double k_CheckUnresponsiveFrequencyInSecond = 0.5; const float k_ShowProgressThreshold = 0.5f; private double m_LastUpdate; + private bool m_IsQuitting; private bool showBakeMode { get { + if (m_IsQuitting) + return false; + var settings = Lightmapping.GetLightingSettingsOrDefaultsFallback(); return settings.bakedGI || settings.realtimeGI; } @@ -93,6 +97,8 @@ protected override void OnEnable() Progress.added += RefreshProgressBar; Progress.removed += RefreshProgressBar; Progress.updated += RefreshProgressBar; + + EditorApplication.editorApplicationQuit += OnQuit; } protected override void OnDisable() @@ -100,6 +106,7 @@ protected override void OnDisable() Progress.added -= RefreshProgressBar; Progress.removed -= RefreshProgressBar; Progress.updated -= RefreshProgressBar; + EditorApplication.editorApplicationQuit -= OnQuit; EditorApplication.delayCall -= DelayRepaint; base.OnDisable(); } @@ -474,6 +481,8 @@ private GUIContent GetBakeModeIcon(bool? bakeMode) return Lightmapping.GetLightingSettingsOrDefaultsFallback().autoGenerate; } + private void OnQuit() + => m_IsQuitting = true; [RequiredByNativeCode] public static void StatusChanged() diff --git a/Editor/Mono/GUI/EditorCache.cs b/Editor/Mono/GUI/EditorCache.cs index 03ffb9404a..7a94acc92e 100644 --- a/Editor/Mono/GUI/EditorCache.cs +++ b/Editor/Mono/GUI/EditorCache.cs @@ -67,10 +67,17 @@ private bool Init(Object obj, EditorFeatures requirements) // Are we dealing with a Root Editor? if (editor.GetType() != nonRootEditor.GetType()) { - // Try again, with a normal editor + // Destroy previous editor + UnityEngine.Object.DestroyImmediate(editor); + // Try again, with a non Root editor editor = nonRootEditor; onSceneDragMethodInfo = editor.GetType().GetMethod("OnSceneDrag", sceneDragReflectionFlags); } + else + { + // Destroy unused non Root editor + UnityEngine.Object.DestroyImmediate(nonRootEditor); + } } if (onSceneDragMethodInfo != null) diff --git a/Editor/Mono/GUI/Toolbar.cs b/Editor/Mono/GUI/Toolbar.cs index 1df88833c6..26b6594ef2 100644 --- a/Editor/Mono/GUI/Toolbar.cs +++ b/Editor/Mono/GUI/Toolbar.cs @@ -100,6 +100,7 @@ void CreateContents() protected override void OnDisable() { + m_Root?.RemoveFromHierarchy(); base.OnDisable(); EditorApplication.modifierKeysChanged -= Repaint; } diff --git a/Editor/Mono/GUI/TreeView/AssetOrGameObjectTreeViewDragging.cs b/Editor/Mono/GUI/TreeView/AssetOrGameObjectTreeViewDragging.cs index 8c7c1bdafe..040e596a46 100644 --- a/Editor/Mono/GUI/TreeView/AssetOrGameObjectTreeViewDragging.cs +++ b/Editor/Mono/GUI/TreeView/AssetOrGameObjectTreeViewDragging.cs @@ -30,7 +30,7 @@ public override bool CanStartDrag(TreeViewItem targetItem, List draggedItem foreach (var draggedItemID in draggedItemIDs) { var path = AssetDatabase.GetAssetPath(draggedItemID); - if (AssetDatabase.IsValidFolder(path) && !AssetDatabase.GetAssetFolderInfo(path, out _, out _)) + if (AssetDatabase.IsValidFolder(path) && !AssetDatabase.TryGetAssetFolderInfo(path, out _, out _)) return false; } diff --git a/Editor/Mono/GUI/WindowLayout.cs b/Editor/Mono/GUI/WindowLayout.cs index fec8b45d5e..83e6a452dc 100644 --- a/Editor/Mono/GUI/WindowLayout.cs +++ b/Editor/Mono/GUI/WindowLayout.cs @@ -1613,6 +1613,7 @@ internal static SaveWindowLayout ShowWindow() { SaveWindowLayout w = GetWindowDontShow(); w.minSize = w.maxSize = new Vector2(k_Width, k_Height); + w.m_Pos = new Rect(0, 0,k_Width, k_Height); w.ShowAuxWindow(); return w; } diff --git a/Editor/Mono/GameView/GameViewSizesMenuModifyItemUI.cs b/Editor/Mono/GameView/GameViewSizesMenuModifyItemUI.cs index 2ac7b2877a..8ffdf97ae7 100644 --- a/Editor/Mono/GameView/GameViewSizesMenuModifyItemUI.cs +++ b/Editor/Mono/GameView/GameViewSizesMenuModifyItemUI.cs @@ -99,9 +99,11 @@ override public void OnGUI(Rect rect) { if (string.IsNullOrEmpty(displayText)) displayText = "Result"; - else - displayText = GetCroppedText(displayText, cropWidth, EditorStyles.label); - GUILayout.Label(GUIContent.Temp(displayText), EditorStyles.label); + + var clipping = EditorStyles.label.clipping; + EditorStyles.label.clipping = TextClipping.Ellipsis; + GUILayout.Label(GUIContent.Temp(displayText), EditorStyles.label, GUILayout.MaxWidth(cropWidth)); + EditorStyles.label.clipping = clipping; } GUILayout.FlexibleSpace(); GUILayout.Space(margin); @@ -133,21 +135,6 @@ override public void OnGUI(Rect rect) GUILayout.Space(Styles.windowBottomPadding); } - - string GetCroppedText(string fullText, float cropWidth, GUIStyle style) - { - // Check if we need to crop - int characterCountVisible = style.GetNumCharactersThatFitWithinWidth(fullText, cropWidth); - if (characterCountVisible == -1) - { - return fullText; - } - - if (characterCountVisible > 1 && characterCountVisible != fullText.Length) - return fullText.Substring(0, characterCountVisible - 1) + ("\u2026"); // 'horizontal ellipsis' (U+2026) is: ... - else - return fullText; - } } } diff --git a/Editor/Mono/ImportSettings/SpeedTreeImporterModelEditor.cs b/Editor/Mono/ImportSettings/SpeedTreeImporterModelEditor.cs index 880932b86e..76bcac056d 100644 --- a/Editor/Mono/ImportSettings/SpeedTreeImporterModelEditor.cs +++ b/Editor/Mono/ImportSettings/SpeedTreeImporterModelEditor.cs @@ -256,7 +256,7 @@ private bool DoMaterialsHaveDifferentShader() { foreach (var mat in mr.sharedMaterials) { - if (mat.shader != defaultShader) + if (mat?.shader != defaultShader) return true; } } @@ -265,7 +265,7 @@ private bool DoMaterialsHaveDifferentShader() { foreach (var br in prefabs[i].transform.GetComponentsInChildren()) { - if (br.billboard.material.shader != defaultBillboardShader) + if (br.billboard.material?.shader != defaultBillboardShader) return true; } } diff --git a/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownGUI.cs b/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownGUI.cs index 860a7b0db3..ca26e20101 100644 --- a/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownGUI.cs +++ b/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownGUI.cs @@ -34,6 +34,8 @@ internal static void LoadStyles() Debug.Assert(Event.current.type == EventType.Repaint && Styles.itemStyle != null); } + public static string k_SearchFieldName = "ComponentSearch"; + //This should ideally match line height private Vector2 s_IconSize = new Vector2(13, 13); private AdvancedDropdownDataSource m_DataSource; @@ -153,7 +155,7 @@ internal void DrawSearchField(bool isSearchFieldDisabled, string searchString, A using (new EditorGUI.DisabledScope(isSearchFieldDisabled)) { - GUI.SetNextControlName("ComponentSearch"); + GUI.SetNextControlName(k_SearchFieldName); var newSearch = DrawSearchFieldControl(searchString); diff --git a/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownWindow.cs b/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownWindow.cs index 6fdf2c9ca8..080587c562 100644 --- a/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownWindow.cs +++ b/Editor/Mono/Inspector/AdvancedDropdown/AdvancedDropdownWindow.cs @@ -338,14 +338,15 @@ private void HandleKeyboard() } // Do these if we're not in search mode - if (!hasSearch) + if (!hasSearch && + (string.IsNullOrEmpty(GUI.GetNameOfFocusedControl()) || GUI.GetNameOfFocusedControl() == AdvancedDropdownGUI.k_SearchFieldName)) { if (evt.keyCode == KeyCode.LeftArrow || evt.keyCode == KeyCode.Backspace) { GoToParent(); evt.Use(); } - if (evt.keyCode == KeyCode.RightArrow) + else if (evt.keyCode == KeyCode.RightArrow) { var idx = m_State.GetSelectedIndex(m_CurrentlyRenderedTree); if (idx > -1 && m_CurrentlyRenderedTree.children.ElementAt(idx).children.Any()) @@ -354,7 +355,7 @@ private void HandleKeyboard() } evt.Use(); } - if (evt.keyCode == KeyCode.Escape) + else if (evt.keyCode == KeyCode.Escape) { Close(); evt.Use(); @@ -494,6 +495,7 @@ private void DrawList(AdvancedDropdownItem item) protected void GoToParent() { + GUI.FocusControl(""); if (m_ViewsStack.Count == 0) return; m_LastTime = DateTime.Now.Ticks; @@ -507,6 +509,7 @@ protected void GoToParent() private void GoToChild() { + GUI.FocusControl(""); m_ViewsStack.Push(m_CurrentlyRenderedTree); m_LastTime = DateTime.Now.Ticks; if (m_NewAnimTarget < 0) diff --git a/Editor/Mono/Inspector/CameraEditor.cs b/Editor/Mono/Inspector/CameraEditor.cs index f019b0651f..b70d8cbde1 100644 --- a/Editor/Mono/Inspector/CameraEditor.cs +++ b/Editor/Mono/Inspector/CameraEditor.cs @@ -552,8 +552,6 @@ int targetEyeValue get { return settings.targetEye.intValue; } } - Overlay m_PreviewOverlay; - static List displayDescriptors = new List(); static void OnReloadSubsystemsComplete() @@ -578,7 +576,7 @@ public void OnEnable() SubsystemManager.afterReloadSubsystems += OnReloadSubsystemsComplete; if(!SceneViewCameraOverlay.forceDisable) - SceneView.AddOverlayToActiveView(m_PreviewOverlay = CreatePreviewOverlay(c)); + CreatePreviewOverlay(c); } public void OnDestroy() @@ -589,7 +587,7 @@ public void OnDestroy() public void OnDisable() { - SceneView.RemoveOverlayFromActiveView(m_PreviewOverlay); + SceneViewCameraOverlay.DisableCameraOverlay((Camera)target); m_ShowBGColorOptions.valueChanged.RemoveListener(Repaint); m_ShowOrthoOptions.valueChanged.RemoveListener(Repaint); m_ShowTargetEyeOption.valueChanged.RemoveListener(Repaint); @@ -774,7 +772,7 @@ public virtual void OnOverlayGUI(Object target, SceneView sceneView) { } - public virtual Overlay CreatePreviewOverlay(Camera cam) => new SceneViewCameraOverlay(cam); + public virtual Overlay CreatePreviewOverlay(Camera cam) => SceneViewCameraOverlay.GetOrCreateCameraOverlay(cam); [RequiredByNativeCode] internal static float GetGameViewAspectRatio() diff --git a/Editor/Mono/Inspector/CameraOverlay.cs b/Editor/Mono/Inspector/CameraOverlay.cs index ab977ea0c4..23dd2865b5 100644 --- a/Editor/Mono/Inspector/CameraOverlay.cs +++ b/Editor/Mono/Inspector/CameraOverlay.cs @@ -2,6 +2,7 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using System.Collections.Generic; using UnityEditor.Overlays; using UnityEngine; using UnityEngine.Experimental.Rendering; @@ -28,9 +29,10 @@ class SceneViewCameraOverlay : IMGUIOverlay Camera previewCamera => m_PreviewCamera; RenderTexture m_PreviewTexture; - int m_QualitySettingsAntiAliasing = -1; - public SceneViewCameraOverlay(Camera camera) + static Dictionary s_CameraOverlays = new Dictionary(); + + SceneViewCameraOverlay(Camera camera) { minSize = new Vector2(40, 40); maxSize = new Vector2(4000, 4000); @@ -39,6 +41,8 @@ public SceneViewCameraOverlay(Camera camera) displayName = selectedCamera == null || string.IsNullOrEmpty(selectedCamera.name) ? "Camera Preview" : selectedCamera.name; + + s_CameraOverlays.Add(camera, (this ,1)); } public override void OnCreated() @@ -55,6 +59,37 @@ public override void OnWillBeDestroyed() UnityObject.DestroyImmediate(m_PreviewCamera.gameObject, true); } + public static SceneViewCameraOverlay GetOrCreateCameraOverlay(Camera camera) + { + if (s_CameraOverlays.ContainsKey(camera)) + { + var value = s_CameraOverlays[camera]; + value.count += 1; + s_CameraOverlays[camera] = value; + return value.overlay; + } + + var overlay = new SceneViewCameraOverlay(camera); + SceneView.AddOverlayToActiveView(overlay); + return overlay; + } + + public static void DisableCameraOverlay(Camera cam) + { + if (s_CameraOverlays.ContainsKey(cam)) + { + var value = s_CameraOverlays[cam]; + value.count -= 1; + if (value.count == 0) + { + s_CameraOverlays.Remove(cam); + SceneView.RemoveOverlayFromActiveView(value.overlay); + } + else + s_CameraOverlays[cam] = value; + } + } + RenderTexture GetPreviewTextureWithSizeAndAA(int width, int height) { int antiAliasing = Mathf.Max(1, QualitySettings.antiAliasing); @@ -64,7 +99,6 @@ RenderTexture GetPreviewTextureWithSizeAndAA(int width, int height) m_PreviewTexture.Release(); m_PreviewTexture = new RenderTexture(width, height, 24, SystemInfo.GetGraphicsFormat(DefaultFormat.LDR)); - m_QualitySettingsAntiAliasing = QualitySettings.antiAliasing; m_PreviewTexture.antiAliasing = antiAliasing; } return m_PreviewTexture; diff --git a/Editor/Mono/Inspector/CanvasEditor.cs b/Editor/Mono/Inspector/CanvasEditor.cs index 796d8602cc..f9bc58e84d 100644 --- a/Editor/Mono/Inspector/CanvasEditor.cs +++ b/Editor/Mono/Inspector/CanvasEditor.cs @@ -311,7 +311,11 @@ public override void OnInspectorGUI() if (m_RenderMode.intValue == 0) // Overlay canvas { if (((newShaderChannelValue & (int)AdditionalCanvasShaderChannels.Normal) | (newShaderChannelValue & (int)AdditionalCanvasShaderChannels.Tangent)) != 0) - EditorGUILayout.HelpBox("Shader channels Normal and Tangent are most often used with lighting, which an Overlay canvas does not support. Its likely these channels are not needed.", MessageType.Warning); + { + var helpMessage = "Shader channels Normal and Tangent are most often used with lighting, which an Overlay canvas does not support. Its likely these channels are not needed."; + rect = GUILayoutUtility.GetRect(EditorGUIUtility.TempContent(helpMessage, EditorGUIUtility.GetHelpIcon(MessageType.Warning)), EditorStyles.helpBox); + EditorGUI.HelpBox(rect, helpMessage, MessageType.Warning); + } } } else diff --git a/Editor/Mono/Inspector/EditorDragging.cs b/Editor/Mono/Inspector/EditorDragging.cs index 31a7b8d442..7cc50be9ce 100644 --- a/Editor/Mono/Inspector/EditorDragging.cs +++ b/Editor/Mono/Inspector/EditorDragging.cs @@ -101,9 +101,16 @@ void HandleNativeDragDropInBottomArea(Editor[] editors, Rect rect) if (Event.current.type == EventType.DragPerform) { - DragAndDrop.AcceptDrag(); - m_TargetIndex = -1; - GUIUtility.ExitGUI(); + // Determine if any object references are component, which would mean we are reordering components in the inspector + var anyComponent = DragAndDrop.objectReferences != null && DragAndDrop.objectReferences.Any(o => o is Component); + + // None of the object references are component, cancel further processing to avoid adding component twice + if (!anyComponent) + { + DragAndDrop.AcceptDrag(); + m_TargetIndex = -1; + GUIUtility.ExitGUI(); + } } } diff --git a/Editor/Mono/Inspector/EditorSettingsInspector.cs b/Editor/Mono/Inspector/EditorSettingsInspector.cs index 23ce2551c0..c88d3aa7e6 100644 --- a/Editor/Mono/Inspector/EditorSettingsInspector.cs +++ b/Editor/Mono/Inspector/EditorSettingsInspector.cs @@ -560,8 +560,11 @@ public override void OnInspectorGUI() EditorGUILayout.PropertyField(m_UseLegacyProbeSampleCount, Content.useLegacyProbeSampleCount); if (EditorGUI.EndChangeCheck()) { + if (m_IsGlobalSettings) +#pragma warning disable 618 EditorSettings.useLegacyProbeSampleCount = m_UseLegacyProbeSampleCount.boolValue; +#pragma warning restore 618 EditorApplication.RequestRepaintAllViews(); } diff --git a/Editor/Mono/Inspector/GameObjectInspector.cs b/Editor/Mono/Inspector/GameObjectInspector.cs index ebc604cda1..5e0785c1d0 100644 --- a/Editor/Mono/Inspector/GameObjectInspector.cs +++ b/Editor/Mono/Inspector/GameObjectInspector.cs @@ -35,7 +35,7 @@ static class Styles public static GUIContent layerContent = EditorGUIUtility.TrTextContent("Layer", "The layer that this GameObject is in.\n\nChoose Add Layer... to edit the list of available layers."); public static GUIContent tagContent = EditorGUIUtility.TrTextContent("Tag", "The tag that this GameObject has.\n\nChoose Untagged to remove the current tag.\n\nChoose Add Tag... to edit the list of available tags."); public static GUIContent staticPreviewContent = EditorGUIUtility.TrTextContent("Static Preview", "This asset is greater than 8MB so, by default, the Asset Preview displays a static preview.\nTo view the asset interactively, click the Asset Preview."); - + public static float tagFieldWidth = EditorGUI.CalcPrefixLabelWidth(Styles.tagContent, EditorStyles.boldLabel); public static float layerFieldWidth = EditorGUI.CalcPrefixLabelWidth(Styles.layerContent, EditorStyles.boldLabel); diff --git a/Editor/Mono/Inspector/InspectorWindow.cs b/Editor/Mono/Inspector/InspectorWindow.cs index 52ff6d11db..5b0f8e5d6d 100644 --- a/Editor/Mono/Inspector/InspectorWindow.cs +++ b/Editor/Mono/Inspector/InspectorWindow.cs @@ -478,6 +478,9 @@ internal static void RefreshInspectors() internal override Object GetInspectedObject() { + if (tracker.hasComponentsWhichCannotBeMultiEdited && !tracker.isLocked) + return Selection.activeObject; + Editor editor = InspectorWindowUtils.GetFirstNonImportInspectorEditor(tracker.activeEditors); if (editor == null) return null; @@ -486,6 +489,9 @@ internal override Object GetInspectedObject() internal Object[] GetInspectedObjects() { + if (tracker.hasComponentsWhichCannotBeMultiEdited && !tracker.isLocked) + return Selection.objects; + Editor editor = InspectorWindowUtils.GetFirstNonImportInspectorEditor(tracker.activeEditors); if (editor == null) return null; diff --git a/Editor/Mono/Inspector/LightingSettingsEditor.cs b/Editor/Mono/Inspector/LightingSettingsEditor.cs index b817b5e4f8..1cf2800c3a 100644 --- a/Editor/Mono/Inspector/LightingSettingsEditor.cs +++ b/Editor/Mono/Inspector/LightingSettingsEditor.cs @@ -535,7 +535,9 @@ void GeneralLightmapSettingsGUI(bool compact) maxDirectSamples = (int)Mathf.ClosestPowerOfTwo(Math.Max(maxDirectSamples, m_PVRDirectSampleCount.intValue)); maxIndirectSamples = (int)Mathf.ClosestPowerOfTwo(Math.Max(maxIndirectSamples, m_PVRSampleCount.intValue)); +#pragma warning disable 618 using (new EditorGUI.DisabledScope(EditorSettings.useLegacyProbeSampleCount)) +#pragma warning restore 618 { EditorGUILayout.PropertyField(m_LightProbeSampleCountMultiplier, Styles.probeSampleCountMultiplier); } diff --git a/Editor/Mono/Inspector/ReorderableListWrapper.cs b/Editor/Mono/Inspector/ReorderableListWrapper.cs index b2a5dd1139..66e085a3df 100644 --- a/Editor/Mono/Inspector/ReorderableListWrapper.cs +++ b/Editor/Mono/Inspector/ReorderableListWrapper.cs @@ -24,10 +24,13 @@ public static class Constants internal ReorderableList m_ReorderableList; float m_HeaderHeight; bool m_Reorderable = false; - bool m_IsNotInPrefabContextModeWithOverrides = false; + bool m_ListIsPatchedInPrefabModeInContext = false; + bool m_DisableListElements = false; SerializedProperty m_OriginalProperty; SerializedProperty m_ArraySize; + string m_PropertyPath = string.Empty; + string m_PropertyPathArraySize = string.Empty; internal static Rect s_ToolTipRect; @@ -41,14 +44,23 @@ internal SerializedProperty Property set { m_OriginalProperty = value; - if (!m_OriginalProperty.isValid) return; + if (!m_OriginalProperty.isValid) + { + m_ArraySize = null; + m_PropertyPath = string.Empty; + m_PropertyPathArraySize = string.Empty; + return; + } m_ArraySize = m_OriginalProperty.FindPropertyRelative("Array.size"); + m_PropertyPath = m_OriginalProperty.propertyPath; + m_PropertyPathArraySize = m_OriginalProperty + ".Array.size"; if (m_ReorderableList != null) { bool versionChanged = !SerializedProperty.VersionEquals(m_ReorderableList.serializedProperty, m_OriginalProperty); m_ReorderableList.serializedProperty = m_OriginalProperty; + UpdatePrefabPatchState(m_OriginalProperty.serializedObject.targetObject); if (versionChanged || m_ArraySize != null && m_LastArraySize != m_ArraySize.intValue) { @@ -78,18 +90,16 @@ public static string GetPropertyIdentifier(SerializedProperty serializedProperty public ReorderableListWrapper(SerializedProperty property, GUIContent label, bool reorderable = true) { - Property = property; - m_HeaderHeight = Constants.kDefaultFoldoutHeaderHeight; - Init(reorderable); + Init(reorderable, property); } - void Init(bool reorderable) + void Init(bool reorderable, SerializedProperty property) { m_Reorderable = reorderable; - SerializedProperty childProperty = Property.Copy(); + SerializedProperty childProperty = property.Copy(); childProperty.Next(true); - m_ReorderableList = new ReorderableList(Property.serializedObject, Property.Copy(), m_Reorderable, false, true, true); + m_ReorderableList = new ReorderableList(property.serializedObject, property.Copy(), m_Reorderable, false, true, true); m_ReorderableList.headerHeight = ReorderableList.Defaults.minHeaderHeight; m_ReorderableList.m_IsEditable = true; m_ReorderableList.multiSelect = true; @@ -98,13 +108,16 @@ void Init(bool reorderable) m_ReorderableList.onCanAddCallback += (list) => { - return m_IsNotInPrefabContextModeWithOverrides; + return !m_ListIsPatchedInPrefabModeInContext; }; m_ReorderableList.onCanRemoveCallback += (list) => { - return m_IsNotInPrefabContextModeWithOverrides; + return !m_ListIsPatchedInPrefabModeInContext; }; + + Property = property; + m_HeaderHeight = Constants.kDefaultFoldoutHeaderHeight; } internal void InvalidateCache() => m_ReorderableList.InvalidateCache(); @@ -114,13 +127,28 @@ public float GetHeight() return m_HeaderHeight + (Property.isExpanded && m_ReorderableList != null ? Constants.kHeaderPadding + m_ReorderableList.GetHeight() : 0.0f); } + void UpdatePrefabPatchState(Object serializedObjectTarget) + { + m_DisableListElements = false; + m_ListIsPatchedInPrefabModeInContext = false; + + var prefabStage = PrefabStageUtility.GetCurrentPrefabStage(); + if (prefabStage != null) + { + m_ListIsPatchedInPrefabModeInContext = prefabStage.HasPatchedPropertyModificationsFor(serializedObjectTarget, m_PropertyPath); + if (m_ListIsPatchedInPrefabModeInContext) + { + m_DisableListElements = prefabStage.HasPatchedPropertyModificationsFor(serializedObjectTarget, m_PropertyPathArraySize); + } + } + + if (m_ReorderableList != null) + m_ReorderableList.draggable = m_Reorderable && !m_ListIsPatchedInPrefabModeInContext; + } + public void Draw(GUIContent label, Rect r, Rect visibleArea, string tooltip, bool includeChildren) { r.xMin += EditorGUI.indent; - var prefabStage = PrefabStageUtility.GetCurrentPrefabStage(); - m_IsNotInPrefabContextModeWithOverrides = prefabStage == null || prefabStage.mode != PrefabStage.Mode.InContext || !PrefabStage.s_PatchAllOverriddenProperties - || Selection.objects.All(obj => PrefabUtility.IsPartOfAnyPrefab(obj) && !AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(obj)).Equals(AssetDatabase.AssetPathToGUID(prefabStage.assetPath))); - m_ReorderableList.draggable = m_Reorderable && m_IsNotInPrefabContextModeWithOverrides; Rect headerRect = new Rect(r.x, r.y, r.width, m_HeaderHeight); Rect sizeRect = new Rect(headerRect.xMax - Constants.kArraySizeWidth - EditorGUI.indent * EditorGUI.indentLevel, headerRect.y, @@ -165,7 +193,11 @@ public void Draw(GUIContent label, Rect r, Rect visibleArea, string tooltip, boo m_ReorderableList.InvalidateCacheRecursive(); } + if (m_DisableListElements) + GUI.enabled = false; + DrawChildren(r, headerRect, sizeRect, visibleArea, prevType); + GUI.enabled = prevEnabled; } void DrawChildren(Rect listRect, Rect headerRect, Rect sizeRect, Rect visibleRect, EventType previousEvent) diff --git a/Editor/Mono/Inspector/ScriptExecutionOrderInspector.cs b/Editor/Mono/Inspector/ScriptExecutionOrderInspector.cs index 51a99df4f3..130810206c 100644 --- a/Editor/Mono/Inspector/ScriptExecutionOrderInspector.cs +++ b/Editor/Mono/Inspector/ScriptExecutionOrderInspector.cs @@ -207,7 +207,7 @@ static bool IsValidScript(MonoScript script) // The user can only define the order of scripts in the assets folder. bool isRootFolder, isReadOnly; - if (!AssetDatabase.GetAssetFolderInfo(AssetDatabase.GetAssetPath(script), out isRootFolder, out isReadOnly)) + if (!AssetDatabase.TryGetAssetFolderInfo(AssetDatabase.GetAssetPath(script), out isRootFolder, out isReadOnly)) { return false; } diff --git a/Editor/Mono/Inspector/TagManagerInspector.cs b/Editor/Mono/Inspector/TagManagerInspector.cs index 1ac0eb1f36..7620f8d27a 100644 --- a/Editor/Mono/Inspector/TagManagerInspector.cs +++ b/Editor/Mono/Inspector/TagManagerInspector.cs @@ -240,6 +240,8 @@ void AddToSortLayerList(ReorderableList list) list.serializedProperty.GetArrayElementAtIndex(list.index).FindPropertyRelative("name").stringValue = "New Layer"; list.serializedProperty.serializedObject.ApplyModifiedProperties(); } + + SortingLayer.onLayerAdded(SortingLayer.layers[list.index]); } public void ReorderSortLayerList(ReorderableList list) @@ -250,6 +252,8 @@ public void ReorderSortLayerList(ReorderableList list) private void RemoveFromSortLayerList(ReorderableList list) { + SortingLayer.onLayerRemoved(SortingLayer.layers[list.index]); + ReorderableList.defaultBehaviours.DoRemoveButton(list); serializedObject.ApplyModifiedProperties(); serializedObject.Update(); diff --git a/Editor/Mono/Inspector/VersionControlSettingsInspector.cs b/Editor/Mono/Inspector/VersionControlSettingsInspector.cs index 1fae6146be..c8adf02067 100644 --- a/Editor/Mono/Inspector/VersionControlSettingsInspector.cs +++ b/Editor/Mono/Inspector/VersionControlSettingsInspector.cs @@ -25,6 +25,7 @@ class Styles public static GUIContent automaticAdd = new GUIContent("Automatic Add", "Automatically add newly created assets to version control."); public static GUIContent smartMerge = new GUIContent("Smart merge"); + public static GUIContent trackPackagesOutsideProject = new GUIContent("Version Packages Outside Project", "Tracks changes to packages that reside on disk outside of the project's root folder."); public static GUIContent vcsConnect = new GUIContent("Connect"); public static GUIContent vcsReconnect = new GUIContent("Reconnect"); public static GUIContent workOffline = new GUIContent("Work Offline", @@ -410,6 +411,9 @@ public override void OnInspectorGUI() EditorUserSettings.semanticMergeMode = (SemanticMergeMode)EditorGUILayout.Popup(Styles.smartMerge, (int)EditorUserSettings.semanticMergeMode, semanticMergePopupList); + VersionControlSettings.trackPackagesOutsideProject = + EditorGUILayout.Toggle(Styles.trackPackagesOutsideProject, VersionControlSettings.trackPackagesOutsideProject); + GUILayout.Space(10); GUILayout.Label(Styles.overlayIcons); diff --git a/Editor/Mono/Networking/PlayerConnection/ConnectionDropDown.cs b/Editor/Mono/Networking/PlayerConnection/ConnectionDropDown.cs index 3b5bd0cda3..aba28e0286 100644 --- a/Editor/Mono/Networking/PlayerConnection/ConnectionDropDown.cs +++ b/Editor/Mono/Networking/PlayerConnection/ConnectionDropDown.cs @@ -142,7 +142,6 @@ public static GUIContent GetIcon(string name) "WSAPlayerX64" => EditorGUIUtility.IconContent("BuildSettings.Metro.Small"), "WSAPlayerARM" => EditorGUIUtility.IconContent("BuildSettings.Metro.Small"), "Switch" => EditorGUIUtility.IconContent("BuildSettings.Switch.Small"), - "Stadia" => EditorGUIUtility.IconContent("BuildSettings.Stadia.small"), "EmbeddedLinuxArm64" => EditorGUIUtility.IconContent("BuildSettings.EmbeddedLinux.Small"), "EmbeddedLinuxArm32" => EditorGUIUtility.IconContent("BuildSettings.EmbeddedLinux.Small"), "EmbeddedLinuxX64" => EditorGUIUtility.IconContent("BuildSettings.EmbeddedLinux.Small"), diff --git a/Editor/Mono/ObjectListArea.cs b/Editor/Mono/ObjectListArea.cs index bc50f31383..6534e6607c 100644 --- a/Editor/Mono/ObjectListArea.cs +++ b/Editor/Mono/ObjectListArea.cs @@ -103,8 +103,6 @@ static class Styles public bool foldersFirst { get; set; } int m_KeyboardControlID; - Dictionary m_AssetReferenceToCroppedNameMap = new Dictionary(new AssetReference.GuidThenInstanceIDEqualityComparer()); - int m_WidthUsedForCroppingName; bool m_AllowRenameOnMouseUp = true; @@ -212,9 +210,6 @@ public void Init(Rect rect, HierarchyType hierarchyType, SearchFilter searchFilt Repaint(); - // Clear instanceID to cropped name cache on init - ClearCroppedLabelCache(); - // Prepare data SetupData(true); } @@ -1280,43 +1275,6 @@ public void OnInspectorUpdate() } } - void ClearCroppedLabelCache() - { - m_AssetReferenceToCroppedNameMap.Clear(); - } - - protected string GetCroppedLabelText(AssetReference assetReference, string fullText, float cropWidth) - { - // Clear when width changes - if (m_WidthUsedForCroppingName != (int)cropWidth) - ClearCroppedLabelCache(); - - string croppedText; - if (!m_AssetReferenceToCroppedNameMap.TryGetValue(assetReference, out croppedText)) - { - // Ensure to clean up once in a while - if (m_AssetReferenceToCroppedNameMap.Count > GetMaxNumVisibleItems() * 2 + 30) - ClearCroppedLabelCache(); - - // Check if we need to crop - int characterCountVisible = Styles.resultsGridLabel.GetNumCharactersThatFitWithinWidth(fullText, cropWidth); - if (characterCountVisible == -1) - { - Repaint(); - return fullText; // failed: do not cache result - } - - if (characterCountVisible > 1 && characterCountVisible != fullText.Length) - croppedText = fullText.Substring(0, characterCountVisible - 1) + ("\u2026"); // 'horizontal ellipsis' (U+2026) is: ... - else - croppedText = fullText; - - m_AssetReferenceToCroppedNameMap[assetReference] = croppedText; - m_WidthUsedForCroppingName = (int)cropWidth; - } - return croppedText; - } - public bool IsShowing(int instanceID) { return m_LocalAssets.IndexOf(instanceID) >= 0; @@ -1386,7 +1344,8 @@ public void BeginPing(int instanceID) float vcPadding = s_VCEnabled ? k_ListModeVersionControlOverlayPadding : 0f; var assetReference = new AssetReference() { instanceID = instanceID }; - GUIContent cont = new GUIContent(m_LocalAssets.ListMode ? name : GetCroppedLabelText(assetReference, name, m_WidthUsedForCroppingName)); + var textClipping = m_LocalAssets.ListMode ? TextClipping.Overflow : TextClipping.Ellipsis; + GUIContent cont = new GUIContent(name); string label = cont.text; if (m_LocalAssets.ListMode) @@ -1410,6 +1369,8 @@ public void BeginPing(int instanceID) else { m_Ping.m_PingStyle = Styles.miniPing; + var oldClipping = m_Ping.m_PingStyle.clipping; + m_Ping.m_PingStyle.clipping = textClipping; Vector2 pingLabelSize = m_Ping.m_PingStyle.CalcSize(cont); m_Ping.m_ContentRect.width = pingLabelSize.x; m_Ping.m_ContentRect.height = pingLabelSize.y; @@ -1421,6 +1382,7 @@ public void BeginPing(int instanceID) Styles.resultsGridLabel.Draw(r, label, false, false, false, false); Styles.resultsGridLabel.alignment = orgAnchor; }; + m_Ping.m_PingStyle.clipping = oldClipping; } Vector2 pos = CalculatePingPosition(); m_Ping.m_ContentRect.x = pos.x; diff --git a/Editor/Mono/ObjectListLocalGroup.cs b/Editor/Mono/ObjectListLocalGroup.cs index 971f58e26c..a60e03faf3 100644 --- a/Editor/Mono/ObjectListLocalGroup.cs +++ b/Editor/Mono/ObjectListLocalGroup.cs @@ -943,11 +943,13 @@ void DrawItem(Rect position, FilteredHierarchy.FilterResult filterItem, BuiltinR if (isDropTarget) Styles.resultsLabel.Draw(new Rect(labelRect.x - 10, labelRect.y, labelRect.width + 20, labelRect.height), GUIContent.none, true, true, false, false); - labeltext = m_Owner.GetCroppedLabelText(assetReference, labeltext, orgPosition.width); + var oldClipping = Styles.resultsGridLabel.clipping; + Styles.resultsGridLabel.clipping = TextClipping.Ellipsis; var labelNewRect = Styles.resultsGridLabel.CalcSizeWithConstraints(GUIContent.Temp(labeltext), orgPosition.size); labelRect.x = orgPosition.x + (orgPosition.width - labelNewRect.x) / 2.0f; - labelRect.width = labelNewRect.x; + labelRect.width = labelNewRect.x + Styles.resultsGridLabel.padding.horizontal; Styles.resultsGridLabel.Draw(labelRect, labeltext, false, false, selected, m_Owner.HasFocus()); + Styles.resultsGridLabel.clipping = oldClipping; } } diff --git a/Editor/Mono/ObjectNames.cs b/Editor/Mono/ObjectNames.cs index b40fbc23fb..b97a0d9174 100644 --- a/Editor/Mono/ObjectNames.cs +++ b/Editor/Mono/ObjectNames.cs @@ -49,7 +49,7 @@ public static bool TryGet(Type objectType, out string title) } } - private static string GetObjectTypeName([NotNull] Object o) + private static string GetObjectTypeName([NotNull] Object o, bool multiObjectEditing = false) { if (o is GameObject) return o.name; @@ -72,6 +72,9 @@ private static string GetObjectTypeName([NotNull] Object o) var meshfilter = o as MeshFilter; if (meshfilter) { + if (multiObjectEditing) + return "MeshFilter"; + var mesh = meshfilter.sharedMesh; return (mesh ? mesh.name : L10n.Tr("[none]")) + " (MeshFilter)"; } @@ -102,8 +105,7 @@ private static string GetObjectTypeName([NotNull] Object o) return o.name + " (" + o.GetType().Name + ")"; } - // Inspector title for an object. - public static string GetInspectorTitle(Object obj) + public static string GetInspectorTitle(Object obj, bool multiObjectEditing) { if (obj == null && (object)obj != null && (obj is MonoBehaviour || obj is ScriptableObject)) return L10n.Tr(" (Script)"); @@ -113,7 +115,7 @@ public static string GetInspectorTitle(Object obj) string title; if (!InspectorTitles.TryGet(obj.GetType(), out title)) - title = NicifyVariableName(GetObjectTypeName(obj)); + title = NicifyVariableName(GetObjectTypeName(obj, multiObjectEditing)); if (Attribute.IsDefined(obj.GetType(), typeof(ObsoleteAttribute))) title += L10n.Tr(" (Deprecated)"); @@ -121,6 +123,12 @@ public static string GetInspectorTitle(Object obj) return title; } + // Inspector title for an object. + public static string GetInspectorTitle(Object obj) + { + return GetInspectorTitle(obj, false); + } + // Like GetClassName but handles folders, scenes, GUISkins, and other default assets as separate types. internal static string GetTypeName(Object obj) { diff --git a/Editor/Mono/Overlays/OverlayCanvas.cs b/Editor/Mono/Overlays/OverlayCanvas.cs index 3a4d94ed56..7c0d916bd3 100644 --- a/Editor/Mono/Overlays/OverlayCanvas.cs +++ b/Editor/Mono/Overlays/OverlayCanvas.cs @@ -252,6 +252,9 @@ internal OverlayContainer GetDockZoneContainer(DockZone zone) [SerializeField] List m_ContainerData = new List(); + [SerializeField] + bool m_OverlaysVisible = true; + VisualElement m_RootVisualElement; internal EditorWindow containerWindow { get; set; } @@ -291,6 +294,8 @@ internal OverlayCanvas() { } internal void SetOverlaysEnabled(bool visible) { + m_OverlaysVisible = visible; + if (visible == overlaysEnabled) return; @@ -364,6 +369,9 @@ VisualElement CreateRoot() ve.RegisterCallback(OnDetachedFromPanel); m_WindowRoot = ve.Q("overlay-window-root"); + + SetOverlaysEnabled(m_OverlaysVisible); + return ve; } diff --git a/Editor/Mono/Prefabs/PrefabUtility.cs b/Editor/Mono/Prefabs/PrefabUtility.cs index f2410635af..7168ded2c5 100644 --- a/Editor/Mono/Prefabs/PrefabUtility.cs +++ b/Editor/Mono/Prefabs/PrefabUtility.cs @@ -621,11 +621,11 @@ InteractionMode action } } } - + internal static PropertyValueOriginInfo GetPropertyValueOriginInfo(SerializedProperty property) - { + { if (property == null) - return new PropertyValueOriginInfo("The property is null"); + return new PropertyValueOriginInfo("The property is null"); if (property.prefabOverride) return new PropertyValueOriginInfo("The property value is overriden in the currently open object"); @@ -2040,7 +2040,7 @@ internal static void ValidatePath(GameObject instanceRoot, string path) // We allow relative paths outside the Assets folder so we do not throw if isValidAssetFolder is false bool isRootFolder = false; bool isImmutableFolder = false; - bool isValidAssetFolder = AssetDatabase.GetAssetFolderInfo(directory, out isRootFolder, out isImmutableFolder); + bool isValidAssetFolder = AssetDatabase.TryGetAssetFolderInfo(directory, out isRootFolder, out isImmutableFolder); if (isValidAssetFolder && isImmutableFolder) throw new ArgumentException("Saving Prefab to immutable folder is not allowed: '" + path + "'"); diff --git a/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs b/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs index 0890d336a7..312f94dd3d 100644 --- a/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs +++ b/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs @@ -132,6 +132,7 @@ class SceneViewProperties public static readonly GUIContent createObjectsAtWorldOrigin = EditorGUIUtility.TrTextContent("Create Objects at Origin", "Enable this preference to instantiate new 3D objects at World coordinates 0,0,0. Disable it to instantiate them at the Scene pivot (in front of the Scene view Camera)."); public static readonly GUIContent enableConstrainProportionsScalingForNewObjects = EditorGUIUtility.TrTextContent("Create Objects with Constrained Proportions scale on", "If enabled, scale in the transform component will be set to constrain proportions for new GameObjects by default"); public static readonly GUIContent useInspectorExpandedStateContent = EditorGUIUtility.TrTextContent("Auto-hide gizmos", "Automatically hide gizmos of Components collapsed in the Inspector"); + public static readonly GUIContent ignoreAlwaysRefreshWhenNotFocused = EditorGUIUtility.TrTextContent("Refresh the Scene view only when the Editor is in focus.", "If enabled, ignore the \"Always Refresh\" flag on the Scene view when the Editor is not the foregrounded application."); } class LanguageProperties @@ -824,6 +825,7 @@ private void ShowSceneView(string searchContext) m_Create3DObjectsAtOrigin = EditorGUILayout.Toggle(SceneViewProperties.createObjectsAtWorldOrigin, m_Create3DObjectsAtOrigin); m_EnableConstrainProportionsScalingForNewObjects = EditorGUILayout.Toggle(SceneViewProperties.enableConstrainProportionsScalingForNewObjects, m_EnableConstrainProportionsScalingForNewObjects); AnnotationUtility.useInspectorExpandedState = EditorGUILayout.Toggle(SceneViewProperties.useInspectorExpandedStateContent, AnnotationUtility.useInspectorExpandedState); + SceneView.s_PreferenceIgnoreAlwaysRefreshWhenNotFocused.value = EditorGUILayout.Toggle(SceneViewProperties.ignoreAlwaysRefreshWhenNotFocused, SceneView.s_PreferenceIgnoreAlwaysRefreshWhenNotFocused); GUILayout.Label("Handles", EditorStyles.boldLabel); Handles.s_LineThickness.value = EditorGUILayout.IntSlider(SceneViewProperties.handlesLineThickness, (int)Handles.s_LineThickness.value, 1, 5); @@ -1044,6 +1046,7 @@ private void ShowDeveloperMode(string searchContext) if (m_DeveloperModeDirty) { ApplyChangesToPrefs(); + EditorApplication.UpdateMainWindowTitle(); } } diff --git a/Editor/Mono/ProjectBrowser.cs b/Editor/Mono/ProjectBrowser.cs index c51d99bf8f..0f8a4ca74f 100644 --- a/Editor/Mono/ProjectBrowser.cs +++ b/Editor/Mono/ProjectBrowser.cs @@ -3005,7 +3005,7 @@ internal static bool CanDeleteSelectedAssets() { var path = AssetDatabase.GetAssetPath(instanceID); bool isRootFolder, isImmutable; - if (string.IsNullOrEmpty(path) || !AssetDatabase.GetAssetFolderInfo(path, out isRootFolder, out isImmutable) || isRootFolder || isImmutable) + if (string.IsNullOrEmpty(path) || !AssetDatabase.TryGetAssetFolderInfo(path, out isRootFolder, out isImmutable) || isRootFolder || isImmutable) { return false; } diff --git a/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs b/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs index 37c2909acb..6f431b7110 100644 --- a/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs +++ b/Editor/Mono/SceneManagement/StageManager/PrefabStage/PrefabStage.cs @@ -451,7 +451,23 @@ void SetPrefabInstanceHiddenForInContextEditing(bool hide) StageUtility.SetPrefabInstanceHiddenForInContextEditing(m_OpenedFromInstanceRoot, hide); } - static List s_ReusableCanvasList = new List(); + void UpdateSortableComponentsWithStagePriority(int stagePriority) + { + List rendererList = new List(); + List canvasList = new List(); + + // Renderer components requires to know there is stage priority when entering context and isolation + // mode. If this is not shared, their sorting order will not be evaluated accordingly since they are not + // in the same layer. + m_PrefabContentsRoot.GetComponentsInChildren(true, rendererList); + m_PrefabContentsRoot.GetComponentsInChildren(true, canvasList); + + foreach (Renderer renderer in rendererList) + renderer.stagePriority = (byte)stagePriority; + + foreach (Canvas canvas in canvasList) + canvas.stagePriority = (byte)stagePriority; + } bool LoadStage() { @@ -496,12 +512,15 @@ bool LoadStage() m_PrefabContentsRoot = PrefabStageUtility.LoadPrefabIntoPreviewScene(m_PrefabAssetPath, scene); if (m_PrefabContentsRoot != null) { + // Corresponds to which breadcrumb this is. + var stagePriority = StageNavigationManager.instance.stageHistory.IndexOf(this); + if (isUIPrefab) { - m_PrefabContentsRoot.GetComponentsInChildren(true, s_ReusableCanvasList); + UpdateSortableComponentsWithStagePriority(stagePriority); if (m_Mode == Mode.InIsolation && m_PrefabContentsRoot.transform.parent == null) - PrefabStageUtility.HandleUIReparentingIfNeeded(m_PrefabContentsRoot, 0); + PrefabStageUtility.HandleUIReparentingIfNeeded(m_PrefabContentsRoot, stagePriority); } m_PrefabFileIcon = DeterminePrefabFileIconFromInstanceRootGameObject(); @@ -540,6 +559,7 @@ bool LoadStage() { dummyCanvas.sortingOrder = instanceCanvas.sortingOrder; dummyCanvas.referencePixelsPerUnit = instanceCanvas.referencePixelsPerUnit; + dummyCanvas.stagePriority = (byte)stagePriority; } } @@ -651,7 +671,7 @@ protected internal override void OnReturnToStage() } } - bool HasPatchedPropertyModificationsFor(UnityEngine.Object obj, string partialPropertyName) + internal bool HasPatchedPropertyModificationsFor(UnityEngine.Object obj, string partialPropertyName) { if (m_PatchedProperties == null) return false; @@ -1239,7 +1259,15 @@ void DetectPrefabFileIconChange() void DetectSceneDirtinessChange() { if (scene.dirtyID != m_LastSceneDirtyID) + { + // We want to make sure that all the new sortable components (e.g, canvas, renderer) being added have + // the correct StagePriority assigned to them. Otherwise they won't be sorted accordingly when in + // context/isolation mode. + if (PrefabStageUtility.IsUIPrefab(m_PrefabAssetPath)) + UpdateSortableComponentsWithStagePriority(StageNavigationManager.instance.stageHistory.IndexOf(this)); + SceneView.RepaintAll(); + } m_LastSceneDirtyID = scene.dirtyID; } @@ -1942,7 +1970,7 @@ void VisualizeOverridesToggle() void CachePrefabFolderInfo() { bool isRootFolder; - m_IsPrefabInValidAssetFolder = AssetDatabase.GetAssetFolderInfo(m_PrefabAssetPath, out isRootFolder, out m_IsPrefabInImmutableFolder); + m_IsPrefabInValidAssetFolder = AssetDatabase.TryGetAssetFolderInfo(m_PrefabAssetPath, out isRootFolder, out m_IsPrefabInImmutableFolder); } bool IsPrefabInImmutableFolder() diff --git a/Editor/Mono/SceneModeWindows/LightingWindow.cs b/Editor/Mono/SceneModeWindows/LightingWindow.cs index 50333a961c..4698cb58a9 100644 --- a/Editor/Mono/SceneModeWindows/LightingWindow.cs +++ b/Editor/Mono/SceneModeWindows/LightingWindow.cs @@ -63,7 +63,7 @@ enum Mode BakedLightmaps } - const string kGlobalIlluminationUnityManualPage = "file:///unity/Manual/GlobalIllumination.html"; + const string kGlobalIlluminationUnityManualPage = "https://docs.unity3d.com/Manual/lighting-window.html"; int m_SelectedModeIndex = 0; List m_Modes = null; @@ -531,47 +531,67 @@ private void DoBakeReflectionProbes() internal static void Summary() { bool autoGenerate = Lightmapping.GetLightingSettingsOrDefaultsFallback().autoGenerate; - // Show the number of lightmaps. These are the lightmaps that will be baked, is being baked or was baked last: + + // Show the number of lightmaps: { - long totalMemorySize = 0; int lightmapCount = 0; - Dictionary sizes = new Dictionary(); - bool shadowmaskMode = false; - foreach (LightmapData ld in LightmapSettings.lightmaps) + long totalMemorySize = 0; + StringBuilder sizesString = new(); + var sizes = new Dictionary(); + if (!autoGenerate && Lightmapping.isRunning) // These are the lightmaps that will be baked or is being baked. { - if (ld.lightmapColor == null) - continue; - lightmapCount++; + RunningBakeInfo info = Lightmapping.GetRunningBakeInfo(); + lightmapCount = info.lightmapSizes.Length; + var probesCount = info.probePositions; + string lightmapsPlural = lightmapCount != 1 ? "s" : string.Empty; + string probesPlural = probesCount != 1 ? "s" : string.Empty; + string probesString = probesCount != 0 ? $"{probesCount} probe{probesPlural} and " : string.Empty; + sizesString.Append($"Baking {probesString}{lightmapCount} lightmap{lightmapsPlural}"); + + foreach (var ld in info.lightmapSizes) + if (sizes.ContainsKey(ld)) + sizes[ld]++; + else + sizes.Add(ld, 1); + } + else // These are the lightmaps that were baked last. + { + bool shadowmaskMode = false; + foreach (LightmapData ld in LightmapSettings.lightmaps) + { + if (ld.lightmapColor == null) + continue; + lightmapCount++; - Vector2 texSize = new Vector2(ld.lightmapColor.width, ld.lightmapColor.height); - if (sizes.ContainsKey(texSize)) - sizes[texSize]++; - else - sizes.Add(texSize, 1); + LightmapSize ls = new() { width = ld.lightmapColor.width, height = ld.lightmapColor.height}; + if (sizes.ContainsKey(ls)) + sizes[ls]++; + else + sizes.Add(ls, 1); - totalMemorySize += TextureUtil.GetStorageMemorySizeLong(ld.lightmapColor); - if (ld.lightmapDir) - { - totalMemorySize += TextureUtil.GetStorageMemorySizeLong(ld.lightmapDir); + totalMemorySize += TextureUtil.GetStorageMemorySizeLong(ld.lightmapColor); + if (ld.lightmapDir) + totalMemorySize += TextureUtil.GetStorageMemorySizeLong(ld.lightmapDir); + + if (ld.shadowMask) + { + totalMemorySize += TextureUtil.GetStorageMemorySizeLong(ld.shadowMask); + shadowmaskMode = true; + } } - if (ld.shadowMask) + + sizesString.Append(lightmapCount); + sizesString.Append(" lightmap"); + if (lightmapCount != 1) sizesString.Append("s"); + if (shadowmaskMode) { - totalMemorySize += TextureUtil.GetStorageMemorySizeLong(ld.shadowMask); - shadowmaskMode = true; + sizesString.Append(" with Shadowmask"); + if (lightmapCount != 1) sizesString.Append("s"); } } - StringBuilder sizesString = new StringBuilder(); - sizesString.Append(lightmapCount); - sizesString.Append(" Lightmap"); - if (lightmapCount != 1) sizesString.Append("s"); - if (shadowmaskMode) - { - sizesString.Append(" with Shadowmask"); - if (lightmapCount != 1) sizesString.Append("s"); - } bool first = true; - foreach (var s in sizes) + foreach (KeyValuePair s in sizes) { sizesString.Append(first ? ": " : ", "); first = false; @@ -580,11 +600,13 @@ internal static void Summary() sizesString.Append(s.Value); sizesString.Append("x"); } - sizesString.Append(s.Key.x.ToString(CultureInfo.InvariantCulture.NumberFormat)); + + sizesString.Append(s.Key.width.ToString(CultureInfo.InvariantCulture.NumberFormat)); sizesString.Append("x"); - sizesString.Append(s.Key.y.ToString(CultureInfo.InvariantCulture.NumberFormat)); + sizesString.Append(s.Key.height.ToString(CultureInfo.InvariantCulture.NumberFormat)); sizesString.Append("px"); } + sizesString.Append(" "); GUILayout.BeginHorizontal(); @@ -593,10 +615,13 @@ internal static void Summary() GUILayout.Label(sizesString.ToString(), Styles.labelStyle); GUILayout.EndVertical(); - GUILayout.BeginVertical(); - GUILayout.Label(EditorUtility.FormatBytes(totalMemorySize), Styles.labelStyle); - GUILayout.Label((lightmapCount == 0 ? "No Lightmaps" : ""), Styles.labelStyle); - GUILayout.EndVertical(); + if (totalMemorySize != 0) + { + GUILayout.BeginVertical(); + GUILayout.Label(EditorUtility.FormatBytes(totalMemorySize), Styles.labelStyle); + GUILayout.Label((lightmapCount == 0 ? "No Lightmaps" : ""), Styles.labelStyle); + GUILayout.EndVertical(); + } GUILayout.EndHorizontal(); } @@ -694,8 +719,9 @@ internal static void Summary() int timeM = time / 60; time -= 60 * timeM; int timeS = time; + int decimalPart = (int)(bakeTime % 1 * 100); - GUILayout.Label("Total Bake Time: " + timeH.ToString("0") + ":" + timeM.ToString("00") + ":" + timeS.ToString("00"), Styles.labelStyle); + GUILayout.Label($"Total Bake Time: {timeH:00}:{timeM:00}:{timeS:00}.{decimalPart:00}", Styles.labelStyle); } } GUILayout.EndVertical(); diff --git a/Editor/Mono/SceneModeWindows/LightingWindowLightingTab.cs b/Editor/Mono/SceneModeWindows/LightingWindowLightingTab.cs index 7c9e67f516..f8bc2140d9 100644 --- a/Editor/Mono/SceneModeWindows/LightingWindowLightingTab.cs +++ b/Editor/Mono/SceneModeWindows/LightingWindowLightingTab.cs @@ -59,7 +59,7 @@ class Styles { EditorGUIUtility.TrTextContent("Highest Performance"), EditorGUIUtility.TrTextContent("High Performance"), - EditorGUIUtility.TrTextContent("Balanced"), + EditorGUIUtility.TrTextContent("Automatic"), EditorGUIUtility.TrTextContent("Low Memory Usage"), EditorGUIUtility.TrTextContent("Lowest Memory Usage"), }; diff --git a/Editor/Mono/SceneView/SceneView.cs b/Editor/Mono/SceneView/SceneView.cs index e3a8a24bd5..8685c98f9b 100644 --- a/Editor/Mono/SceneView/SceneView.cs +++ b/Editor/Mono/SceneView/SceneView.cs @@ -151,6 +151,7 @@ private set public static Color selectedOutlineColor => kSceneViewSelectedOutline.Color; public bool isUsingSceneFiltering => UseSceneFiltering(); + internal static SavedBool s_PreferenceIgnoreAlwaysRefreshWhenNotFocused = new SavedBool("SceneView.ignoreAlwaysRefreshWhenNotFocused", false); internal static SavedBool s_PreferenceEnableFilteringWhileSearching = new SavedBool("SceneView.enableFilteringWhileSearching", true); internal static SavedBool s_PreferenceEnableFilteringWhileLodGroupEditing = new SavedBool("SceneView.enableFilteringWhileLodGroupEditing", true); @@ -662,6 +663,9 @@ public bool showGrid [NonSerialized] Camera m_Camera; + [NonSerialized] + bool m_EditorApplicationHasFocus = true; + VisualElement m_CameraViewVisualElement; static readonly string s_CameraRectVisualElementName = "unity-scene-view-camera-rect"; @@ -3117,16 +3121,28 @@ void SetupCamera() void OnBecameVisible() { EditorApplication.update += UpdateAnimatedMaterials; + EditorApplication.focusChanged += OnEditorApplicationFocusChanged; } void OnBecameInvisible() { EditorApplication.update -= UpdateAnimatedMaterials; + EditorApplication.focusChanged -= OnEditorApplicationFocusChanged; + } + + void OnEditorApplicationFocusChanged(bool hasFocus) + { + m_EditorApplicationHasFocus = hasFocus; } void UpdateAnimatedMaterials() { var repaint = false; + + // Ensure that we in fact do want to paint when not in focus. + if (!m_EditorApplicationHasFocus && s_PreferenceIgnoreAlwaysRefreshWhenNotFocused.value) + return; + if (m_lastRenderedTime + 0.033f < EditorApplication.timeSinceStartup) repaint = sceneViewState.alwaysRefreshEnabled; repaint |= LODUtility.IsLODAnimating(m_Camera); diff --git a/Editor/Mono/SceneView/SceneViewMotion.cs b/Editor/Mono/SceneView/SceneViewMotion.cs index 2787de81c0..75c3b8536f 100644 --- a/Editor/Mono/SceneView/SceneViewMotion.cs +++ b/Editor/Mono/SceneView/SceneViewMotion.cs @@ -91,6 +91,7 @@ static void Init() s_Initialized = true; } + [ReserveModifiers(ShortcutModifiers.Shift)] class SceneViewViewport : IShortcutToolContext { public bool active => IsActive; @@ -106,12 +107,14 @@ public static bool IsActive } } + [ReserveModifiers(ShortcutModifiers.Shift)] class SceneViewViewport2D : IShortcutToolContext { public bool active => SceneViewViewport.IsActive && ((SceneView.lastActiveSceneView?.in2DMode ?? false) || (SceneView.lastActiveSceneView?.isRotationLocked ?? false)); } + [ReserveModifiers(ShortcutModifiers.Shift)] class SceneViewViewport3D : IShortcutToolContext { public bool active => SceneViewViewport.IsActive @@ -336,7 +339,7 @@ internal static void ResetMotion() private static void HandleMouseUp(SceneView view, int id, int button, int clickCount) { - if (GUIUtility.hotControl == id && (shortcutKey == KeyCode.None || shortcutKey == (Event.current.keyCode == KeyCode.None ? KeyCode.Mouse0 + Event.current.button : Event.current.keyCode))) + if (Event.current != null && GUIUtility.hotControl == id && (shortcutKey == KeyCode.None || shortcutKey == (Event.current.keyCode == KeyCode.None ? KeyCode.Mouse0 + Event.current.button : Event.current.keyCode))) { // Move pivot to clicked point. if (Tools.s_LockedViewTool == ViewTool.Pan && !s_Drag) diff --git a/Editor/Mono/ScriptAttributeGUI/Implementations/ExposedReferenceDrawer.cs b/Editor/Mono/ScriptAttributeGUI/Implementations/ExposedReferenceDrawer.cs index 05cc9b12d4..ec4e134c3e 100644 --- a/Editor/Mono/ScriptAttributeGUI/Implementations/ExposedReferenceDrawer.cs +++ b/Editor/Mono/ScriptAttributeGUI/Implementations/ExposedReferenceDrawer.cs @@ -150,7 +150,6 @@ public override VisualElement CreatePropertyGUI(SerializedProperty prop) { name = kVisualElementName, label = preferredLabel, - bindingPath = m_Item.exposedPropertyDefault.propertyPath, objectType = typeOfExposedReference, value = m_Item.currentReferenceValue, allowSceneObjects = m_Item.exposedPropertyTable != null @@ -165,7 +164,13 @@ public override VisualElement CreatePropertyGUI(SerializedProperty prop) void SetReference(ChangeEvent evt) { SetReference(evt.newValue); - m_Item.currentReferenceValue = evt.newValue; + if (m_Item.currentReferenceValue != evt.newValue) + { + m_Item.currentReferenceValue = evt.newValue; + + //save the modified SerializedObject since we are bypassing the binding system + m_Item.exposedPropertyName.serializedObject.ApplyModifiedProperties(); + } } internal void SetReference(Object newValue) @@ -189,10 +194,10 @@ internal void SetReference(Object newValue) } else { - var guid = UnityEditor.GUID.Generate(); - var str = guid.ToString(); + var str = UnityEditor.GUID.Generate().ToString(); m_Item.exposedPropertyNameString = str; m_Item.exposedPropertyName.stringValue = str; + m_Item.propertyMode = ExposedPropertyMode.NamedGUID; Undo.RecordObject(m_Item.exposedPropertyTable as UnityEngine.Object, kSetExposedPropertyMsg); m_Item.exposedPropertyTable.SetReferenceValue(m_Item.exposedPropertyNameString, newValue); diff --git a/Editor/Mono/ScriptAttributeGUI/PropertyHandler.cs b/Editor/Mono/ScriptAttributeGUI/PropertyHandler.cs index c394f75894..d3111dfc6e 100644 --- a/Editor/Mono/ScriptAttributeGUI/PropertyHandler.cs +++ b/Editor/Mono/ScriptAttributeGUI/PropertyHandler.cs @@ -348,9 +348,9 @@ public float GetHeight(SerializedProperty property, GUIContent label, bool inclu bool childrenAreExpanded = property.isExpanded && EditorGUI.HasVisibleChildFields(property); // Loop through all child properties - var tc = EditorGUIUtility.TempContent(property.localizedDisplayName, tooltip); if (childrenAreExpanded) { + var tc = EditorGUIUtility.TempContent(property.localizedDisplayName, tooltip); SerializedProperty endProperty = property.GetEndProperty(); while (property.NextVisible(childrenAreExpanded) && !SerializedProperty.EqualContents(property, endProperty)) { diff --git a/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs b/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs index bafdba1c32..7b5d10b7a8 100644 --- a/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs +++ b/Editor/Mono/Scripting/ScriptCompilation/CustomScriptAssembly.cs @@ -285,7 +285,7 @@ public AssemblyFlags AssemblyFlags } bool rootFolder, immutable; - bool imported = AssetDatabase.GetAssetFolderInfo(PathPrefix, out rootFolder, out immutable); + bool imported = AssetDatabase.TryGetAssetFolderInfo(PathPrefix, out rootFolder, out immutable); // Do not emit warnings for immutable (package) folders, // as the user cannot do anything to fix them. @@ -358,6 +358,7 @@ static CustomScriptAssembly() new CustomScriptAssemblyPlatform("LinuxStandalone32", BuildTarget.StandaloneLinux), new CustomScriptAssemblyPlatform("LinuxStandaloneUniversal", BuildTarget.StandaloneLinuxUniversal), new CustomScriptAssemblyPlatform("Lumin", BuildTarget.Lumin), + new CustomScriptAssemblyPlatform("Stadia", BuildTarget.Stadia), }; #pragma warning restore 0618 } diff --git a/Editor/Mono/Shaders/ShaderKeywordFilterUtil.cs b/Editor/Mono/Shaders/ShaderKeywordFilterUtil.cs index 8c7d548830..3e923fe666 100644 --- a/Editor/Mono/Shaders/ShaderKeywordFilterUtil.cs +++ b/Editor/Mono/Shaders/ShaderKeywordFilterUtil.cs @@ -84,6 +84,40 @@ internal struct ConstraintState [RequiredByNativeCode] internal static class ShaderKeywordFilterUtil { + internal struct CachedFilterData + { + public Hash128 dependencyHash; + public SettingsNode settingsNode; + }; + + // In memory cache for filter data per renderpipeline asset. + // This is to avoid redundant attribute search for each shader/pass/stage. + internal static Dictionary PerAssetFilterDataCache = new Dictionary(); + + internal static SettingsNode GetFilterDataCached(string nodeName, UnityEngine.Object containerObject) + { + string assetPath = AssetDatabase.GetAssetPath(containerObject); + Hash128 dependencyHash = AssetDatabase.GetAssetDependencyHash(assetPath); + + CachedFilterData cachedData; + if (PerAssetFilterDataCache.TryGetValue(assetPath, out cachedData)) + { + // Cached data is valid only if dependency hash hasn't changed + if (cachedData.dependencyHash == dependencyHash) + return cachedData.settingsNode; + } + + // No valid data found in the cache so we need to do the full processing + // and then enter the result into the cache. + var visited = new HashSet(); + cachedData.dependencyHash = dependencyHash; + cachedData.settingsNode = SettingsNode.GatherFilterData(nodeName, containerObject, visited); + + PerAssetFilterDataCache[assetPath] = cachedData; + + return cachedData.settingsNode; + } + // For the current build target with given constraint state, gets the list of active filter rule sets. [RequiredByNativeCode] internal static SettingsVariant[] GetKeywordFilterVariants(string buildTargetGroupName, ConstraintState constraintState) @@ -98,8 +132,7 @@ internal static SettingsVariant[] GetKeywordFilterVariants(string buildTargetGro if (rpAsset == null) continue; - var visited = new HashSet(); - var node = SettingsNode.GatherFilterData(rpAsset.name, rpAsset, visited); + var node = GetFilterDataCached(rpAsset.name, rpAsset); if (node != null) root.Children.Add(node); } diff --git a/Editor/Mono/UIElements/Controls/PropertyField.cs b/Editor/Mono/UIElements/Controls/PropertyField.cs index 2ff4e3d7f3..abb17beb48 100644 --- a/Editor/Mono/UIElements/Controls/PropertyField.cs +++ b/Editor/Mono/UIElements/Controls/PropertyField.cs @@ -920,7 +920,6 @@ private void RegisterPropertyChangesOnCustomDrawerElement(VisualElement customPr customPropertyDrawer.RegisterCallback>((changeEvent) => AsyncDispatchPropertyChangedEvent()); customPropertyDrawer.RegisterCallback>((changeEvent) => AsyncDispatchPropertyChangedEvent()); customPropertyDrawer.RegisterCallback>((changeEvent) => AsyncDispatchPropertyChangedEvent()); - customPropertyDrawer.RegisterCallback>((changeEvent) => AsyncDispatchPropertyChangedEvent()); customPropertyDrawer.RegisterCallback>((changeEvent) => AsyncDispatchPropertyChangedEvent()); customPropertyDrawer.RegisterCallback>((changeEvent) => AsyncDispatchPropertyChangedEvent()); customPropertyDrawer.RegisterCallback>((changeEvent) => AsyncDispatchPropertyChangedEvent()); diff --git a/Editor/Mono/UIElements/Inspector/EditorElement.cs b/Editor/Mono/UIElements/Inspector/EditorElement.cs index 12e3c8bad7..97106d9f1c 100644 --- a/Editor/Mono/UIElements/Inspector/EditorElement.cs +++ b/Editor/Mono/UIElements/Inspector/EditorElement.cs @@ -129,7 +129,7 @@ void Init(Editor[] editors) { PopulateCache(editors); m_EditorTarget = editor.targets[0]; - var editorTitle = ObjectNames.GetInspectorTitle(m_EditorTarget); + var editorTitle = ObjectNames.GetInspectorTitle(m_EditorTarget, editor.targets.Length > 1); m_Header = BuildHeaderElement(editorTitle); m_Footer = BuildFooterElement(editorTitle); @@ -137,6 +137,13 @@ void Init(Editor[] editors) Add(m_Header); Add(m_Footer); + // For GameObjects we want to ensure the first component's title bar is flush with the header, + // so we apply a small offset to the margin. (UUM-16138) + if (m_EditorTarget is GameObject) + { + AddToClassList("game-object-inspector"); + } + if (InspectorElement.disabledThrottling) CreateInspectorElement(); } @@ -496,17 +503,6 @@ Rect DrawEditorSmallHeader(Editor[] editors, Object target, bool wasVisible) if (currentEditor == null) return GUILayoutUtility.GetLastRect(); - // ensure first component's title bar is flush with the header - if (EditorNeedsVerticalOffset(editors, target)) - { - // TODO: Check if we can fix this in the GameObjectInspector instead - GUILayout.Space( - -3f // 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); diff --git a/Editor/Mono/UIElements/Inspector/InspectorElement.cs b/Editor/Mono/UIElements/Inspector/InspectorElement.cs index e54b2068f9..6777ad8795 100644 --- a/Editor/Mono/UIElements/Inspector/InspectorElement.cs +++ b/Editor/Mono/UIElements/Inspector/InspectorElement.cs @@ -613,7 +613,7 @@ private VisualElement CreateIMGUIInspectorFromEditor(SerializedObject serialized } EditorGUIUtility.ResetGUIState(); - using (new EditorGUI.DisabledScope(!editor.IsEnabled())) + using (new EditorGUI.DisabledScope(!editor.IsEnabled() || !enabledInHierarchy)) { var genericEditor = editor as GenericInspector; if (genericEditor != null) diff --git a/Editor/Mono/Unwrapping.bindings.cs b/Editor/Mono/Unwrapping.bindings.cs index eb66678f06..40e0f8cf59 100644 --- a/Editor/Mono/Unwrapping.bindings.cs +++ b/Editor/Mono/Unwrapping.bindings.cs @@ -44,6 +44,9 @@ public static Vector2[] GeneratePerTriangleUV(Mesh src) // Will generate per-triangle uv (3 uv pairs for each triangle) with provided settings public static Vector2[] GeneratePerTriangleUV(Mesh src, UnwrapParam settings) { + if (src == null) + throw new ArgumentNullException("src"); + return GeneratePerTriangleUVImpl(src, settings); } diff --git a/Editor/Mono/VersionControlSettings.bindings.cs b/Editor/Mono/VersionControlSettings.bindings.cs index 8249de6ce7..bdc8633a48 100644 --- a/Editor/Mono/VersionControlSettings.bindings.cs +++ b/Editor/Mono/VersionControlSettings.bindings.cs @@ -67,6 +67,10 @@ public static extern string mode set; } + [StaticAccessor("GetVersionControlSettings()", StaticAccessorType.Dot)] + [ExcludeFromDocs] + public static extern bool trackPackagesOutsideProject { get; set; } + [StaticAccessor("GetEditorUserSettings()", StaticAccessorType.Dot)] private static extern string GetConfigValue(string name); diff --git a/ModuleOverrides/com.unity.ui/Core/ClickDetector.cs b/ModuleOverrides/com.unity.ui/Core/ClickDetector.cs index 5046414ea1..cb83216170 100644 --- a/ModuleOverrides/com.unity.ui/Core/ClickDetector.cs +++ b/ModuleOverrides/com.unity.ui/Core/ClickDetector.cs @@ -170,5 +170,15 @@ private static bool ContainsPointer(VisualElement element, Vector2 position) var elementUnderPointer = element.panel.Pick(position); return element == elementUnderPointer || element.Contains(elementUnderPointer); } + + //Called when a visual element is removed from a panel to clear all reference to the visual element + internal void Cleanup(VisualElement ve) + { + foreach (var status in m_ClickStatus) + { + if (status.m_Target == ve) + status.Reset(); + } + } } } diff --git a/ModuleOverrides/com.unity.ui/Core/Clickable.cs b/ModuleOverrides/com.unity.ui/Core/Clickable.cs index e168880747..67ac15d728 100644 --- a/ModuleOverrides/com.unity.ui/Core/Clickable.cs +++ b/ModuleOverrides/com.unity.ui/Core/Clickable.cs @@ -96,7 +96,7 @@ private void OnTimer(TimerState timerState) { if ((clicked != null || clickedWithEventInfo != null) && IsRepeatable()) { - if (ContainsPointer(m_ActivePointerId)) + if (ContainsPointer(m_ActivePointerId) && (target.enabledInHierarchy || acceptClicksIfDisabled)) { Invoke(null); target.pseudoStates |= PseudoStates.Active; @@ -310,7 +310,7 @@ protected virtual void ProcessDownEvent(EventBase evt, Vector2 localPosition, in if (IsRepeatable()) { // Repeatable button clicks are performed on the MouseDown and at timer events - if (ContainsPointer(pointerId)) + if (ContainsPointer(pointerId) && (target.enabledInHierarchy || acceptClicksIfDisabled)) { Invoke(evt); } @@ -370,7 +370,7 @@ protected virtual void ProcessUpEvent(EventBase evt, Vector2 localPosition, int else { // Non repeatable button clicks are performed on the MouseUp - if (ContainsPointer(pointerId) && target.enabledInHierarchy) + if (ContainsPointer(pointerId) && (target.enabledInHierarchy || acceptClicksIfDisabled)) { Invoke(evt); } diff --git a/ModuleOverrides/com.unity.ui/Core/Collections/Controllers/BaseListViewController.cs b/ModuleOverrides/com.unity.ui/Core/Collections/Controllers/BaseListViewController.cs index f9c92555dd..c2e1b4e4ad 100644 --- a/ModuleOverrides/com.unity.ui/Core/Collections/Controllers/BaseListViewController.cs +++ b/ModuleOverrides/com.unity.ui/Core/Collections/Controllers/BaseListViewController.cs @@ -150,16 +150,11 @@ public virtual void Move(int index, int newIndex) /// The item index. public virtual void RemoveItem(int index) { - var indices = ListPool.Get(); - try + using (ListPool.Get(out var indices)) { indices.Add(index); RemoveItems(indices); } - finally - { - ListPool.Release(indices); - } } /// diff --git a/ModuleOverrides/com.unity.ui/Core/Collections/Controllers/BaseTreeViewController.cs b/ModuleOverrides/com.unity.ui/Core/Collections/Controllers/BaseTreeViewController.cs index dec6c8e33a..76581ed4d2 100644 --- a/ModuleOverrides/com.unity.ui/Core/Collections/Controllers/BaseTreeViewController.cs +++ b/ModuleOverrides/com.unity.ui/Core/Collections/Controllers/BaseTreeViewController.cs @@ -6,6 +6,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using Unity.Profiling; namespace UnityEngine.UIElements { @@ -17,6 +18,7 @@ public abstract class BaseTreeViewController : CollectionViewController Dictionary m_TreeItems = new Dictionary(); List m_RootIndices = new List(); List m_ItemWrappers = new List(); + HashSet m_TreeItemIdsWithItemWrappers = new HashSet(); List m_WrapperInsertionList = new List(); /// @@ -214,12 +216,15 @@ public virtual int GetTreeItemsCount() /// The index of the item in the expanded items source. Returns -1 if the item is not visible. public override int GetIndexForId(int id) { - for (var index = 0; index < m_ItemWrappers.Count; index++) + if (m_TreeItemIdsWithItemWrappers.Contains(id)) { - var wrapper = m_ItemWrappers[index]; - if (wrapper.id == id) + for (var index = 0; index < m_ItemWrappers.Count; index++) { - return index; + var wrapper = m_ItemWrappers[index]; + if (wrapper.id == id) + { + return index; + } } } @@ -320,6 +325,7 @@ public bool IsExpandedByIndex(int index) return IsExpanded(m_ItemWrappers[index].id); } + static readonly ProfilerMarker K_ExpandItemByIndex = new ProfilerMarker(ProfilerCategory.Scripts, "BaseTreeViewController.ExpandItemByIndex"); /// /// Expands the item with the specified index, making his children visible. Allows to expand the whole hierarchy under that item. /// @@ -328,6 +334,7 @@ public bool IsExpandedByIndex(int index) /// Whether to refresh items or not. Set to false when doing multiple operations on the tree, to only do one RefreshItems once all operations are done. public void ExpandItemByIndex(int index, bool expandAllChildren, bool refresh = true) { + using var marker = K_ExpandItemByIndex.Auto(); if (!HasChildrenByIndex(index)) return; @@ -337,12 +344,11 @@ public void ExpandItemByIndex(int index, bool expandAllChildren, bool refresh = var childrenIdsList = new List(); foreach (var childId in childrenIds) { - if (m_ItemWrappers.All(x => x.id != childId)) + if (!m_TreeItemIdsWithItemWrappers.Contains(childId)) childrenIdsList.Add(childId); } - CreateWrappers(childrenIdsList, GetIndentationDepth(index) + 1, - ref m_WrapperInsertionList); + CreateWrappers(childrenIdsList, GetIndentationDepth(index) + 1, ref m_WrapperInsertionList); m_ItemWrappers.InsertRange(index + 1, m_WrapperInsertionList); if (!baseTreeView.expandedItemIds.Contains(m_ItemWrappers[index].id)) baseTreeView.expandedItemIds.Add(m_ItemWrappers[index].id); @@ -416,9 +422,13 @@ public void CollapseItemByIndex(int index, bool collapseAllChildren) recursiveChildCount++; currentIndex++; } + var end = index + 1 + recursiveChildCount; + for (int i = index + 1; i < end; i++) + { + m_TreeItemIdsWithItemWrappers.Remove(m_ItemWrappers[i].id); + } m_ItemWrappers.RemoveRange(index + 1, recursiveChildCount); - baseTreeView.RefreshItems(); } @@ -431,12 +441,17 @@ public void CollapseItem(int id, bool collapseAllChildren) { // Try to find it in the currently visible list. for (var i = 0; i < m_ItemWrappers.Count; ++i) + { if (m_ItemWrappers[i].id == id) + { if (IsExpandedByIndex(i)) { CollapseItemByIndex(i, collapseAllChildren); return; } + break; + } + } if (!baseTreeView.expandedItemIds.Contains(id)) return; @@ -473,6 +488,7 @@ public void CollapseAll() internal void RegenerateWrappers() { m_ItemWrappers.Clear(); + m_TreeItemIdsWithItemWrappers.Clear(); var rootItemIds = GetRootItemIds(); if (rootItemIds == null) @@ -481,10 +497,12 @@ internal void RegenerateWrappers() CreateWrappers(rootItemIds, 0, ref m_ItemWrappers); SetItemsSourceWithoutNotify(m_ItemWrappers); } - + + static readonly ProfilerMarker k_CreateWrappers = new ProfilerMarker("BaseTreeViewController.CreateWrappers"); void CreateWrappers(IEnumerable treeViewItemIds, int depth, ref List wrappers) { - if (treeViewItemIds == null || wrappers == null) + using var marker = k_CreateWrappers.Auto(); + if (treeViewItemIds == null || wrappers == null || m_TreeItemIdsWithItemWrappers == null) return; foreach (var id in treeViewItemIds) @@ -494,6 +512,7 @@ void CreateWrappers(IEnumerable treeViewItemIds, int depth, ref List(className: Foldout.toggleUssClassName); + foldoutToggle.m_Clickable.acceptClicksIfDisabled = true; + m_Foldout.AddToClassList(foldoutHeaderUssClassName); m_Foldout.tabIndex = 1; hierarchy.Add(m_Foldout); diff --git a/ModuleOverrides/com.unity.ui/Core/Controls/GenericDropdownMenu.cs b/ModuleOverrides/com.unity.ui/Core/Controls/GenericDropdownMenu.cs index a0810ecdc3..3a02ee6639 100644 --- a/ModuleOverrides/com.unity.ui/Core/Controls/GenericDropdownMenu.cs +++ b/ModuleOverrides/com.unity.ui/Core/Controls/GenericDropdownMenu.cs @@ -129,9 +129,6 @@ void OnDetachFromPanel(DetachFromPanelEvent evt) if (evt.originPanel == null) return; - m_MenuContainer.UnregisterCallback(OnAttachToPanel); - m_MenuContainer.UnregisterCallback(OnDetachFromPanel); - contentContainer.RemoveManipulator(m_NavigationManipulator); m_MenuContainer.UnregisterCallback(OnPointerDown); m_MenuContainer.UnregisterCallback(OnPointerMove); diff --git a/ModuleOverrides/com.unity.ui/Core/Controls/Image.cs b/ModuleOverrides/com.unity.ui/Core/Controls/Image.cs index 34520b540e..94af4b824b 100644 --- a/ModuleOverrides/com.unity.ui/Core/Controls/Image.cs +++ b/ModuleOverrides/com.unity.ui/Core/Controls/Image.cs @@ -370,7 +370,13 @@ private void OnCustomStyleResolved(CustomStyleResolvedEvent e) } if (!m_TintColorIsInline && customStyle.TryGetValue(s_TintColorProperty, out tintValue)) - m_TintColor = tintValue; + { + if (m_TintColor != tintValue) + { + m_TintColor = tintValue; + IncrementVersion(VersionChangeType.Repaint); + } + } } private void SetScaleMode(ScaleMode mode) diff --git a/ModuleOverrides/com.unity.ui/Core/Controls/MultiColumn/SortColumnDescription.cs b/ModuleOverrides/com.unity.ui/Core/Controls/MultiColumn/SortColumnDescription.cs index 4bfaa6ddff..8550449e0b 100644 --- a/ModuleOverrides/com.unity.ui/Core/Controls/MultiColumn/SortColumnDescription.cs +++ b/ModuleOverrides/com.unity.ui/Core/Controls/MultiColumn/SortColumnDescription.cs @@ -81,7 +81,7 @@ public string columnName } /// - /// The index of the column. + /// The index of the column to be used to find the column only if the columnName isn't set. /// public int columnIndex { diff --git a/ModuleOverrides/com.unity.ui/Core/Controls/PopupField.cs b/ModuleOverrides/com.unity.ui/Core/Controls/PopupField.cs index 6ad21a6718..a013fe7b9e 100644 --- a/ModuleOverrides/com.unity.ui/Core/Controls/PopupField.cs +++ b/ModuleOverrides/com.unity.ui/Core/Controls/PopupField.cs @@ -17,6 +17,8 @@ public class PopupField : BasePopupField { internal static readonly DataBindingProperty indexProperty = nameof(index); + internal static List s_Modifiers = new List() { '&', '%', '^', '#', '_' }; + /// /// Callback that provides a string representation used to display the selected value. /// @@ -43,7 +45,20 @@ internal override string GetValueToDisplay() { if (m_FormatSelectedValueCallback != null) return m_FormatSelectedValueCallback(value); - return (value != null) ? value.ToString() : string.Empty; + + Func defaultFormatSelectedValue = (value) => { + string displayValue = value.TrimEnd(); + int pos = displayValue.LastIndexOf(' '); + if (pos != -1 && displayValue.Length > pos + 1 && s_Modifiers.Contains(displayValue[pos + 1])) + displayValue = displayValue.Substring(0, pos).TrimEnd(); + + return displayValue; + }; + + if (value != null) + return defaultFormatSelectedValue(value.ToString()); + + return string.Empty; } internal override string GetListItemToDisplay(T value) diff --git a/ModuleOverrides/com.unity.ui/Core/Controls/ScrollView.cs b/ModuleOverrides/com.unity.ui/Core/Controls/ScrollView.cs index 52ba04a1bb..18d66462d1 100644 --- a/ModuleOverrides/com.unity.ui/Core/Controls/ScrollView.cs +++ b/ModuleOverrides/com.unity.ui/Core/Controls/ScrollView.cs @@ -97,7 +97,7 @@ public enum ScrollerVisibility } /// - /// Displays its contents inside a scrollable frame. + /// Displays its contents inside a scrollable frame. For more information, see [[wiki:UIE-uxml-element-ScrollView|ScrollView]]. /// public class ScrollView : VisualElement { @@ -306,7 +306,13 @@ public Vector2 scrollOffset { horizontalScroller.value = value.x; verticalScroller.value = value.y; - UpdateContentViewTransform(); + + if (panel != null) + { + UpdateScrollers(needsHorizontal, needsVertical); + UpdateContentViewTransform(); + } + NotifyPropertyChanged(scrollOffsetProperty); } } diff --git a/ModuleOverrides/com.unity.ui/Core/GameObjects/PanelSettings.cs b/ModuleOverrides/com.unity.ui/Core/GameObjects/PanelSettings.cs index 819e1225cf..751e1d8562 100644 --- a/ModuleOverrides/com.unity.ui/Core/GameObjects/PanelSettings.cs +++ b/ModuleOverrides/com.unity.ui/Core/GameObjects/PanelSettings.cs @@ -353,11 +353,10 @@ internal void ApplySortingOrder() private int m_TargetDisplay = 0; /// - /// When the Scene uses more than one panel, this value determines where this panel appears in the sorting - /// order relative to other panels. + /// Set the display intended for the panel. /// /// - /// Unity renders panels with a higher sorting order value on top of panels with a lower value. + /// This setting is relevant only when no render texture is applied, as the renderTexture takes precedence. /// public int targetDisplay { @@ -438,6 +437,7 @@ public UInt32 vertexBudget internal static Action CreateRuntimePanelDebug; internal static Func GetOrCreateDefaultTheme; + internal static Func GetGameViewResolution; internal static Action SetPanelSettingsAssetDirty; internal static void SetupLiveReloadPanelTrackers(bool isLiveReloadOn) @@ -735,13 +735,12 @@ internal Rect GetDisplayRect() return new Rect(0, 0, m_TargetTexture.width, m_TargetTexture.height); // TODO: Support sub-rects } - // Overlay. - if (targetDisplay > 0 && targetDisplay < Display.displays.Length) - { - return new Rect(0, 0, Display.displays[targetDisplay].renderingWidth, Display.displays[targetDisplay].renderingHeight); - } + //The device simulatior is a special game view on display 0, and the screen values are properly populated + if( m_TargetDisplay == 0) + return new Rect(0,0, Screen.width, Screen.height); - return new Rect(0, 0, Screen.width, Screen.height); + // In the Unity Editor, Display.displays is not supported; displays.Length always has a value of 1, regardless of how many displays you have connected. + return new(Vector2.zero, GetGameViewResolution(m_TargetDisplay)); } internal void AttachAndInsertUIDocumentToVisualTree(UIDocument uiDocument) diff --git a/ModuleOverrides/com.unity.ui/Core/Layout/LayoutManager.cs b/ModuleOverrides/com.unity.ui/Core/Layout/LayoutManager.cs index ae0933e10b..96b2390bc5 100644 --- a/ModuleOverrides/com.unity.ui/Core/Layout/LayoutManager.cs +++ b/ModuleOverrides/com.unity.ui/Core/Layout/LayoutManager.cs @@ -2,7 +2,7 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using System; +using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; @@ -30,6 +30,7 @@ enum LayoutConfigDataType } delegate void LayoutMeasureFunction( + VisualElement ve, ref LayoutNode node, float width, LayoutMeasureMode widthMode, @@ -192,6 +193,7 @@ static void Shutdown() readonly ManagedObjectStore m_ManagedMeasureFunctions = new(); readonly ManagedObjectStore m_ManagedBaselineFunctions = new(); + readonly ManagedObjectStore> m_ManagedOwners = new(); int m_HighMark; @@ -362,6 +364,7 @@ void FreeNode(LayoutHandle handle) ref var data = ref GetAccess().GetNodeData(handle); m_ManagedMeasureFunctions.UpdateValue(ref data.ManagedMeasureFunctionIndex, null); m_ManagedBaselineFunctions.UpdateValue(ref data.ManagedBaselineFunctionIndex, null); + m_ManagedOwners.UpdateValue(ref data.ManagedOwnerIndex, null); m_Nodes.Free(handle); } @@ -379,17 +382,42 @@ public LayoutMeasureFunction GetMeasureFunction(LayoutHandle handle) public void SetMeasureFunction(LayoutHandle handle, LayoutMeasureFunction value) { + if (GetAccess().GetNodeData(handle).ManagedOwnerIndex == 0) Debug.LogWarning("Settomg Measure method on a node with no Owner"); ref var index = ref GetAccess().GetNodeData(handle).ManagedMeasureFunctionIndex; m_ManagedMeasureFunctions.UpdateValue(ref index, value); } + public VisualElement GetOwner(LayoutHandle handle) + { + //This assumes an internal behavior of the managed object store... invalid could be -1 instead + if (GetAccess().GetNodeData(handle).ManagedOwnerIndex == 0) + return null; + + // Will throw if the weak referenc is not in the list + m_ManagedOwners.GetValue(GetAccess().GetNodeData(handle).ManagedOwnerIndex).TryGetTarget(out var ve); + return ve; + } + + public void SetOwner(LayoutHandle handle, VisualElement value) + { + if (value == null) + { + if (GetAccess().GetNodeData(handle).ManagedMeasureFunctionIndex != 0) Debug.LogWarning("Node with no owner has a Measure method"); + if (GetAccess().GetNodeData(handle).ManagedBaselineFunctionIndex != 0) Debug.LogWarning("Node with no owner has a baseline method"); + } + ref var index = ref GetAccess().GetNodeData(handle).ManagedOwnerIndex; + m_ManagedOwners.UpdateValue(ref index, new(value)); + } + + public LayoutBaselineFunction GetBaselineFunction(LayoutHandle handle) { - return m_ManagedBaselineFunctions.GetValue(GetAccess().GetNodeData(handle).ManagedBaselineFunctionIndex); + return m_ManagedBaselineFunctions.GetValue(GetAccess().GetNodeData(handle).ManagedMeasureFunctionIndex); } public void SetBaselineFunction(LayoutHandle handle, LayoutBaselineFunction value) { + if (GetAccess().GetNodeData(handle).ManagedOwnerIndex == 0) Debug.LogWarning("Setting Baseline method on a node with no Owner"); ref var index = ref GetAccess().GetNodeData(handle).ManagedBaselineFunctionIndex; m_ManagedBaselineFunctions.UpdateValue(ref index, value); } diff --git a/ModuleOverrides/com.unity.ui/Core/Layout/LayoutNode.cs b/ModuleOverrides/com.unity.ui/Core/Layout/LayoutNode.cs index cef003068b..59f651178e 100644 --- a/ModuleOverrides/com.unity.ui/Core/Layout/LayoutNode.cs +++ b/ModuleOverrides/com.unity.ui/Core/Layout/LayoutNode.cs @@ -2,7 +2,7 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using System; +using System; using System.Runtime.InteropServices; using Unity.Collections.LowLevel.Unsafe; using UnityEngine.Assertions; @@ -83,11 +83,16 @@ public LayoutMeasureFunction Measure } /// - /// Sets the custom measure function for this node. + /// Sets the owner of this node. /// - public void SetMeasureFunction(LayoutMeasureFunction func) + public void SetOwner(VisualElement func) { - m_Access.SetMeasureFunction(m_Handle, func); + m_Access.SetOwner(m_Handle, func); + } + + public VisualElement GetOwner() + { + return m_Access.GetOwner(m_Handle); } /// @@ -263,6 +268,7 @@ public void Reset() Measure = null; Baseline = null; + SetOwner(null); Layout = LayoutComputedData.Default; Style = LayoutStyleData.Default; diff --git a/ModuleOverrides/com.unity.ui/Core/Layout/LayoutProcessor.cs b/ModuleOverrides/com.unity.ui/Core/Layout/LayoutProcessor.cs index 2f2eb9f3a0..85db42ce1b 100644 --- a/ModuleOverrides/com.unity.ui/Core/Layout/LayoutProcessor.cs +++ b/ModuleOverrides/com.unity.ui/Core/Layout/LayoutProcessor.cs @@ -2,7 +2,7 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using System; +using System; using System.Runtime.InteropServices; using Unity.Profiling; @@ -70,12 +70,13 @@ static void InvokeMeasureFunction( if (measureFunction == null) { + Debug.Assert(false, "Measure called on a null method"); result = default; return; } using (s_InvokeMeasureFunctionMarker.Auto()) - measureFunction(ref node, width, widthMode, height, heightMode, out result); + measureFunction(node.GetOwner(), ref node, width, widthMode, height, heightMode, out result); } [AOT.MonoPInvokeCallback(typeof(InvokeBaselineFunctionDelegate))] diff --git a/ModuleOverrides/com.unity.ui/Core/Layout/Model/Components/LayoutDataAccess.cs b/ModuleOverrides/com.unity.ui/Core/Layout/Model/Components/LayoutDataAccess.cs index e4012e8288..d9c9e3c382 100644 --- a/ModuleOverrides/com.unity.ui/Core/Layout/Model/Components/LayoutDataAccess.cs +++ b/ModuleOverrides/com.unity.ui/Core/Layout/Model/Components/LayoutDataAccess.cs @@ -75,6 +75,14 @@ public LayoutMeasureFunction GetMeasureFunction(LayoutHandle handle) public void SetMeasureFunction(LayoutHandle handle, LayoutMeasureFunction value) => LayoutManager.GetManager(m_Manager).SetMeasureFunction(handle, value); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public VisualElement GetOwner(LayoutHandle handle) + => LayoutManager.GetManager(m_Manager).GetOwner(handle); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetOwner(LayoutHandle handle, VisualElement value) + => LayoutManager.GetManager(m_Manager).SetOwner(handle, value); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public LayoutBaselineFunction GetBaselineFunction(LayoutHandle handle) => LayoutManager.GetManager(m_Manager).GetBaselineFunction(handle); diff --git a/ModuleOverrides/com.unity.ui/Core/Layout/Model/Components/LayoutNodeData.cs b/ModuleOverrides/com.unity.ui/Core/Layout/Model/Components/LayoutNodeData.cs index f1d9ecead8..88f1ef410a 100644 --- a/ModuleOverrides/com.unity.ui/Core/Layout/Model/Components/LayoutNodeData.cs +++ b/ModuleOverrides/com.unity.ui/Core/Layout/Model/Components/LayoutNodeData.cs @@ -2,7 +2,7 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; namespace UnityEngine.UIElements.Layout; @@ -15,6 +15,7 @@ struct LayoutNodeData public bool HasNewLayout; public int ManagedMeasureFunctionIndex; public int ManagedBaselineFunctionIndex; + public int ManagedOwnerIndex; public int LineIndex; public LayoutHandle Config; diff --git a/ModuleOverrides/com.unity.ui/Core/Panel.cs b/ModuleOverrides/com.unity.ui/Core/Panel.cs index 062053e241..061a959362 100644 --- a/ModuleOverrides/com.unity.ui/Core/Panel.cs +++ b/ModuleOverrides/com.unity.ui/Core/Panel.cs @@ -1179,10 +1179,21 @@ internal bool drawToCameras internal int targetDisplay { get; set;} - internal int screenRenderingWidth => targetDisplay > 0 && targetDisplay < Display.displays.Length - ? Display.displays[targetDisplay].renderingWidth : Screen.width; - internal int screenRenderingHeight => targetDisplay > 0 && targetDisplay < Display.displays.Length - ? Display.displays[targetDisplay].renderingHeight : Screen.height; + internal int screenRenderingWidth => getScreenRenderingWidth(targetDisplay); + internal int screenRenderingHeight => getScreenRenderingHeight(targetDisplay); + + // Expose common static method for getting the display/window resolution for calculation in the PanelSetting. + // Does not consider the gameView, so useless in the editor unless called directly after the render of a camera + internal static int getScreenRenderingHeight(int display) + { + return display >= 0 && display < Display.displays.Length ? Display.displays[display].renderingHeight : Screen.height; + } + + internal static int getScreenRenderingWidth(int display) + { + return display >= 0 && display < Display.displays.Length ? Display.displays[display].renderingWidth : Screen.width; + } + public override void Repaint(Event e) { diff --git a/ModuleOverrides/com.unity.ui/Core/Renderer/UIRElementBuilder.cs b/ModuleOverrides/com.unity.ui/Core/Renderer/UIRElementBuilder.cs index 3ad63733e8..e44f29078b 100644 --- a/ModuleOverrides/com.unity.ui/Core/Renderer/UIRElementBuilder.cs +++ b/ModuleOverrides/com.unity.ui/Core/Renderer/UIRElementBuilder.cs @@ -132,7 +132,7 @@ protected override void DrawVisualElementBackground(MeshGenerationContext mgc) return; var style = ve.computedStyle; - if (style.backgroundColor != Color.clear) + if (style.backgroundColor.a > UIRUtility.k_Epsilon) { // Draw solid color background var rectParams = new MeshGenerator.RectangleParams diff --git a/ModuleOverrides/com.unity.ui/Core/Renderer/UIRMeshGenerator.cs b/ModuleOverrides/com.unity.ui/Core/Renderer/UIRMeshGenerator.cs index 108a77312e..ecb22d0c24 100644 --- a/ModuleOverrides/com.unity.ui/Core/Renderer/UIRMeshGenerator.cs +++ b/ModuleOverrides/com.unity.ui/Core/Renderer/UIRMeshGenerator.cs @@ -1392,6 +1392,13 @@ void DrawSprite(RectangleParams rectParams) AdjustSpriteWinding(spriteVertices, spriteIndices, indices); + var colorPage = rectParams.colorPage; + var pageAndID = colorPage.pageAndID; + + var flags = new Color32(0, 0, 0, colorPage.isValid ? (byte)1 : (byte)0); + var page = new Color32(0, 0, colorPage.pageAndID.r, colorPage.pageAndID.g); + var ids = new Color32(0, 0, 0, colorPage.pageAndID.b); + for (int i = 0; i < vertexCount; ++i) { var v = spriteVertices[i]; @@ -1405,7 +1412,10 @@ void DrawSprite(RectangleParams rectParams) { position = new Vector3(v.x, v.y, Vertex.nearZ), tint = rectParams.color, - uv = spriteUV[i] + uv = spriteUV[i], + flags = flags, + opacityColorPages = page, + ids = ids }; } diff --git a/ModuleOverrides/com.unity.ui/Core/Renderer/UIRRenderChain.cs b/ModuleOverrides/com.unity.ui/Core/Renderer/UIRRenderChain.cs index 4b7be2c543..8ce5b02eea 100644 --- a/ModuleOverrides/com.unity.ui/Core/Renderer/UIRRenderChain.cs +++ b/ModuleOverrides/com.unity.ui/Core/Renderer/UIRRenderChain.cs @@ -43,6 +43,9 @@ class EntryPool : ImplicitPool { e.firstChild = null; e.nextSibling = null; + e.texture = null; + e.material = null; + e.gradientsOwner = null; }; public EntryPool(int maxCapacity = 1000) diff --git a/ModuleOverrides/com.unity.ui/Core/Renderer/UIRRenderEvents.cs b/ModuleOverrides/com.unity.ui/Core/Renderer/UIRRenderEvents.cs index f1f9db7380..a226096e71 100644 --- a/ModuleOverrides/com.unity.ui/Core/Renderer/UIRRenderEvents.cs +++ b/ModuleOverrides/com.unity.ui/Core/Renderer/UIRRenderEvents.cs @@ -538,6 +538,13 @@ static void OnColorChanged(RenderChain renderChain, VisualElement ve, uint dirty stats.colorUpdatesExpanded++; var newColor = ve.resolvedStyle.backgroundColor; + + // UUM-21405: Fully-transparent backgrounds don't generate any geometry. So, we need to + // force a dirty-repaint if we were transparent before, otherwise we may be trying to + // change the color of a mesh that doesn't exists. + if (ve.renderChainData.backgroundColor.a == 0.0f && newColor.a > 0.0f) + renderChain.UIEOnVisualsChanged(ve, false); + ve.renderChainData.backgroundColor = newColor; bool shouldUpdateVisuals = false; diff --git a/ModuleOverrides/com.unity.ui/Core/StyleEnums.cs b/ModuleOverrides/com.unity.ui/Core/StyleEnums.cs index ae9f1de8d7..0d0ed2ba42 100644 --- a/ModuleOverrides/com.unity.ui/Core/StyleEnums.cs +++ b/ModuleOverrides/com.unity.ui/Core/StyleEnums.cs @@ -7,7 +7,7 @@ namespace UnityEngine.UIElements { /// - /// Defaines how the position values are interpreted by the layout engine. + /// Defines how the position values are interpreted by the layout engine. /// public enum Position { @@ -16,18 +16,18 @@ public enum Position /// Relative = LayoutPositionType.Relative, /// - /// The element is positioned in relation to its parent box and does not contribute to the layout anymore. + /// The element is positioned in relation to its parent box and doesn't contribute to the layout anymore. /// Absolute = LayoutPositionType.Absolute, } /// - /// Defines what should happend if content overflows an element bounds. + /// Defines what should happened if content overflows an element bounds. /// public enum Overflow { /// - /// The overflow is not clipped. It renders outside the element's box. Default Value. + /// The overflow isn't clipped. It renders outside the element's box. Default Value. /// Visible = LayoutOverflow.Visible, /// @@ -101,7 +101,7 @@ public enum Wrap } /// - /// Defines the alignement behavior along an axis. + /// Defines the alignment behavior along an axis. /// public enum Align { @@ -199,7 +199,7 @@ public enum TextOverflow public enum TransformOriginOffset { /// - /// The origin of the transform operation is is set to the left of the element. + /// The origin of the transform operation is set to the left of the element. /// Left = 1, @@ -266,19 +266,19 @@ public enum DisplayStyle /// Flex = LayoutDisplay.Flex, /// - /// The element is not visible and absent from the layout. + /// The element isn't visible and absent from the layout. /// None = LayoutDisplay.None } /// - /// Defines the position of the background + /// Defines the position of the background. /// public enum BackgroundPositionKeyword { /// /// Vertical alignment is centered and/or Horizontal alignment is centered. - /// This is the default value to make sure it is backward compatible + /// This is the default value to make sure it's backward compatible /// with unity-background-scale-mode default value. /// Center = 0, @@ -305,7 +305,7 @@ public enum BackgroundPositionKeyword } /// - /// Defines the position of an element + /// Defines the position of an element. /// internal enum PositionProperty { @@ -331,71 +331,71 @@ internal enum PositionProperty } /// - /// Defines how the background is repeated + /// Defines how the background is repeated. /// public enum Repeat { /// - /// The background-image is not repeated. The image will only be shown once + /// The background-image isn't repeated. The image is only shown once. /// This is the default to keep background compatibility with - /// unity-background-scale-mode + /// unity-background-scale-mode. /// NoRepeat = 0, /// /// The background-image is repeated as much as possible without clipping. /// The first and last image is pinned to either side of the element, - /// and whitespace is distributed evenly between the images + /// and whitespace is distributed evenly between the images. /// Space = 1, /// - /// The background-image is repeated and squished or stretched to fill the space (no gaps) + /// The background-image is repeated and squished or stretched to fill the space (no gaps). /// Round = 2, /// /// The background image is repeated both vertically and horizontally. - /// The last image will be clipped if it does not fit. + /// The last image will be clipped if it doesn't fit. /// Repeat = 3, } /// - /// Defines how the background is repeated (one-value only) + /// Defines how the background is repeated (one-value only). /// internal enum RepeatXY { /// - /// The background image is repeated only horizontally + /// The background image is repeated horizontally. /// RepeatX = 0, /// - /// The background image is repeated only vertically + /// The background image is repeated vertically. /// RepeatY = 1, } /// - /// Defines the size of the background + /// Defines the size of the background. /// public enum BackgroundSizeType { /// /// Determines if the size of the background image comes from the - /// and length values + /// and length values. /// Length = 0, /// /// Resize the background image to cover the entire container, - /// even if it has to stretch the image or cut a little bit off one of the edges + /// even if it has to stretch the image or cut a little bit off one of the edges. /// Cover = 1, /// - /// Resize the background image to make sure the image is fully visible + /// Resize the background image to make sure the image is fully visible. /// Contain = 2, } diff --git a/ModuleOverrides/com.unity.ui/Core/Text/TextSelectingManipulator.cs b/ModuleOverrides/com.unity.ui/Core/Text/TextSelectingManipulator.cs index f33a0797ac..5a924aa4cd 100644 --- a/ModuleOverrides/com.unity.ui/Core/Text/TextSelectingManipulator.cs +++ b/ModuleOverrides/com.unity.ui/Core/Text/TextSelectingManipulator.cs @@ -87,6 +87,11 @@ internal bool HasSelection() return m_SelectingUtilities.hasSelection; } + internal bool HasFocus() + { + return m_TextElement.hasFocus; + } + internal void ExecuteDefaultActionAtTarget(EventBase evt) { switch (evt) @@ -160,7 +165,15 @@ void OnPointerDownEvent(PointerDownEvent evt) m_ConsecutiveMouseDownCount = 1; if (m_ConsecutiveMouseDownCount == 2 && m_TextElement.selection.doubleClickSelectsWord) + { + // We need to assign the correct cursor and select index to the current cursor position + // prior to selecting the current word. Because selectAllOnMouseUp is true, it'll always + // use a cursorIndex of 0. + if (cursorIndex == 0 && cursorIndex != selectIndex) + m_SelectingUtilities.MoveCursorToPosition_Internal(pointerPosition, evt.shiftKey); + m_SelectingUtilities.SelectCurrentWord(); + } else if (m_ConsecutiveMouseDownCount == 3 && m_TextElement.selection.tripleClickSelectsLine) m_SelectingUtilities.SelectCurrentParagraph(); else diff --git a/ModuleOverrides/com.unity.ui/Core/TextElement.cs b/ModuleOverrides/com.unity.ui/Core/TextElement.cs index f42eadbc06..f23499c16b 100644 --- a/ModuleOverrides/com.unity.ui/Core/TextElement.cs +++ b/ModuleOverrides/com.unity.ui/Core/TextElement.cs @@ -151,7 +151,6 @@ private void OnDetachFromPanel(DetachFromPanelEvent detachEvent) (detachEvent.originPanel as BaseVisualElementPanel)?.liveReloadSystem.UnregisterTextElement(this); } - [SerializeField, DontCreateProperty] private string m_Text = String.Empty; /// @@ -257,7 +256,7 @@ internal void OnGenerateVisualContent(MeshGenerationContext mgc) UpdateTooltip(); - if(selection.HasSelection()) + if(selection.HasSelection() && selectingManipulator.HasFocus()) DrawHighlighting(mgc); else if(!edition.isReadOnly && selection.isSelectable && selectingManipulator.RevealCursor()) DrawCaret(mgc); @@ -470,7 +469,8 @@ void INotifyValueChanged.SetValueWithoutNotify(string newValue) SaveViewData(); } - if (!edition.isReadOnly && editingManipulator?.editingUtilities.text != newValue) + // Always sync the manipulator if it exists even if the element is read-only or disabled. See issue UUM-8802 + if (editingManipulator != null) editingManipulator.editingUtilities.text = newValue; } } diff --git a/ModuleOverrides/com.unity.ui/Core/TextElementSelection.cs b/ModuleOverrides/com.unity.ui/Core/TextElementSelection.cs index 2187bcd500..7313369019 100644 --- a/ModuleOverrides/com.unity.ui/Core/TextElementSelection.cs +++ b/ModuleOverrides/com.unity.ui/Core/TextElementSelection.cs @@ -123,7 +123,7 @@ bool ITextSelection.isSelectable get => m_IsSelectable && focusable; set { - if (value == m_IsSelectable) + if (value == m_IsSelectable && value == focusable) return; focusable = value; diff --git a/ModuleOverrides/com.unity.ui/Core/UQuery.cs b/ModuleOverrides/com.unity.ui/Core/UQuery.cs index 71d922c471..747ca7cf76 100644 --- a/ModuleOverrides/com.unity.ui/Core/UQuery.cs +++ b/ModuleOverrides/com.unity.ui/Core/UQuery.cs @@ -523,7 +523,7 @@ public struct UQueryBuilder : IEquatable> where T : VisualEl /// /// Initializes a QueryBuilder. /// - /// The root element on which to condfuct the search query. + /// The root element on which to conduct the search query. public UQueryBuilder(VisualElement visualElement) : this() { diff --git a/ModuleOverrides/com.unity.ui/Core/VisualElement.cs b/ModuleOverrides/com.unity.ui/Core/VisualElement.cs index 2fce78e205..0a91abc04c 100644 --- a/ModuleOverrides/com.unity.ui/Core/VisualElement.cs +++ b/ModuleOverrides/com.unity.ui/Core/VisualElement.cs @@ -1393,6 +1393,8 @@ void WillChangePanel(BaseVisualElementPanel destinationPanel) EventDispatchUtilities.HandleEventAtTargetAndDefaultPhase(e, elementPanel, this); } } + + panel.dispatcher.m_ClickDetector.Cleanup(this); } UnregisterRunningAnimations(); @@ -1862,12 +1864,14 @@ internal bool requireMeasureFunction private void AssignMeasureFunction() { - LayoutManager.SharedManager.SetMeasureFunction(layoutNode.Handle, Measure); + layoutNode.SetOwner(this); + layoutNode.Measure = Measure; } private void RemoveMeasureFunction() { - layoutNode.SetMeasureFunction(null); + layoutNode.Measure = null; + layoutNode.SetOwner(null); } /// @@ -1877,11 +1881,12 @@ protected internal virtual Vector2 DoMeasure(float desiredWidth, MeasureMode wid return new Vector2(float.NaN, float.NaN); } - internal void Measure(ref LayoutNode node, float width, LayoutMeasureMode widthMode, float height, LayoutMeasureMode heightMode, out LayoutSize result) + internal static void Measure(VisualElement ve, ref LayoutNode node, float width, LayoutMeasureMode widthMode, float height, LayoutMeasureMode heightMode, out LayoutSize result) { - Debug.Assert(node.Equals(layoutNode), "LayoutNode instance mismatch"); - Vector2 size = DoMeasure(width, (MeasureMode)widthMode, height, (MeasureMode)heightMode); - float ppp = scaledPixelsPerPoint; + result = default; + Debug.Assert(node.Equals(ve.layoutNode), "LayoutNode instance mismatch"); + Vector2 size = ve.DoMeasure(width, (MeasureMode)widthMode, height, (MeasureMode)heightMode); + float ppp = ve.scaledPixelsPerPoint; result = new LayoutSize(AlignmentUtils.RoundToPixelGrid(size.x, ppp), AlignmentUtils.RoundToPixelGrid(size.y, ppp)); } diff --git a/ModuleOverrides/com.unity.ui/Core/VisualElementTooltip.cs b/ModuleOverrides/com.unity.ui/Core/VisualElementTooltip.cs index 5670c1c6b6..053fb83e4d 100644 --- a/ModuleOverrides/com.unity.ui/Core/VisualElementTooltip.cs +++ b/ModuleOverrides/com.unity.ui/Core/VisualElementTooltip.cs @@ -20,7 +20,7 @@ public partial class VisualElement internal static readonly PropertyName tooltipPropertyKey = new PropertyName("--unity-tooltip"); /// - /// Text to display inside an information box after the user hovers the element for a small amount of time. + /// Text to display inside an information box after the user hovers the element for a small amount of time. This is only supported in the Editor UI. /// [CreateProperty] public string tooltip diff --git a/ModuleOverrides/com.unity.ui/Editor/Bindings/BindingStyleHelpers.cs b/ModuleOverrides/com.unity.ui/Editor/Bindings/BindingStyleHelpers.cs index 5975e0c67a..abce7c17a6 100644 --- a/ModuleOverrides/com.unity.ui/Editor/Bindings/BindingStyleHelpers.cs +++ b/ModuleOverrides/com.unity.ui/Editor/Bindings/BindingStyleHelpers.cs @@ -203,6 +203,13 @@ internal static void UpdateLivePropertyStateStyle(VisualElement element, Seriali UpdateElementRecursively(element, prop, UpdateLivePropertyStyleFromProperty); } + static bool ComponentIsPrefabOverride(Component comp) + { + return comp != null && + PrefabUtility.GetCorrespondingConnectedObjectFromSource(comp.gameObject) != null && + PrefabUtility.GetCorrespondingObjectFromSource(comp) == null; + } + private static void UpdatePrefabStateStyleFromProperty(VisualElement element, SerializedProperty prop) { bool handlePrefabState = false; @@ -212,9 +219,9 @@ private static void UpdatePrefabStateStyleFromProperty(VisualElement element, Se // This can throw if the serialized object changes type under our feet handlePrefabState = prop.serializedObject.targetObjects.Length == 1 && prop.isInstantiatedPrefab && - prop.prefabOverride; + (prop.prefabOverride || ComponentIsPrefabOverride(prop.serializedObject.targetObject as Component)); } - catch (Exception) + catch { return; } @@ -306,9 +313,10 @@ private static void UpdatePrefabOverrideOrLivePropertyBarStyle(VisualElement bar // bars touch (and it looks like one long bar). They normally wouldn't // because most fields have a small margin. var bottomOffset = element.resolvedStyle.marginBottom; + var topOffset = element.resolvedStyle.marginTop; - bar.style.top = top; - bar.style.height = elementHeight + bottomOffset; + bar.style.top = top - topOffset; + bar.style.height = elementHeight + bottomOffset + topOffset; bar.style.left = 0.0f; } @@ -328,6 +336,17 @@ private static void UpdatePrefabOverrideOrLivePropertyBarStyleEvent(GeometryChan if (barContainer == null) return; + // If the userData parent has been removed then we should remove all bars as the component has been removed. + for (var i = 0; i < barContainer.childCount; i++) + { + var element = barContainer[i].userData as VisualElement; + if (FindPrefabOverrideOrLivePropertyBarCompatibleParent(element) == null) + { + barContainer.RemoveFromHierarchy(); + return; + } + } + for (var i = 0; i < barContainer.childCount; i++) UpdatePrefabOverrideOrLivePropertyBarStyle(barContainer[i]); } diff --git a/ModuleOverrides/com.unity.ui/Editor/Bindings/EditorListViewController.cs b/ModuleOverrides/com.unity.ui/Editor/Bindings/EditorListViewController.cs index c78fb592de..e8d0906a04 100644 --- a/ModuleOverrides/com.unity.ui/Editor/Bindings/EditorListViewController.cs +++ b/ModuleOverrides/com.unity.ui/Editor/Bindings/EditorListViewController.cs @@ -75,6 +75,8 @@ public override void RemoveItems(List indices) { indices.Sort(); + RaiseItemsRemoved(indices); + for (var i = indices.Count - 1; i >= 0; i--) { var index = indices[i]; @@ -88,8 +90,6 @@ public override void RemoveItems(List indices) serializedObjectList.RemoveAt(index); } - RaiseItemsRemoved(indices); - serializedObjectList.ApplyChanges(); RaiseOnSizeChanged(); } @@ -102,18 +102,14 @@ public override void RemoveItem(int index) index--; } - serializedObjectList.RemoveAt(index); - serializedObjectList.ApplyChanges(); - var indices = ListPool.Get(); - try + using (ListPool.Get(out var indices)) { indices.Add(index); RaiseItemsRemoved(indices); } - finally - { - ListPool.Release(indices); - } + + serializedObjectList.RemoveAt(index); + serializedObjectList.ApplyChanges(); RaiseOnSizeChanged(); } diff --git a/ModuleOverrides/com.unity.ui/Editor/Delegates/EditorDelegateRegistration.cs b/ModuleOverrides/com.unity.ui/Editor/Delegates/EditorDelegateRegistration.cs index 213e3dc73c..fbdd16f90b 100644 --- a/ModuleOverrides/com.unity.ui/Editor/Delegates/EditorDelegateRegistration.cs +++ b/ModuleOverrides/com.unity.ui/Editor/Delegates/EditorDelegateRegistration.cs @@ -22,6 +22,16 @@ static EditorDelegateRegistration() PanelSettings.CreateRuntimePanelDebug = UIElementsEditorRuntimeUtility.CreateRuntimePanelDebug; PanelSettings.GetOrCreateDefaultTheme = PanelSettingsCreator.GetOrCreateDefaultTheme; + PanelSettings.GetGameViewResolution = (int display) => + { + foreach (var playModeView in PlayModeView.GetAllPlayModeViewWindows()) + { + if (playModeView.targetDisplay == display) + return playModeView.targetSize; + } + return new(Display.main.renderingWidth, Display.main.renderingHeight); + }; + DropdownUtility.MakeDropdownFunc = CreateGenericOSMenu; PanelSettings.SetPanelSettingsAssetDirty = EditorUtility.SetDirty; } diff --git a/Modules/AndroidJNI/AndroidApp.bindings.cs b/Modules/AndroidJNI/AndroidApp.bindings.cs new file mode 100644 index 0000000000..998ce27922 --- /dev/null +++ b/Modules/AndroidJNI/AndroidApp.bindings.cs @@ -0,0 +1,35 @@ +// 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.Bindings; + +namespace UnityEngine.Android +{ + [NativeHeader("Modules/AndroidJNI/Public/AndroidApp.bindings.h")] + [StaticAccessor("AndroidApp", StaticAccessorType.DoubleColon)] + [NativeConditional("PLATFORM_ANDROID")] + internal static class AndroidApp + { + private static AndroidJavaObject m_Activity; + + public static AndroidJavaObject Activity + { + get + { + if (m_Activity != null) + return m_Activity; + + using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) + { + m_Activity = unityPlayer.GetStatic("currentActivity"); + } + + return m_Activity; + } + } + + public static extern IntPtr UnityPlayerRaw { [ThreadSafe] get; } + } +} diff --git a/Modules/AndroidJNI/AndroidCommon.cs b/Modules/AndroidJNI/AndroidCommon.cs deleted file mode 100644 index d500be1f8f..0000000000 --- a/Modules/AndroidJNI/AndroidCommon.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - - -namespace UnityEngine.Android -{ - internal static class Common - { - private static AndroidJavaObject m_Activity; - - public static AndroidJavaObject GetActivity() - { - if (m_Activity != null) - return m_Activity; - - using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) - { - m_Activity = unityPlayer.GetStatic("currentActivity"); - } - - return m_Activity; - } - } -} diff --git a/Modules/AndroidJNI/AndroidJNI.bindings.cs b/Modules/AndroidJNI/AndroidJNI.bindings.cs index 5827c4c77d..1d7aa13353 100644 --- a/Modules/AndroidJNI/AndroidJNI.bindings.cs +++ b/Modules/AndroidJNI/AndroidJNI.bindings.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEngine; +using UnityEngine.Android; using UnityEngine.Bindings; using UnityEngine.Scripting; using Unity.Collections; @@ -106,7 +107,7 @@ public static IntPtr CreateJavaProxy(AndroidJavaProxy proxy) var handle = GCHandle.Alloc(proxy); try { - return _AndroidJNIHelper.CreateJavaProxy(GCHandle.ToIntPtr(handle), proxy); + return _AndroidJNIHelper.CreateJavaProxy(AndroidApp.UnityPlayerRaw, GCHandle.ToIntPtr(handle), proxy); } catch { diff --git a/Modules/AndroidJNI/AndroidJava.cs b/Modules/AndroidJNI/AndroidJava.cs index 044ce7c66a..7cbe99180a 100644 --- a/Modules/AndroidJNI/AndroidJava.cs +++ b/Modules/AndroidJNI/AndroidJava.cs @@ -1061,7 +1061,7 @@ private static IntPtr GetMethodID(string clazz, string methodName, string signat private static readonly IntPtr s_ReflectionHelperGetMethodID = GetStaticMethodID(RELECTION_HELPER_CLASS_NAME, "getMethodID", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/reflect/Method;"); private static readonly IntPtr s_ReflectionHelperGetFieldID = GetStaticMethodID(RELECTION_HELPER_CLASS_NAME, "getFieldID", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/reflect/Field;"); private static readonly IntPtr s_ReflectionHelperGetFieldSignature = GetStaticMethodID(RELECTION_HELPER_CLASS_NAME, "getFieldSignature", "(Ljava/lang/reflect/Field;)Ljava/lang/String;"); - private static readonly IntPtr s_ReflectionHelperNewProxyInstance = GetStaticMethodID(RELECTION_HELPER_CLASS_NAME, "newProxyInstance", "(JLjava/lang/Class;)Ljava/lang/Object;"); + private static readonly IntPtr s_ReflectionHelperNewProxyInstance = GetStaticMethodID(RELECTION_HELPER_CLASS_NAME, "newProxyInstance", "(Lcom/unity3d/player/UnityPlayer;JLjava/lang/Class;)Ljava/lang/Object;"); private static readonly IntPtr s_ReflectionHelperSetNativeExceptionOnProxy = GetStaticMethodID(RELECTION_HELPER_CLASS_NAME, "setNativeExceptionOnProxy", "(Ljava/lang/Object;JZ)V"); private static readonly IntPtr s_FieldGetDeclaringClass = GetMethodID("java/lang/reflect/Field", "getDeclaringClass", "()Ljava/lang/Class;"); @@ -1128,11 +1128,12 @@ public static string GetFieldSignature(IntPtr field) return AndroidJNISafe.CallStaticStringMethod(s_ReflectionHelperClass, s_ReflectionHelperGetFieldSignature, jniArgs); } - public static IntPtr NewProxyInstance(IntPtr delegateHandle, IntPtr interfaze) + public static IntPtr NewProxyInstance(IntPtr player, IntPtr delegateHandle, IntPtr interfaze) { - jvalue[] jniArgs = new jvalue[2]; - jniArgs[0].j = delegateHandle.ToInt64(); - jniArgs[1].l = interfaze; + jvalue[] jniArgs = new jvalue[3]; + jniArgs[0].l = player; + jniArgs[1].j = delegateHandle.ToInt64(); + jniArgs[2].l = interfaze; return AndroidJNISafe.CallStaticObjectMethod(s_ReflectionHelperClass, s_ReflectionHelperNewProxyInstance, jniArgs); } @@ -1149,9 +1150,9 @@ public static void SetNativeExceptionOnProxy(IntPtr proxy, Exception e, bool met [UsedByNativeCode] sealed class _AndroidJNIHelper { - public static IntPtr CreateJavaProxy(IntPtr delegateHandle, AndroidJavaProxy proxy) + public static IntPtr CreateJavaProxy(IntPtr player, IntPtr delegateHandle, AndroidJavaProxy proxy) { - return AndroidReflection.NewProxyInstance(delegateHandle, proxy.javaInterface.GetRawClass()); + return AndroidReflection.NewProxyInstance(player, delegateHandle, proxy.javaInterface.GetRawClass()); } public static IntPtr CreateJavaRunnable(AndroidJavaRunnable jrunnable) diff --git a/Modules/Animation/ScriptBindings/Animation.bindings.cs b/Modules/Animation/ScriptBindings/Animation.bindings.cs index a96a93427f..2e19baf371 100644 --- a/Modules/Animation/ScriptBindings/Animation.bindings.cs +++ b/Modules/Animation/ScriptBindings/Animation.bindings.cs @@ -307,8 +307,13 @@ internal unsafe static void DisposeEvents(IntPtr animationEventBlittableArray, i { animationEventsBlittable[i].Dispose(); } + + FreeEventsInternal(animationEventBlittableArray); } + [FreeFunction(Name = "AnimationClipBindings::FreeEventsInternal")] + extern static private void FreeEventsInternal(IntPtr value); + [ThreadStatic] static GCHandlePool s_handlePool; diff --git a/Modules/Animation/ScriptBindings/Animator.bindings.cs b/Modules/Animation/ScriptBindings/Animator.bindings.cs index 0465aeb130..5bc2054ae3 100644 --- a/Modules/Animation/ScriptBindings/Animator.bindings.cs +++ b/Modules/Animation/ScriptBindings/Animator.bindings.cs @@ -1237,6 +1237,12 @@ extern public bool keepAnimatorStateOnDisable set; } + extern public bool writeDefaultValuesOnDisable + { + get; + set; + } + [Obsolete("GetVector is deprecated.")] public Vector3 GetVector(string name) { return Vector3.zero; } [Obsolete("GetVector is deprecated.")] diff --git a/Modules/AssetDatabase/Editor/ScriptBindings/AssetDatabase.bindings.cs b/Modules/AssetDatabase/Editor/ScriptBindings/AssetDatabase.bindings.cs index 88235aa243..1de6a33be9 100644 --- a/Modules/AssetDatabase/Editor/ScriptBindings/AssetDatabase.bindings.cs +++ b/Modules/AssetDatabase/Editor/ScriptBindings/AssetDatabase.bindings.cs @@ -130,7 +130,7 @@ public partial class AssetDatabase // rootFolder is true if the path is a registered root folder // immutable is true when the root of the path was registered with the immutable flag (e.g. shared package) // asset folders marked immutable are not modified by the asset database - extern internal static bool GetAssetFolderInfo(string path, out bool rootFolder, out bool immutable); + extern public static bool TryGetAssetFolderInfo(string path, out bool rootFolder, out bool immutable); public static bool Contains(Object obj) { return Contains(obj.GetInstanceID()); } extern public static bool Contains(int instanceID); @@ -725,7 +725,7 @@ public static void ForceReserializeAssets(IEnumerable assetPaths, ForceR continue; bool rootFolder, readOnly; - bool validPath = GetAssetFolderInfo(path, out rootFolder, out readOnly); + bool validPath = TryGetAssetFolderInfo(path, out rootFolder, out readOnly); if (validPath && (rootFolder || readOnly)) continue; diff --git a/Modules/GridAndSnap/LinkedVector3Field.cs b/Modules/GridAndSnap/LinkedVector3Field.cs index a9e2db7231..a02aff5ee5 100644 --- a/Modules/GridAndSnap/LinkedVector3Field.cs +++ b/Modules/GridAndSnap/LinkedVector3Field.cs @@ -15,6 +15,7 @@ class LinkedVector3Field : Vector3Field bool m_Linked; readonly VisualElement m_LinkedToggle; + readonly FloatField m_XField; readonly FloatField m_YField; readonly FloatField m_ZField; @@ -49,7 +50,7 @@ public LinkedVector3Field(string label) : base(label) ? "StyleSheets/SceneViewToolbarElements/LinkedVector3FieldDark.uss" : "StyleSheets/SceneViewToolbarElements/LinkedVector3FieldLight.uss")); - var xField = this.Q("unity-x-input"); + m_XField = this.Q("unity-x-input"); m_YField = this.Q("unity-y-input"); m_ZField = this.Q("unity-z-input"); @@ -60,6 +61,17 @@ public LinkedVector3Field(string label) : base(label) UpdateLinkedState(); } + public bool isDelayed + { + get => m_XField.isDelayed; + set + { + m_XField.isDelayed = value; + m_YField.isDelayed = value; + m_ZField.isDelayed = value; + } + } + void UpdateLinkedState() { if (linked) diff --git a/Modules/GridAndSnap/SnapSettingsWindow.cs b/Modules/GridAndSnap/SnapSettingsWindow.cs index 6c5a3d0aca..24306383a8 100644 --- a/Modules/GridAndSnap/SnapSettingsWindow.cs +++ b/Modules/GridAndSnap/SnapSettingsWindow.cs @@ -51,7 +51,7 @@ protected override void OnEnable() rootVisualElement.Add(new SnapSettingsHeader(L10n.Tr("Grid Snapping"), ResetValues)); - m_GridSize = new LinkedVector3Field(L10n.Tr("Grid Size")) { name = "GridSize" }; + m_GridSize = new LinkedVector3Field(L10n.Tr("Grid Size")) { name = "GridSize", isDelayed = true}; m_GridSize.value = GridSettings.size; m_GridSize.linked = Mathf.Approximately(m_GridSize.value.x, m_GridSize.value.y) && Mathf.Approximately(m_GridSize.value.x, m_GridSize.value.z); GridSettings.sizeChanged += (value) => m_GridSize.SetValueWithoutNotify(value); diff --git a/Modules/IMGUI/GUI.cs b/Modules/IMGUI/GUI.cs index 61e99c6f28..0643213521 100644 --- a/Modules/IMGUI/GUI.cs +++ b/Modules/IMGUI/GUI.cs @@ -607,11 +607,7 @@ internal static void DoTextField(Rect position, int id, GUIContent content, bool editor.controlID = id; editor.DetectFocusChange(); - if (TouchScreenKeyboard.isRequiredToForceOpen) - { - HandleTextFieldEventForDesktopWithForcedKeyboard(position, id, content, multiline, maxLength, style, secureText, editor); - } - else if (TouchScreenKeyboard.isSupported && !TouchScreenKeyboard.isInPlaceEditingAllowed) + if (TouchScreenKeyboard.isSupported && !TouchScreenKeyboard.isInPlaceEditingAllowed) { HandleTextFieldEventForTouchscreen(position, id, content, multiline, maxLength, style, secureText, maskChar, editor); } @@ -814,62 +810,6 @@ private static void HandleTextFieldEventForDesktop(Rect position, int id, GUICon } } - private static void HandleTextFieldEventForDesktopWithForcedKeyboard(Rect position, int id, GUIContent content, bool multiline, int maxLength, GUIStyle style, string secureText, TextEditor editor) - { - // On certain platforms, the TouchScreenKeyboard must always be "open" in order to receive text events. The keyboard.active state signals - // the platform to switch between "text input" and "key input" modes; unlike other platforms only one of these modes is active at a time. - // Therefore, TextField must open the keyboard when it has focus and deactivate it when it loses focus. - - bool openKeyboard = false; - - // Due to the asynchronous behavior of the platform's APIs (race conditions) we cannot guarantee the keyboard will land in the correct state - // simply by responding to mouse and keyboard events. Instead we must check the keyboard state matches the UI focus state every - // frame and make changes when necessary. - if (Event.current.type == EventType.Repaint) - { - // Disable keyboard for previously active text field, if any - if (s_HotTextField != -1 && s_HotTextField != id) - { - TextEditor currentEditor = (TextEditor)GUIUtility.GetStateObject(typeof(TextEditor), s_HotTextField); - currentEditor.keyboardOnScreen.active = false; - currentEditor.keyboardOnScreen = null; - } - - if (editor.keyboardOnScreen != null) - { - if (GUIUtility.keyboardControl != id || !Application.isFocused) - { - // Text field isn't focused; reset keyboard reference - editor.keyboardOnScreen.active = false; - editor.keyboardOnScreen = null; - } - else if (!editor.keyboardOnScreen.active) - { - // UI is focused and keyboard is valid, but it's inactive for some reason; need to re-open it - openKeyboard = true; - } - } - else if (GUIUtility.keyboardControl == id && Application.isFocused) - { - // Text field is focused but don't have a valid Keyboard; need to open it - openKeyboard = true; - } - } - - if (openKeyboard) - { - editor.keyboardOnScreen = TouchScreenKeyboard.Open( - secureText ?? content.text, - TouchScreenKeyboardType.Default, - true, - multiline, - (secureText != null)); - } - - // Continue processing the event normally for Desktop - HandleTextFieldEventForDesktop(position, id, content, multiline, maxLength, style, editor); - } - public static bool Toggle(Rect position, bool value, string text) { return Toggle(position, value, GUIContent.Temp(text), s_Skin.toggle); diff --git a/Modules/IMGUI/GUIStyle.cs b/Modules/IMGUI/GUIStyle.cs index 86db082cfc..c3bbea5fb5 100644 --- a/Modules/IMGUI/GUIStyle.cs +++ b/Modules/IMGUI/GUIStyle.cs @@ -411,7 +411,7 @@ public static implicit operator GUIStyle(string str) // Get the pixel position of a given string index. public Vector2 GetCursorPixelPosition(Rect position, GUIContent content, int cursorStringIndex) { - var handle = IMGUITextHandle.GetTextHandle(this, padding.Remove(position), content.textWithWhitespace, Color.white, true); + var handle = IMGUITextHandle.GetTextHandle(this, padding.Remove(position), content.textWithWhitespace, Color.white); var cursorPos = handle.GetCursorPositionFromStringIndexUsingLineHeight(cursorStringIndex); cursorPos = new Vector2(Mathf.Max(0.0f, cursorPos.x), cursorPos.y); var rectOffset = Internal_GetTextRectOffset(position, content, new Vector2(handle.preferredSize.x, handle.preferredSize.y > 0 ? handle.preferredSize.y : lineHeight)); @@ -427,13 +427,13 @@ internal Rect[] GetHyperlinkRects(IMGUITextHandle handle, Rect content) // Get the cursor position (indexing into contents.text) when the user clicked at cursorPixelPosition public int GetCursorStringIndex(Rect position, GUIContent content, Vector2 cursorPixelPosition) { - return IMGUITextHandle.GetTextHandle(this, position, content.textWithWhitespace, Color.white, true).GetCursorIndexFromPosition(cursorPixelPosition); + return IMGUITextHandle.GetTextHandle(this, position, content.textWithWhitespace, Color.white).GetCursorIndexFromPosition(cursorPixelPosition); } // Returns number of characters that can fit within width, returns -1 if fails due to missing font internal int GetNumCharactersThatFitWithinWidth(string text, float width) { - return IMGUITextHandle.GetTextHandle(this, new Rect(0, 0, width, 1), text, Color.white, true).GetNumCharactersThatFitWithinWidth(width); + return IMGUITextHandle.GetTextHandle(this, new Rect(0, 0, width, 1), text, Color.white).GetNumCharactersThatFitWithinWidth(width); } // Calculate the size of a some content if it is rendered with this style. @@ -466,7 +466,7 @@ public float CalcHeight(GUIContent content, float width) internal Vector2 GetPreferredSize(string content, Rect rect) { - return IMGUITextHandle.GetTextHandle(this, padding.Remove(rect), content, Color.white, true).GetPreferredSize(); + return IMGUITextHandle.GetTextHandle(this, padding.Remove(rect), content, Color.white).GetPreferredSize(); } public bool isHeightDependantOnWidth => fixedHeight == 0 && (wordWrap && imagePosition != ImagePosition.ImageOnly); @@ -523,8 +523,7 @@ public enum TextClipping Overflow = 0, // Text gets clipped to be inside the element. Clip = 1, - // Text gets truncated with dots to show it is too long - // Truncate = 2 + Ellipsis = 2, } } diff --git a/Modules/IMGUI/IMGUITextHandle.cs b/Modules/IMGUI/IMGUITextHandle.cs index 980e622229..9b5a0ca113 100644 --- a/Modules/IMGUI/IMGUITextHandle.cs +++ b/Modules/IMGUI/IMGUITextHandle.cs @@ -5,12 +5,15 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using UnityEngine.TextCore.Text; namespace UnityEngine { internal class IMGUITextHandle : TextHandle { + internal LinkedListNode tuple; + const float sFallbackFontSize = 13; const float sTimeToFlush = 1.0f; const string kDefaultFontName = "LegacyRuntime.ttf"; @@ -21,54 +24,79 @@ internal class IMGUITextHandle : TextHandle private static IMGUITextHandle s_TextHandle = new IMGUITextHandle(); - private static List textHandles = new List(); + private static Dictionary textHandles = new Dictionary(); + private static LinkedList textHandlesTuple = new LinkedList(); + private static float lastCleanupTime; + + internal class TextHandleTuple + { + public TextHandleTuple(float lastTimeUsed, int hashCode) + { + this.hashCode = hashCode; + this.lastTimeUsed = lastTimeUsed; + } + + public float lastTimeUsed; + public int hashCode; + } internal static void EmptyCache() { GUIStyle.Internal_CleanupAllTextGenerator(); textHandles.Clear(); + textHandlesTuple.Clear(); } - internal static IMGUITextHandle GetTextHandle(GUIStyle style, Rect position, string content, Color32 textColor, bool isOnlyForGeometry = false) + internal static IMGUITextHandle GetTextHandle(GUIStyle style, Rect position, string content, Color32 textColor) { var settings = new TextCore.Text.TextGenerationSettings(); ConvertGUIStyleToGenerationSettings(settings, style, textColor, content, position); - return GetTextHandle(settings, isOnlyForGeometry); + return GetTextHandle(settings); } - private static IMGUITextHandle GetTextHandle(TextCore.Text.TextGenerationSettings settings, bool isOnlyForGeometry) + private static void ClearUnusedTextHandles() { var currentTime = Time.realtimeSinceStartup; - bool isCached = false; - IMGUITextHandle textHandleCached = null; - int hash = isOnlyForGeometry ? settings.cachedGeomertyHashCode : settings.cachedHashCode; - - for (int i = textHandles.Count - 1; i >= 0; i--) + while (textHandlesTuple.Count > 0) { - var textHandle = textHandles[i]; - var hash2 = isOnlyForGeometry ? textHandle.textGenerationSettings.cachedGeomertyHashCode : textHandle.textGenerationSettings.cachedHashCode; - if (hash == hash2) + var tuple = textHandlesTuple.First(); + if (currentTime - tuple.lastTimeUsed > sTimeToFlush) { - textHandleCached = textHandle; - textHandle.lastTimeUsed = currentTime; - isCached = true; + GUIStyle.Internal_DestroyTextGenerator(tuple.hashCode); + textHandles.Remove(tuple.hashCode); + textHandlesTuple.RemoveFirst(); } + else + break; + } + } - if (currentTime - textHandle.lastTimeUsed > sTimeToFlush) - { - GUIStyle.Internal_DestroyTextGenerator(textHandle.textGenerationSettings.cachedHashCode); - textHandles.RemoveAt(i); - } + private static IMGUITextHandle GetTextHandle(TextCore.Text.TextGenerationSettings settings) + { + var currentTime = Time.realtimeSinceStartup; + if (currentTime - lastCleanupTime > sTimeToFlush) + { + ClearUnusedTextHandles(); + lastCleanupTime = currentTime; } - if (isCached) + int hash = settings.cachedHashCode; + + if (textHandles.TryGetValue(hash, out IMGUITextHandle textHandleCached)) + { + textHandlesTuple.Remove(textHandleCached.tuple); + textHandlesTuple.AddLast(textHandleCached.tuple); return textHandleCached; + } var handle = new IMGUITextHandle(); - handle.lastTimeUsed = currentTime; - textHandles.Add(handle); + var tuple = new TextHandleTuple(currentTime, hash); + var listNode = new LinkedListNode(tuple); + handle.tuple = listNode; + textHandles[hash] = handle; handle.Update(settings); handle.UpdatePreferredSize(settings); + textHandlesTuple.AddLast(listNode); return handle; } @@ -79,7 +107,6 @@ internal static float GetLineHeight(GUIStyle style) return GetLineHeightDefault(settings); } - internal TextInfo GetTextInfo(ref int id) { id = textGenerationSettings.cachedHashCode; @@ -161,6 +188,7 @@ private static void ConvertGUIStyleToGenerationSettings(UnityEngine.TextCore.Tex settings.fontStyle = TextGeneratorUtilities.LegacyStyleToNewStyle(style.fontStyle); settings.textAlignment = TextGeneratorUtilities.LegacyAlignmentToNewAlignment(tempAlignment); + settings.overflowMode = LegacyClippingToNewOverflow(style.clipping); settings.wordWrap = rect.width > 0 ? style.wordWrap : false; settings.wordWrappingRatio = 0.4f; settings.richText = style.richText; @@ -173,14 +201,28 @@ private static void ConvertGUIStyleToGenerationSettings(UnityEngine.TextCore.Tex else settings.fontSize = sFallbackFontSize; - settings.overflowMode = TextOverflowMode.Overflow; settings.characterSpacing = 0; settings.wordSpacing = 0; settings.paragraphSpacing = 0; settings.color = textColor; settings.inverseYAxis = true; + settings.isIMGUI = true; settings.shouldConvertToLinearSpace = false; } + + static TextOverflowMode LegacyClippingToNewOverflow(TextClipping clipping) + { + switch (clipping) + { + case TextClipping.Clip: + return TextOverflowMode.Masking; + case TextClipping.Ellipsis: + return TextOverflowMode.Ellipsis; + case TextClipping.Overflow: + default: + return TextOverflowMode.Overflow; + } + } } } diff --git a/Modules/IMGUI/TextEditor.cs b/Modules/IMGUI/TextEditor.cs index 88bf4cc4ae..0e7d938889 100644 --- a/Modules/IMGUI/TextEditor.cs +++ b/Modules/IMGUI/TextEditor.cs @@ -141,7 +141,7 @@ public enum DblClickSnapping : byte { WORDS, PARAGRAPHS } public TextEditor() { var style = GUIStyle.none; - m_TextHandle = new IMGUITextHandle(); + m_TextHandle = IMGUITextHandle.GetTextHandle(style, position, textWithWhitespace, Color.white); m_TextSelecting = new TextSelectingUtilities(m_TextHandle); m_TextEditing = new TextEditingUtilities(m_TextSelecting, m_TextHandle, m_Content.text); m_Content.OnTextChanged += OnContentTextChangedHandle; @@ -204,6 +204,10 @@ public bool HasClickedOnHREF(Vector2 mousePosition, out string href) if (link.linkId != null && link.linkIdLength > 0) { href = new string(link.linkId); + if (!href.StartsWith("href")) + return false; + // Removes href="..." + href = href.Substring(6, href.Length - 7); if (Uri.IsWellFormedUriString(href, UriKind.Absolute)) { return true; @@ -408,7 +412,7 @@ public void UpdateScrollOffsetIfNeeded(Event evt) internal void UpdateTextHandle() { - m_TextHandle = IMGUITextHandle.GetTextHandle(style, style.padding.Remove(position), textWithWhitespace, Color.white, true); + m_TextHandle = IMGUITextHandle.GetTextHandle(style, style.padding.Remove(position), textWithWhitespace, Color.white); m_TextEditing.textHandle = m_TextHandle; m_TextSelecting.textHandle = m_TextHandle; } diff --git a/Modules/IMGUI/TextSelectingUtilities.cs b/Modules/IMGUI/TextSelectingUtilities.cs index c8824961f3..4c05697dc3 100644 --- a/Modules/IMGUI/TextSelectingUtilities.cs +++ b/Modules/IMGUI/TextSelectingUtilities.cs @@ -52,7 +52,6 @@ public int cursorIndex if (m_CursorIndex != value) { m_CursorIndex = value; - revealCursor = true; OnCursorIndexChange?.Invoke(); } } @@ -65,7 +64,6 @@ internal int cursorIndexNoValidation if (m_CursorIndex != value) { SetCursorIndexWithoutNotify(value); - revealCursor = true; OnCursorIndexChange?.Invoke(); } } diff --git a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadManager.cs b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadManager.cs index 920fe311c6..cc6aebbb5e 100644 --- a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadManager.cs +++ b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadManager.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using UnityEditorInternal; +using UnityEditor.Utils; using UnityEngine; namespace UnityEditor.PackageManager.UI.Internal @@ -195,9 +196,8 @@ private void SetupDownloadOperation(AssetStoreDownloadOperation operation) private void OnDownloadFinalized(AssetStoreDownloadOperation operation) { onDownloadFinalized?.Invoke(operation); - if (operation.state == DownloadState.Completed && - !string.IsNullOrEmpty(operation.packageOldPath) && operation.packageNewPath != operation.packageOldPath) + !string.IsNullOrEmpty(operation.packageOldPath) && operation.packageNewPath.NormalizePath() != operation.packageOldPath.NormalizePath()) { m_IOProxy.DeleteFile(operation.packageOldPath); } diff --git a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreRestAPI.cs b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreRestAPI.cs index fd5352e811..e7640b2c66 100644 --- a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreRestAPI.cs +++ b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreRestAPI.cs @@ -50,7 +50,8 @@ internal class AssetStoreRestAPI "Essentials", "Templates", "Tools", - "VFX" + "VFX", + "Web3" }; private string m_Host; diff --git a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreVersionList.cs b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreVersionList.cs index 7db8d277c5..736aa37466 100644 --- a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreVersionList.cs +++ b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreVersionList.cs @@ -16,7 +16,7 @@ internal class AssetStoreVersionList : IVersionList [SerializeField] private List m_Versions; - public IEnumerable key => m_Versions.Cast(); + public IEnumerable key => m_Versions; public IPackageVersion installed => null; diff --git a/Modules/PackageManagerUI/Editor/Services/Common/BasePackageVersion.cs b/Modules/PackageManagerUI/Editor/Services/Common/BasePackageVersion.cs index 3998a4582e..afb878ee93 100644 --- a/Modules/PackageManagerUI/Editor/Services/Common/BasePackageVersion.cs +++ b/Modules/PackageManagerUI/Editor/Services/Common/BasePackageVersion.cs @@ -47,10 +47,6 @@ internal abstract class BasePackageVersion : IPackageVersion, ISerializationCall public virtual IEnumerable importedAssets => null; - public virtual bool isRegistryPackage => false; - - public virtual bool isFromScopedRegistry => false; - [NonSerialized] private IPackage m_Package; public UI.IPackage package => m_Package; @@ -67,6 +63,8 @@ public virtual bool HasTag(PackageTag tag) return (m_Tag & tag) != 0; } + public virtual RegistryType availableRegistry => RegistryType.None; + // Currently we don't consider Upm Packages with EntitlementLicensingModel.AssetStore as having entitlements // and it is only used right now to check if a package is from Asset Store. This is also to be consistent with // other Asset Store packages (as in, if Upm Packages on Asset Store are considered with entitlements, then every @@ -95,7 +93,6 @@ public virtual bool HasTag(PackageTag tag) public abstract string localPath { get; } public abstract string versionString { get; } public abstract long versionId { get; } - public virtual bool isUnityPackage => false; public bool IsDifferentVersionThanRequested => !string.IsNullOrEmpty(versionInManifest) && !HasTag(PackageTag.Git | PackageTag.Local | PackageTag.Custom) && diff --git a/Modules/PackageManagerUI/Editor/Services/Common/Package.cs b/Modules/PackageManagerUI/Editor/Services/Common/Package.cs index 1f51158fd8..03998ca260 100644 --- a/Modules/PackageManagerUI/Editor/Services/Common/Package.cs +++ b/Modules/PackageManagerUI/Editor/Services/Common/Package.cs @@ -26,7 +26,6 @@ internal class Package : IPackage, ISerializationCallbackReceiver [SerializeField] private bool m_IsDiscoverable; - public bool isDiscoverable => m_IsDiscoverable; public string displayName => !string.IsNullOrEmpty(m_Product?.displayName) ? m_Product?.displayName : versions.FirstOrDefault()?.displayName ?? string.Empty; public PackageState state @@ -108,9 +107,9 @@ private IEnumerable GetAllErrorsInPackageAndVersions() yield return versionError; } - public bool hasEntitlements => versions.Any(version => version.HasTag(PackageTag.Unity) && version.hasEntitlements); + public bool hasEntitlements => versions.Any(v => v.HasTag(PackageTag.Unity) && v.hasEntitlements); - public bool hasEntitlementsError => m_Errors.Any(error => error.errorCode == UIErrorCode.UpmError_Forbidden) || versions.Any(version => version.hasEntitlementsError); + public bool hasEntitlementsError => m_Errors.Any(e => e.errorCode == UIErrorCode.UpmError_Forbidden) || versions.Any(v => v.hasEntitlementsError); private IVersionList m_VersionList; public IVersionList versions => m_VersionList; @@ -171,17 +170,16 @@ private Package(string name, IVersionList versionList, Product product = null, b public virtual bool IsInTab(PackageFilterTab tab) { - var version = versions.primary; switch (tab) { case PackageFilterTab.BuiltIn: - return version.HasTag(PackageTag.BuiltIn); + return versions.All(v => v.HasTag(PackageTag.BuiltIn)); case PackageFilterTab.UnityRegistry: - return !version.HasTag(PackageTag.BuiltIn) && version.HasTag(PackageTag.UpmFormat) && version.HasTag(PackageTag.Unity) && (isDiscoverable || (versions.installed?.isDirectDependency ?? false)); + return versions.Any(v => v.availableRegistry == RegistryType.UnityRegistry) && !versions.All(v => v.HasTag(PackageTag.BuiltIn)) && (m_IsDiscoverable || versions.installed?.isDirectDependency == true); case PackageFilterTab.MyRegistries: - return version.HasTag(PackageTag.UpmFormat) && version.HasTag(PackageTag.ScopedRegistry | PackageTag.MainNotUnity) && (isDiscoverable || (versions.installed?.isDirectDependency ?? false)); + return versions.Any(v => v.availableRegistry == RegistryType.MyRegistries) && (m_IsDiscoverable || versions.installed?.isDirectDependency == true); case PackageFilterTab.InProject: - return !version.HasTag(PackageTag.BuiltIn) && (progress == PackageProgress.Installing || versions.installed != null); + return !versions.All(v => v.HasTag(PackageTag.BuiltIn)) && (progress == PackageProgress.Installing || versions.installed != null); case PackageFilterTab.AssetStore: return product != null; default: diff --git a/Modules/PackageManagerUI/Editor/Services/Common/PlaceholderVersionList.cs b/Modules/PackageManagerUI/Editor/Services/Common/PlaceholderVersionList.cs index d15a80c69f..3eff96c062 100644 --- a/Modules/PackageManagerUI/Editor/Services/Common/PlaceholderVersionList.cs +++ b/Modules/PackageManagerUI/Editor/Services/Common/PlaceholderVersionList.cs @@ -22,8 +22,6 @@ internal class PlaceholderVersionList : IVersionList public IPackageVersion latest => m_Versions[0]; - public IPackageVersion latestPatch => m_Versions[0]; - public IPackageVersion importAvailable => null; public IPackageVersion recommended => m_Versions[0]; diff --git a/Modules/PackageManagerUI/Editor/Services/Common/VersionsFilter.cs b/Modules/PackageManagerUI/Editor/Services/Common/VersionsFilter.cs index 6cbc07f0ff..66df3c8673 100644 --- a/Modules/PackageManagerUI/Editor/Services/Common/VersionsFilter.cs +++ b/Modules/PackageManagerUI/Editor/Services/Common/VersionsFilter.cs @@ -9,15 +9,15 @@ namespace UnityEditor.PackageManager.UI.Internal { internal static class VersionsFilter { - public static UpmVersionList GetFilteredVersionList(UpmVersionList versonList, bool seeAllVersions, bool showPreRelease) + public static UpmVersionList GetFilteredVersionList(UpmVersionList versionList, bool seeAllVersions, bool showPreRelease) { // Only filter on Lifecycle tags if is a Unity package and the `seeAllVersions` option is not checked - if (seeAllVersions || !versonList.Any(v => v.isUnityPackage)) - return versonList; + if (seeAllVersions || versionList.Any(v => v.availableRegistry != RegistryType.UnityRegistry)) + return versionList; var packageTagsToExclude = PackageTag.PreRelease | PackageTag.Experimental; - var installedVersion = versonList.installed; + var installedVersion = versionList.installed; if (showPreRelease || installedVersion?.HasTag(PackageTag.PreRelease | PackageTag.Experimental) == true) packageTagsToExclude &= ~PackageTag.PreRelease; @@ -27,7 +27,7 @@ public static UpmVersionList GetFilteredVersionList(UpmVersionList versonList, b var numVersionsFilteredOut = 0; var filteredVersions = new List(); - foreach (var version in versonList.Cast()) + foreach (var version in versionList.Cast()) { if (version.isInstalled || !version.HasTag(packageTagsToExclude)) filteredVersions.Add(version); @@ -35,22 +35,22 @@ public static UpmVersionList GetFilteredVersionList(UpmVersionList versonList, b ++numVersionsFilteredOut; } if (numVersionsFilteredOut <= 0) - return versonList; - return new UpmVersionList(filteredVersions, versonList.lifecycleVersionString, versonList.lifecycleNextVersion); + return versionList; + return new UpmVersionList(filteredVersions, versionList.lifecycleVersionString, versionList.lifecycleNextVersion); } - public static UpmVersionList UnloadVersionsIfNeeded(UpmVersionList versonList, bool loadAllVersions) + public static UpmVersionList UnloadVersionsIfNeeded(UpmVersionList versionList, bool loadAllVersions) { if (loadAllVersions) - return versonList; - var numTotalVersions = versonList.Count(); + return versionList; + var numTotalVersions = versionList.Count(); if (numTotalVersions == 0) - return versonList; - var keyVersions = versonList.key.Cast().ToArray(); + return versionList; + var keyVersions = versionList.key.Cast().ToArray(); var numVersionsToUnload = numTotalVersions - keyVersions.Length; if (numVersionsToUnload <= 0) - return versonList; - return new UpmVersionList(keyVersions, versonList.lifecycleVersionString, versonList.lifecycleNextVersion, numVersionsToUnload); + return versionList; + return new UpmVersionList(keyVersions, versionList.lifecycleVersionString, versionList.lifecycleNextVersion, numVersionsToUnload); } } } diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackage.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackage.cs index 4b058a8e3d..f8b2d64e40 100644 --- a/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackage.cs +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackage.cs @@ -31,8 +31,6 @@ internal interface IPackage : UI.IPackage PackageProgress progress { get; } - bool isDiscoverable { get; } - // package level errors (for upm this refers to operation errors that are separate from the package info) IEnumerable errors { get; } diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackageVersion.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackageVersion.cs index 0582bd460b..f569b6feaf 100644 --- a/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackageVersion.cs +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackageVersion.cs @@ -72,6 +72,8 @@ internal interface IPackageVersion : UI.IPackageVersion bool HasTag(PackageTag tag); + RegistryType availableRegistry { get; } + // A version is fully fetched when the information isn't derived from another version (therefore may be inaccurate) bool isFullyFetched { get; } @@ -79,8 +81,6 @@ internal interface IPackageVersion : UI.IPackageVersion bool isDirectDependency { get; } - bool isUnityPackage { get; } - string localPath { get; } SemVersion? supportedVersion { get; } @@ -95,10 +95,6 @@ internal interface IPackageVersion : UI.IPackageVersion bool IsRequestedButOverriddenVersion { get; } - bool isRegistryPackage { get; } - - bool isFromScopedRegistry { get; } - string deprecationMessage { get; } string GetDescriptor(bool isFirstLetterCapitalized = false); diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageTag.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageTag.cs index b77e51c2a6..9828f7bda8 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageTag.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageTag.cs @@ -15,19 +15,16 @@ internal enum PackageTag : uint Custom = 1 << 0, Local = 1 << 1, Git = 1 << 2, - Bundled = 1 << 3, - BuiltIn = 1 << 4, - Feature = 1 << 5, - Placeholder = 1 << 6, - SpecialInstall = 1 << 7, - VersionLocked = 1 << 8, + BuiltIn = 1 << 3, + Feature = 1 << 4, + Placeholder = 1 << 5, + SpecialInstall = 1 << 6, + VersionLocked = 1 << 7, LegacyFormat = 1 << 10, // legacy .unitypackage format UpmFormat = 1 << 11, Unity = 1 << 15, - ScopedRegistry = 1 << 16, - MainNotUnity = 1 << 17, Disabled = 1 << 20, Published = 1 << 21, diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/RegistryType.cs b/Modules/PackageManagerUI/Editor/Services/Packages/RegistryType.cs new file mode 100644 index 0000000000..43f41cf724 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/Services/Packages/RegistryType.cs @@ -0,0 +1,16 @@ +// 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.PackageManager.UI.Internal +{ + internal enum RegistryType + { + None, + UnityRegistry, + MyRegistries, + AssetStore + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/Proxies/AssetDatabaseProxy.cs b/Modules/PackageManagerUI/Editor/Services/Proxies/AssetDatabaseProxy.cs index 76e7a5e952..40ed13600b 100644 --- a/Modules/PackageManagerUI/Editor/Services/Proxies/AssetDatabaseProxy.cs +++ b/Modules/PackageManagerUI/Editor/Services/Proxies/AssetDatabaseProxy.cs @@ -49,9 +49,9 @@ public virtual UnityEngine.Object LoadMainAssetAtPath(string assetPath) return AssetDatabase.LoadMainAssetAtPath(assetPath); } - public virtual bool GetAssetFolderInfo(string path, out bool rootFolder, out bool immutable) + public virtual bool TryGetAssetFolderInfo(string path, out bool rootFolder, out bool immutable) { - return AssetDatabase.GetAssetFolderInfo(path, out rootFolder, out immutable); + return AssetDatabase.TryGetAssetFolderInfo(path, out rootFolder, out immutable); } public virtual AssetOrigin GetAssetOrigin(string guid) diff --git a/Modules/PackageManagerUI/Editor/Services/Upm/UpmClient.cs b/Modules/PackageManagerUI/Editor/Services/Upm/UpmClient.cs index 0c9c5527d7..8f5cd34fc4 100644 --- a/Modules/PackageManagerUI/Editor/Services/Upm/UpmClient.cs +++ b/Modules/PackageManagerUI/Editor/Services/Upm/UpmClient.cs @@ -55,9 +55,9 @@ internal class UpmClient : ISerializationCallbackReceiver private string[] m_SerializedRegistryUrlsKeys; [SerializeField] - private bool[] m_SerializedRegistryUrlsValues; + private RegistryType[] m_SerializedRegistryUrlsValues; - internal Dictionary m_RegistryUrls = new Dictionary(); + internal Dictionary m_RegistryUrls = new Dictionary(); [NonSerialized] private UpmCache m_UpmCache; @@ -99,7 +99,7 @@ public virtual bool IsAnyExperimentalPackagesInUse() public void OnBeforeSerialize() { m_SerializedRegistryUrlsKeys = m_RegistryUrls?.Keys.ToArray() ?? new string[0]; - m_SerializedRegistryUrlsValues = m_RegistryUrls?.Values.ToArray() ?? new bool[0]; + m_SerializedRegistryUrlsValues = m_RegistryUrls?.Values.ToArray() ?? new RegistryType[0]; m_SerializedInProgressExtraFetchOperations = m_ExtraFetchOperations?.Values.Where(i => i.isInProgress).ToArray() ?? new UpmSearchOperation[0]; } @@ -513,25 +513,30 @@ public virtual void Resolve() m_ClientProxy.Resolve(); } - public virtual bool IsUnityPackage(PackageInfo packageInfo) + public virtual RegistryType GetAvailableRegistryType(PackageInfo packageInfo) { + // Special handling for packages that's built in/bundled with unity, we always consider them from the Unity registry if (packageInfo?.source == PackageSource.BuiltIn) - return true; + return RegistryType.UnityRegistry; - if (packageInfo == null - || packageInfo.source != PackageSource.Registry - || packageInfo.registry?.isDefault != true - || string.IsNullOrEmpty(packageInfo.registry?.url) - || !packageInfo.versions.all.Any() - || packageInfo.entitlements?.licensingModel == EntitlementLicensingModel.AssetStore) - return false; + if (string.IsNullOrEmpty(packageInfo?.registry?.url)) + return RegistryType.None; + + if (packageInfo.entitlements?.licensingModel == EntitlementLicensingModel.AssetStore) + return RegistryType.AssetStore; - if (m_RegistryUrls.TryGetValue(packageInfo.registry.url, out var isUnityRegistry)) - return isUnityRegistry; + if (m_RegistryUrls.TryGetValue(packageInfo.registry.url, out var result)) + return result; - isUnityRegistry = IsUnityUrl(packageInfo.registry.url); - m_RegistryUrls[packageInfo.registry.url] = isUnityRegistry; - return isUnityRegistry; + result = packageInfo.registry.isDefault && IsUnityUrl(packageInfo.registry.url) ? RegistryType.UnityRegistry : RegistryType.MyRegistries; + m_RegistryUrls[packageInfo.registry.url] = result; + return result; + } + + public virtual bool IsUnityPackage(PackageInfo packageInfo) + { + return packageInfo is { source: PackageSource.BuiltIn or PackageSource.Registry } && + GetAvailableRegistryType(packageInfo) == RegistryType.UnityRegistry; } public static bool IsUnityUrl(string url) diff --git a/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageDocs.cs b/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageDocs.cs index f57424bff9..afba983ddf 100644 --- a/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageDocs.cs +++ b/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageDocs.cs @@ -72,7 +72,7 @@ public static void HandleInvalidOrUnreachableOnlineUrl(string onlineUrl, string public static void OpenWebUrl(string onlineUrl, IPackageVersion version, ApplicationProxy applicationProxy, string analyticsEvent, Action errorCallback) { - if (!version.isUnityPackage) + if (!version.HasTag(PackageTag.Unity)) { applicationProxy.OpenURL(onlineUrl); PackageManagerWindowAnalytics.SendEvent($"{analyticsEvent}NonUnityPackageUrl", version?.uniqueId); diff --git a/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageFactory.cs b/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageFactory.cs index 812812bc05..1f8ddc3683 100644 --- a/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageFactory.cs +++ b/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageFactory.cs @@ -162,9 +162,9 @@ public void GeneratePackagesAndTriggerChangeEvent(IEnumerable packageNam packagesToRemove.Add(packageName); else { - var isUnityPackage = m_UpmClient.IsUnityPackage(searchInfo ?? installedInfo); + var availableRegistry = m_UpmClient.GetAvailableRegistryType(searchInfo ?? installedInfo); var extraVersions = m_UpmCache.GetExtraPackageInfos(packageName); - var versionList = new UpmVersionList(searchInfo, installedInfo, isUnityPackage, extraVersions); + var versionList = new UpmVersionList(searchInfo, installedInfo, availableRegistry, extraVersions); versionList = VersionsFilter.GetFilteredVersionList(versionList, seeAllVersions, showPreRelease); versionList = VersionsFilter.UnloadVersionsIfNeeded(versionList, m_UpmCache.IsLoadAllVersions(packageName)); if (!versionList.Any()) @@ -325,8 +325,8 @@ public void GeneratePackagesAndTriggerChangeEvent(IEnumerable productIds) productIdAndNamesToSearch.Add((productId: productId, packageName: packageName)); var extraVersions = m_UpmCache.GetExtraPackageInfos(packageName); - var isUnityPackage = m_UpmClient.IsUnityPackage(productSearchInfo ?? installedPackageInfo); - var versionList = new UpmVersionList(productSearchInfo, installedPackageInfo, isUnityPackage, extraVersions); + var availableRegistry = m_UpmClient.GetAvailableRegistryType(productSearchInfo ?? installedPackageInfo); + var versionList = new UpmVersionList(productSearchInfo, installedPackageInfo, availableRegistry, extraVersions); versionList = VersionsFilter.UnloadVersionsIfNeeded(versionList, m_UpmCache.IsLoadAllVersions(productId.ToString())); package = CreatePackage(packageName, versionList, new Product(productId, purchaseInfo, productInfo), isDeprecated: isDeprecated, deprecationMessage: deprecationMessage); if (productInfoFetchError != null) diff --git a/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageVersion.cs b/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageVersion.cs index e20c1bea4e..a7abc3cc34 100644 --- a/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageVersion.cs +++ b/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageVersion.cs @@ -22,7 +22,6 @@ internal class UpmPackageVersion : BasePackageVersion private string m_Category; public override string category => m_Category; - [SerializeField] private bool m_IsFullyFetched; public override bool isFullyFetched => m_IsFullyFetched; @@ -45,26 +44,11 @@ internal class UpmPackageVersion : BasePackageVersion public override string author => m_Author; [SerializeField] - private bool m_IsUnityPackage; - public override bool isUnityPackage - { - get - { - if (HasTag(PackageTag.Bundled)) - return true; - if (HasTag(PackageTag.Git | PackageTag.Local | PackageTag.Custom)) - return false; - return m_IsUnityPackage; - } - } + private RegistryType m_AvailableRegistry; + public override RegistryType availableRegistry => m_AvailableRegistry; [SerializeField] private PackageSource m_Source; - public override bool isRegistryPackage => m_Source == PackageSource.Registry; - - [SerializeField] - private bool m_IsFromScopedRegistry; - public override bool isFromScopedRegistry => isRegistryPackage && m_IsFromScopedRegistry; [SerializeField] private DependencyInfo[] m_Dependencies; @@ -117,34 +101,33 @@ public string sourcePath public override string deprecationMessage => m_DeprecationMessage; - public UpmPackageVersion(PackageInfo packageInfo, bool isInstalled, SemVersion? version, string displayName, bool isUnityPackage) + public UpmPackageVersion(PackageInfo packageInfo, bool isInstalled, SemVersion? version, string displayName, RegistryType availableRegistry) { m_Version = version; m_VersionString = m_Version?.ToString(); m_DisplayName = displayName; m_IsInstalled = isInstalled; - UpdatePackageInfo(packageInfo, isUnityPackage); + UpdatePackageInfo(packageInfo, availableRegistry); } - public UpmPackageVersion(PackageInfo packageInfo, bool isInstalled, bool isUnityPackage) + public UpmPackageVersion(PackageInfo packageInfo, bool isInstalled, RegistryType availableRegistry) { SemVersionParser.TryParse(packageInfo.version, out m_Version); m_VersionString = m_Version?.ToString(); m_DisplayName = packageInfo.displayName; m_IsInstalled = isInstalled; - UpdatePackageInfo(packageInfo, isUnityPackage); + UpdatePackageInfo(packageInfo, availableRegistry); } - internal void UpdatePackageInfo(PackageInfo packageInfo, bool isUnityPackage) + internal void UpdatePackageInfo(PackageInfo packageInfo, RegistryType availableRegistry) { m_IsFullyFetched = m_Version?.ToString() == packageInfo.version; - m_IsUnityPackage = isUnityPackage; + m_AvailableRegistry = availableRegistry; m_Source = packageInfo.source; m_Category = packageInfo.category; m_IsDirectDependency = packageInfo.isDirectDependency; - m_IsFromScopedRegistry = packageInfo.registry?.isDefault == false; m_Name = packageInfo.name; m_VersionInManifest = packageInfo.projectDependenciesEntry; @@ -152,10 +135,10 @@ internal void UpdatePackageInfo(PackageInfo packageInfo, bool isUnityPackage) // For core packages, or packages that are bundled with Unity without being published, use Unity's build date m_PublishedDateTicks = packageInfo.datePublished?.Ticks ?? 0; - if (HasTag(PackageTag.Bundled) && packageInfo.datePublished == null) + if (m_PublishedDateTicks == 0 && packageInfo.source == PackageSource.BuiltIn) m_PublishedDateTicks = new DateTime(1970, 1, 1).Ticks + InternalEditorUtility.GetUnityVersionDate() * TimeSpan.TicksPerSecond; - m_Author = this.isUnityPackage ? k_UnityAuthor : packageInfo.author?.name ?? string.Empty; + m_Author = HasTag(PackageTag.Unity) ? k_UnityAuthor : packageInfo.author?.name ?? string.Empty; if (m_IsFullyFetched) { @@ -183,8 +166,8 @@ internal void UpdatePackageInfo(PackageInfo packageInfo, bool isUnityPackage) m_HasErrorWithEntitlementMessage = false; m_Errors.Clear(); - m_Dependencies = new DependencyInfo[0]; - m_ResolvedDependencies = new DependencyInfo[0]; + m_Dependencies = Array.Empty(); + m_ResolvedDependencies = Array.Empty(); m_Entitlements = new EntitlementsInfo(); m_ResolvedPath = string.Empty; m_Description = string.Empty; @@ -199,11 +182,8 @@ public void SetInstalled(bool value) private void RefreshTagsForLocalAndGit(PackageSource source) { - if (source == PackageSource.BuiltIn || source == PackageSource.Registry) - return; - m_Tag &= ~(PackageTag.Custom | PackageTag.VersionLocked | PackageTag.Local | PackageTag.Git); - if (!m_IsInstalled) + if (!m_IsInstalled || source is PackageSource.BuiltIn or PackageSource.Registry) return; switch (source) @@ -218,8 +198,6 @@ private void RefreshTagsForLocalAndGit(PackageSource source) case PackageSource.Git: m_Tag |= PackageTag.Git | PackageTag.VersionLocked; break; - default: - break; } } @@ -228,47 +206,36 @@ private void RefreshTags(PackageInfo packageInfo) m_Tag = PackageTag.UpmFormat; // in the case of git/local packages, we always assume that the non-installed versions are from the registry - var source = packageInfo.source == PackageSource.BuiltIn || m_IsInstalled ? packageInfo.source : PackageSource.Registry; - if (source == PackageSource.BuiltIn) + if (packageInfo.source == PackageSource.BuiltIn) { - m_Tag |= PackageTag.Bundled | PackageTag.VersionLocked; - if (packageInfo.type == "module") - m_Tag |= PackageTag.BuiltIn; - else if (packageInfo.type == "feature") - m_Tag |= PackageTag.Feature; + m_Tag |= PackageTag.Unity | PackageTag.VersionLocked; + switch (packageInfo.type) + { + case "module": + m_Tag |= PackageTag.BuiltIn; + break; + case "feature": + m_Tag |= PackageTag.Feature; + break; + } } else RefreshTagsForLocalAndGit(packageInfo.source); - if (isFromScopedRegistry) - m_Tag |= PackageTag.ScopedRegistry; - - // The following logic means that if we see a Unity package on a scoped registry, we will consider it NOT from the scoped registry - // We'll also mark any non unity packages from any registry as `main not unity` - if (isRegistryPackage) - { - if (isUnityPackage) - m_Tag &= ~PackageTag.ScopedRegistry; - else - m_Tag |= PackageTag.MainNotUnity; - } + // We only tag a package as `Unity` when it's directly installed from registry. A package available on Unity registry can be installed + // through git or local file system but in those cases it is not considered a `Unity` package. + if (m_Source == PackageSource.Registry && m_AvailableRegistry == RegistryType.UnityRegistry) + m_Tag |= PackageTag.Unity; // We use the logic below instead packageInfo.isDeprecated, since we don't do an extra fetch when we want to tag deprecated version in version history // We want to know if a version is deprecated before we do the extra fetch - var isDeprecated = packageInfo.versions.deprecated.Contains(m_VersionString); - if (isDeprecated) + if (packageInfo.versions.deprecated.Contains(m_VersionString)) m_Tag |= PackageTag.Deprecated; - if (isUnityPackage) - m_Tag |= PackageTag.Unity; - - if (!isUnityPackage || isDeprecated) + if (!HasTag(PackageTag.Unity) || HasTag(PackageTag.Deprecated)) return; - const string previewTagString = "Preview"; - SemVersion? lifecycleVersionParsed; - var isLifecycleVersionValid = SemVersionParser.TryParse(packageInfo.unityLifecycle?.version, out lifecycleVersionParsed); - + var isLifecycleVersionValid = SemVersionParser.TryParse(packageInfo.unityLifecycle?.version, out var lifecycleVersionParsed); if (m_Version?.HasPreReleaseVersionTag() == true) { // must match exactly to be release candidate @@ -279,9 +246,9 @@ private void RefreshTags(PackageInfo packageInfo) } else if ((version?.Major == 0 && string.IsNullOrEmpty(version?.Prerelease)) || m_Version?.IsExperimental() == true || - previewTagString.Equals(version?.Prerelease.Split('.')[0], StringComparison.InvariantCultureIgnoreCase)) + "Preview".Equals(version?.Prerelease.Split('.')[0], StringComparison.InvariantCultureIgnoreCase)) m_Tag |= PackageTag.Experimental; - else if (isLifecycleVersionValid && m_Version.Value.IsEqualOrPatchOf(lifecycleVersionParsed)) + else if (isLifecycleVersionValid && m_Version?.IsEqualOrPatchOf(lifecycleVersionParsed) == true) { m_Tag |= PackageTag.Release; } @@ -298,20 +265,16 @@ public override string GetDescriptor(bool isFirstLetterCapitalized = false) private static string GetDisplayName(PackageInfo info) { - if (!string.IsNullOrEmpty(info.displayName)) - return info.displayName; - return ExtractDisplayName(info.name); + return !string.IsNullOrEmpty(info.displayName) ? info.displayName : ExtractDisplayName(info.name); } public static string ExtractDisplayName(string packageName) { - if (packageName.StartsWith(k_UnityPrefix)) - { - var displayName = packageName.Substring(k_UnityPrefix.Length).Replace("modules.", ""); - displayName = string.Join(" ", displayName.Split('.')); - return new CultureInfo("en-US").TextInfo.ToTitleCase(displayName); - } - return packageName; + if (!packageName.StartsWith(k_UnityPrefix)) + return packageName; + var displayName = packageName.Substring(k_UnityPrefix.Length).Replace("modules.", ""); + displayName = string.Join(" ", displayName.Split('.')); + return new CultureInfo("en-US").TextInfo.ToTitleCase(displayName); } public static string FormatPackageId(string name, string version) diff --git a/Modules/PackageManagerUI/Editor/Services/Upm/UpmVersionList.cs b/Modules/PackageManagerUI/Editor/Services/Upm/UpmVersionList.cs index ccd9ddef32..f4e419e004 100644 --- a/Modules/PackageManagerUI/Editor/Services/Upm/UpmVersionList.cs +++ b/Modules/PackageManagerUI/Editor/Services/Upm/UpmVersionList.cs @@ -149,8 +149,6 @@ public void OnAfterDeserialize() SemVersionParser.TryParse(m_LifecycleNextVersionString, out m_LifecycleNextVersion); } - private bool isUnityPackage => m_Versions.All(v => v.isUnityPackage); - public IPackageVersion latest => m_Versions.LastOrDefault(); public IPackageVersion recommended @@ -158,16 +156,15 @@ public IPackageVersion recommended get { var installed = this.installed; - if (installed != null && installed.HasTag(PackageTag.VersionLocked)) return installed; - if (!isUnityPackage) + if (m_Versions.Any(v => v.availableRegistry != RegistryType.UnityRegistry)) return latest; - // for Unity packages, we should only recommend versions that have been tested with - // the Editor; this means they have to be either version or nextVersion in the manifest - // version will take precedence over nextVersion + // for Unity packages, we should only recommend versions that have been tested with the Editor; + // this means they have to be either the lifecycle version or nextVersion in the manifest + // lifecycle version will take precedence over nextVersion var resolvedLifecycleVersion = this.resolvedLifecycleVersion; var resolvedLifecycleNextVersion = this.resolvedLifecycleNextVersion; @@ -242,35 +239,35 @@ private static int AddToSortedVersions(List sortedVersions, U return sortedVersions.Count - 1; } - public UpmVersionList(PackageInfo searchInfo, PackageInfo installedInfo, bool isUnityPackage, Dictionary extraVersions = null) + public UpmVersionList(PackageInfo searchInfo, PackageInfo installedInfo, RegistryType availableRegistry, Dictionary extraVersions = null) { // We prioritize searchInfo over installedInfo, because searchInfo is fetched from the server // while installedInfo sometimes only contain local data var mainInfo = searchInfo ?? installedInfo; if (mainInfo != null) { - var mainVersion = new UpmPackageVersion(mainInfo, mainInfo == installedInfo, isUnityPackage); + var mainVersion = new UpmPackageVersion(mainInfo, mainInfo == installedInfo, availableRegistry); m_Versions = mainInfo.versions.compatible.Select(v => { SemVersion? version; SemVersionParser.TryParse(v, out version); - return new UpmPackageVersion(mainInfo, false, version, mainVersion.displayName, isUnityPackage); + return new UpmPackageVersion(mainInfo, false, version, mainVersion.displayName, availableRegistry); }).ToList(); AddToSortedVersions(m_Versions, mainVersion); if (mainInfo != installedInfo && installedInfo != null) - AddInstalledVersion(new UpmPackageVersion(installedInfo, true, isUnityPackage)); + AddInstalledVersion(new UpmPackageVersion(installedInfo, true, availableRegistry)); } m_InstalledIndex = m_Versions.FindIndex(v => v.isInstalled); var recommendedVersion = mainInfo?.unityLifecycle?.recommendedVersion; if (string.IsNullOrEmpty(recommendedVersion)) recommendedVersion = mainInfo?.unityLifecycle?.version; SetLifecycleVersions(recommendedVersion, mainInfo?.unityLifecycle?.nextVersion); - UpdateExtraPackageInfos(extraVersions, isUnityPackage); + UpdateExtraPackageInfos(extraVersions, availableRegistry); m_NumUnloadedVersions = 0; } - public UpmVersionList(IEnumerable versions = null, string unityLifecycleInfoVersion = null, string unityLifecycleInfoNextVersion = null, int numUnloadedVersions = 0) + public UpmVersionList(IEnumerable versions, string unityLifecycleInfoVersion = null, string unityLifecycleInfoNextVersion = null, int numUnloadedVersions = 0) { m_Versions = versions?.ToList() ?? new List(); m_InstalledIndex = m_Versions.FindIndex(v => v.isInstalled); @@ -278,13 +275,13 @@ public UpmVersionList(IEnumerable versions = null, string uni m_NumUnloadedVersions = numUnloadedVersions; } - private void UpdateExtraPackageInfos(Dictionary extraVersions, bool isUnityPackage) + private void UpdateExtraPackageInfos(Dictionary extraVersions, RegistryType availableRegistry) { if (extraVersions?.Any() != true) return; foreach (var version in m_Versions.Where(v => !v.isFullyFetched)) if (extraVersions.TryGetValue(version.version.ToString(), out var packageInfo)) - version.UpdatePackageInfo(packageInfo, isUnityPackage); + version.UpdatePackageInfo(packageInfo, availableRegistry); } private void SetLifecycleVersions(string unityLifecycleInfoVersion, string unityLifecycleInfoNextVersion) diff --git a/Modules/PackageManagerUI/Editor/Services/UserSettings/PackageManagerUserSettingsProvider.cs b/Modules/PackageManagerUI/Editor/Services/UserSettings/PackageManagerUserSettingsProvider.cs index f5b80025a9..400784b05d 100644 --- a/Modules/PackageManagerUI/Editor/Services/UserSettings/PackageManagerUserSettingsProvider.cs +++ b/Modules/PackageManagerUI/Editor/Services/UserSettings/PackageManagerUserSettingsProvider.cs @@ -241,7 +241,7 @@ private void GetAssetStoreCacheConfig() private void RefreshAssetStoreCachePathConfig(CachePathConfig config) { m_CurrentAssetStoreConfig = config; - assetsCachePath.text = currentAssetStoreNormalizedPath.EscapeBackslashes(); + assetsCachePath.text = currentAssetStoreNormalizedPath; UIUtils.SetElementDisplay(assetsCacheErrorBox, false); if (m_CurrentAssetStoreConfig.source == ConfigSource.Environment) @@ -306,7 +306,7 @@ private void OnPackagesClearCacheRootOperationResult(CacheRootConfig config) private void RefreshCurrentPackagesConfig(CacheRootConfig config) { m_CurrentPackagesConfig = config; - packagesCachePath.text = currentPackagesNormalizedPath.EscapeBackslashes(); + packagesCachePath.text = currentPackagesNormalizedPath; packagesCacheDropdown.SetEnabled(true); UIUtils.SetElementDisplay(packagesCacheErrorBox, false); } diff --git a/Modules/PackageManagerUI/Editor/UI/Common/PageManager.cs b/Modules/PackageManagerUI/Editor/UI/Common/PageManager.cs index 335fb97a53..3226a22326 100644 --- a/Modules/PackageManagerUI/Editor/UI/Common/PageManager.cs +++ b/Modules/PackageManagerUI/Editor/UI/Common/PageManager.cs @@ -176,7 +176,7 @@ public virtual IPage FindPage(IEnumerable packageVersions) if (packageVersions.All(v => v.package.versions.installed != null || (v.package.progress == PackageProgress.Installing && v.package.versions.primary.HasTag(PackageTag.Placeholder)))) return GetPage(PackageFilterTab.InProject); - if (packageVersions.All(v => v.HasTag(PackageTag.Unity))) + if (packageVersions.All(v => v.availableRegistry == RegistryType.UnityRegistry)) return GetPage(PackageFilterTab.UnityRegistry); if (packageVersions.All(v => v.HasTag(PackageTag.LegacyFormat))) diff --git a/Modules/PackageManagerUI/Editor/UI/PackageDetailsHeader.cs b/Modules/PackageManagerUI/Editor/UI/PackageDetailsHeader.cs index 16db699c9a..fe21c792ef 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageDetailsHeader.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageDetailsHeader.cs @@ -76,12 +76,12 @@ public PackageDetailsHeader() private void CreateTags() { - versionContainer.Add(new PackageSimpleTagLabel(PackageTag.Git, L10n.Tr("git"))); - versionContainer.Add(new PackageSimpleTagLabel(PackageTag.Local, L10n.Tr("local"))); + versionContainer.Add(new PackageSimpleTagLabel(PackageTag.Git, L10n.Tr("Git"))); + versionContainer.Add(new PackageSimpleTagLabel(PackageTag.Local, L10n.Tr("Local"))); versionContainer.Add(new PackageAssetStoreTagLabel()); versionContainer.Add(new PackageDeprecatedTagLabel()); - versionContainer.Add(new PackageSimpleTagLabel(PackageTag.Disabled, L10n.Tr("disabled"))); - versionContainer.Add(new PackageSimpleTagLabel(PackageTag.Custom, L10n.Tr("custom"))); + versionContainer.Add(new PackageSimpleTagLabel(PackageTag.Disabled, L10n.Tr("Disabled"))); + versionContainer.Add(new PackageSimpleTagLabel(PackageTag.Custom, L10n.Tr("Custom"))); versionContainer.Add(new PackageSimpleTagLabel(PackageTag.PreRelease, L10n.Tr("Pre-Release"))); versionContainer.Add(new PackageReleaseTagLabel(m_PackageDatabase)); versionContainer.Add(new PackageSimpleTagLabel(PackageTag.ReleaseCandidate, L10n.Tr("Release Candidate"))); @@ -404,9 +404,6 @@ private void RefreshRegistry() UIUtils.SetElementDisplay(scopedRegistryInfoBox, showRegistry); if (showRegistry) { - scopedRegistryInfoBox.text = k_InfoBoxReadMoreText[(int)InfoBoxState.ScopedRegistry]; - UIUtils.SetElementDisplay(scopedRegistryInfoBox, !registry.isDefault); - var detailRegistryName = L10n.Tr("Unknown"); detailRegistry.tooltip = string.Empty; if (packageInfo.versions.all.Any()) @@ -427,6 +424,8 @@ private void RefreshRegistry() detailRegistry.text = L10n.Tr($"From {detailRegistryName}"); } } + + // To be reworked in PAX-2547 if (m_Version.HasTag(PackageTag.Experimental)) { scopedRegistryInfoBox.text = k_InfoBoxReadMoreText[(int)InfoBoxState.Experimental]; @@ -442,6 +441,11 @@ private void RefreshRegistry() scopedRegistryInfoBox.text = k_InfoBoxReadMoreText[(int)InfoBoxState.ReleaseCandidate]; UIUtils.SetElementDisplay(scopedRegistryInfoBox, true); } + else if (showRegistry) + { + scopedRegistryInfoBox.text = k_InfoBoxReadMoreText[(int)InfoBoxState.ScopedRegistry]; + UIUtils.SetElementDisplay(scopedRegistryInfoBox, !registry.isDefault); + } } private void RefreshEmbeddedFeatureSetWarningBox() @@ -449,15 +453,16 @@ private void RefreshEmbeddedFeatureSetWarningBox() UIUtils.SetElementDisplay(embeddedFeatureSetWarningBox, m_Version.HasTag(PackageTag.Feature) && m_Version.HasTag(PackageTag.Custom)); } + // To be reworked in PAX-2547 private void OnInfoBoxClickMore() { - if (m_Version.HasTag(PackageTag.PreRelease)) - m_Application.OpenURL($"{infoBoxUrl}{k_InfoBoxReadMoreUrl[(int)InfoBoxState.PreRelease]}"); - else if (m_Version.HasTag(PackageTag.Experimental)) + if (m_Version.HasTag(PackageTag.Experimental)) m_Application.OpenURL($"{infoBoxUrl}{k_InfoBoxReadMoreUrl[(int)InfoBoxState.Experimental]}"); + else if (m_Version.HasTag(PackageTag.PreRelease)) + m_Application.OpenURL($"{infoBoxUrl}{k_InfoBoxReadMoreUrl[(int)InfoBoxState.PreRelease]}"); else if (m_Version.HasTag(PackageTag.ReleaseCandidate)) m_Application.OpenURL($"{infoBoxUrl}{k_InfoBoxReadMoreUrl[(int)InfoBoxState.ReleaseCandidate]}"); - else if (m_Version.HasTag(PackageTag.ScopedRegistry)) + else m_Application.OpenURL($"{infoBoxUrl}{k_InfoBoxReadMoreUrl[(int)InfoBoxState.ScopedRegistry]}"); } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageDetailsLinks.cs b/Modules/PackageManagerUI/Editor/UI/PackageDetailsLinks.cs index 8298418233..36fde53bd1 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageDetailsLinks.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageDetailsLinks.cs @@ -162,7 +162,7 @@ private void AddToParentWithSeparator(VisualElement parent, VisualElement item) if (packageInfo == null || version.HasTag(PackageTag.Feature)) return (LinkState.NotVisible, ""); - if (UpmPackageDocs.GetDocumentationUrl(packageInfo, version.isUnityPackage).Any() || + if (UpmPackageDocs.GetDocumentationUrl(packageInfo, version.HasTag(PackageTag.Unity)).Any() || !string.IsNullOrEmpty(UpmPackageDocs.GetOfflineDocumentation(m_IOProxy, packageInfo)) || version.HasTag(PackageTag.BuiltIn)) return (LinkState.Enabled, ""); @@ -179,7 +179,7 @@ private void AddToParentWithSeparator(VisualElement parent, VisualElement item) if (packageInfo == null || version.HasTag(PackageTag.Feature | PackageTag.BuiltIn)) return (LinkState.NotVisible, ""); - if (!string.IsNullOrEmpty(UpmPackageDocs.GetChangelogUrl(packageInfo, version.isUnityPackage)) || + if (!string.IsNullOrEmpty(UpmPackageDocs.GetChangelogUrl(packageInfo, version.HasTag(PackageTag.Unity))) || !string.IsNullOrEmpty(UpmPackageDocs.GetOfflineChangelog(m_IOProxy, packageInfo))) return (LinkState.Enabled, ""); @@ -195,7 +195,7 @@ private void AddToParentWithSeparator(VisualElement parent, VisualElement item) if (packageInfo == null || version.HasTag(PackageTag.Feature | PackageTag.BuiltIn)) return (LinkState.NotVisible, ""); - if (!string.IsNullOrEmpty(UpmPackageDocs.GetLicensesUrl(packageInfo, version.isUnityPackage)) || + if (!string.IsNullOrEmpty(UpmPackageDocs.GetLicensesUrl(packageInfo, version.HasTag(PackageTag.Unity))) || !string.IsNullOrEmpty(UpmPackageDocs.GetOfflineLicenses(m_IOProxy, packageInfo))) return (LinkState.Enabled, ""); @@ -229,21 +229,21 @@ private void ViewUrl(string[] onlineUrls, string offlineDocPath, string docType, private void ViewDocClick() { var packageInfo = m_Version != null ? m_UpmCache.GetBestMatchPackageInfo(m_Version.name, m_Version.isInstalled, m_Version.versionString) : null; - var isUnityPackage = m_Version?.isUnityPackage == true; + var isUnityPackage = m_Version?.HasTag(PackageTag.Unity) == true; ViewUrl(UpmPackageDocs.GetDocumentationUrl(packageInfo, isUnityPackage), UpmPackageDocs.GetOfflineDocumentation(m_IOProxy, packageInfo), L10n.Tr("documentation"), "viewDocs"); } private void ViewChangelogClick() { var packageInfo = m_Version != null ? m_UpmCache.GetBestMatchPackageInfo(m_Version.name, m_Version.isInstalled, m_Version.versionString) : null; - var isUnityPackage = m_Version?.isUnityPackage == true; + var isUnityPackage = m_Version?.HasTag(PackageTag.Unity) == true; UpmPackageDocs.ViewUrl(UpmPackageDocs.GetChangelogUrl(packageInfo, isUnityPackage), UpmPackageDocs.GetOfflineChangelog(m_IOProxy, packageInfo), L10n.Tr("changelog"), "viewChangelog", m_Version, m_Package, m_Application); } private void ViewLicensesClick() { var packageInfo = m_Version != null ? m_UpmCache.GetBestMatchPackageInfo(m_Version.name, m_Version.isInstalled, m_Version.versionString) : null; - var isUnityPackage = m_Version?.isUnityPackage == true; + var isUnityPackage = m_Version?.HasTag(PackageTag.Unity) == true; UpmPackageDocs.ViewUrl(UpmPackageDocs.GetLicensesUrl(packageInfo, isUnityPackage), UpmPackageDocs.GetOfflineLicenses(m_IOProxy, packageInfo), L10n.Tr("license documentation"), "viewLicense", m_Version, m_Package, m_Application); } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionHistoryItem.cs b/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionHistoryItem.cs index 2425a9eeac..9723ecda02 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionHistoryItem.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionHistoryItem.cs @@ -79,7 +79,7 @@ public void StopSpinner() private void VersionHistoryItemChangeLogClicked() { var packageInfo = m_Version != null ? m_UpmCache.GetBestMatchPackageInfo(m_Version.name, m_Version.isInstalled, m_Version.versionString) : null; - var isUnityPackage = m_Version?.isUnityPackage == true; + var isUnityPackage = m_Version?.HasTag(PackageTag.Unity) == true; UpmPackageDocs.ViewUrl(UpmPackageDocs.GetChangelogUrl(packageInfo, isUnityPackage), UpmPackageDocs.GetOfflineChangelog(m_IOProxy, packageInfo), L10n.Tr("changelog"), "viewChangelog", m_Version, m_Version.package, m_ApplicationProxy); } @@ -120,16 +120,16 @@ private void RefreshState(bool multipleVersionsVisible, bool isLatestVersion) { if (m_Version.isInstalled) stateText = L10n.Tr(m_Version.isDirectDependency ? "Installed" : "Installed as dependency"); - else if (m_Version == recommended && multipleVersionsVisible && m_Version.isUnityPackage) + else if (m_Version == recommended && multipleVersionsVisible && m_Version.HasTag(PackageTag.Unity)) stateText = L10n.Tr("Recommended"); - else if (!m_Version.isUnityPackage && multipleVersionsVisible && isLatestVersion) + else if (!m_Version.HasTag(PackageTag.Unity) && multipleVersionsVisible && isLatestVersion) stateText = L10n.Tr("Latest"); } else if (versionInManifest == m_Version.versionString) stateText = L10n.Tr("Requested"); - else if (m_Version == recommended && m_Version.isUnityPackage) + else if (m_Version == recommended && m_Version.HasTag(PackageTag.Unity)) stateText = L10n.Tr("Recommended"); - else if ((primary.isInstalled || !m_Version.isUnityPackage) && isLatestVersion) + else if ((primary.isInstalled || !m_Version.HasTag(PackageTag.Unity)) && isLatestVersion) stateText = L10n.Tr("Latest"); versionHistoryItemState.text = stateText; diff --git a/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionsTab.cs b/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionsTab.cs index da98ef4bad..3b8afd3dc8 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionsTab.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionsTab.cs @@ -109,7 +109,7 @@ public override void Refresh(IPackageVersion version) return; } - var seeVersionsToolbar = versions.numUnloadedVersions > 0 && (m_Version.HasTag(PackageTag.ScopedRegistry) || m_SettingsProxy.seeAllPackageVersions || m_Version.package.versions.installed?.HasTag(PackageTag.Experimental) == true); + var seeVersionsToolbar = versions.numUnloadedVersions > 0 && (m_SettingsProxy.seeAllPackageVersions || m_Version.availableRegistry == RegistryType.MyRegistries || m_Version.package.versions.installed?.HasTag(PackageTag.Experimental) == true); UIUtils.SetElementDisplay(m_VersionsToolbar, seeVersionsToolbar); var latestVersion = m_Version.package?.versions.latest; diff --git a/Modules/PackageManagerUI/Editor/UI/PackageListScrollView.cs b/Modules/PackageManagerUI/Editor/UI/PackageListScrollView.cs index 8b29a90c66..19e039410c 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageListScrollView.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageListScrollView.cs @@ -408,12 +408,19 @@ public void OnKeyDownShortcut(KeyDownEvent evt) if (!UIUtils.IsElementVisible(this)) return; - if (evt.keyCode == KeyCode.A && evt.actionKey) + switch (evt.keyCode) { - SelectAllVisible(); + case KeyCode.A when evt.actionKey: + SelectAllVisible(); + evt.StopPropagation(); + break; + // On mac moving up and down will trigger the sound of an incorrect key being pressed + // This should be fixed in UUM-26264 by the UIToolkit team + case KeyCode.DownArrow: + case KeyCode.UpArrow: + evt.StopPropagation(); + break; } - - evt.StopPropagation(); } public void OnNavigationMoveShortcut(NavigationMoveEvent evt) diff --git a/Modules/PackageManagerUI/Editor/UI/PackageListView.cs b/Modules/PackageManagerUI/Editor/UI/PackageListView.cs index 1fba98baf9..e0f8f3e043 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageListView.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageListView.cs @@ -247,22 +247,30 @@ public void OnKeyDownShortcut(KeyDownEvent evt) { case KeyCode.A when evt.actionKey: SelectAll(); + evt.StopPropagation(); break; case KeyCode.PageUp: if (!selectedIndices.Any()) return; index = Mathf.Max(0, selectedIndices.Max() - (virtualizationController.visibleItemCount - 1)); HandleSelectionAndScroll(index, evt.shiftKey); + evt.StopPropagation(); break; case KeyCode.PageDown: if (!selectedIndices.Any()) return; index = Mathf.Min(viewController.itemsSource.Count - 1, selectedIndices.Max() + (virtualizationController.visibleItemCount - 1)); HandleSelectionAndScroll(index, evt.shiftKey); + evt.StopPropagation(); + break; + // On mac moving up and down will trigger the sound of an incorrect key being pressed + // This should be fixed in UUM-26264 by the UIToolkit team + case KeyCode.DownArrow: + case KeyCode.UpArrow: + evt.StopPropagation(); break; } Focus(); - evt.StopPropagation(); } public void OnNavigationMoveShortcut(NavigationMoveEvent evt) diff --git a/Modules/PackageManagerUI/Editor/UI/PackageManagerToolbar.cs b/Modules/PackageManagerUI/Editor/UI/PackageManagerToolbar.cs index d4acdc6ccd..c1631d6dbf 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageManagerToolbar.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageManagerToolbar.cs @@ -122,10 +122,10 @@ private void OnPackagesChanged(PackagesChangeArgs args) { // We can skip the whole database scan to save some time if non of the packages changed are related to scoped registry // Note that we also check `preUpdate` to catch the cases where packages are move from ScopedRegistry to UnityRegistry - if (!args.added.Concat(args.removed).Concat(args.updated).Concat(args.preUpdate).Any(p => p.versions.primary.HasTag(PackageTag.ScopedRegistry))) + if (!args.added.Concat(args.removed).Concat(args.updated).Concat(args.preUpdate).Any(p => p.versions.primary.availableRegistry == RegistryType.MyRegistries)) return; - if (!m_PackageDatabase.allPackages.Any(p => p.versions.primary.HasTag(PackageTag.ScopedRegistry))) + if (!m_PackageDatabase.allPackages.Any(p => p.versions.primary.availableRegistry == RegistryType.MyRegistries)) SetFilter(PackageFilterTab.UnityRegistry); } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs b/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs index 3be86e4c06..b92f0de4b7 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs @@ -133,7 +133,7 @@ public override void OnInspectorGUI() var immutable = true; m_ShouldBeEnabled = true; - if (!m_Version.isInstalled || m_AssetDatabase.GetAssetFolderInfo("Packages/" + m_Package.name, out var rootFolder, out immutable)) + if (!m_Version.isInstalled || m_AssetDatabase.TryGetAssetFolderInfo("Packages/" + m_Package.name, out var rootFolder, out immutable)) m_ShouldBeEnabled = !immutable; } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageAssetStoreTagLabel.cs b/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageAssetStoreTagLabel.cs index 29615b582b..06dfef6ff0 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageAssetStoreTagLabel.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageAssetStoreTagLabel.cs @@ -11,7 +11,7 @@ internal class PackageAssetStoreTagLabel : PackageBaseTagLabel public PackageAssetStoreTagLabel() { name = "tagAssetStore"; - text = L10n.Tr("asset store"); + text = L10n.Tr("Asset Store"); } public override void Refresh(IPackageVersion version) diff --git a/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageDynamicTagLabel.cs b/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageDynamicTagLabel.cs index 6d724592a6..26a75ea585 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageDynamicTagLabel.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageDynamicTagLabel.cs @@ -36,6 +36,14 @@ private void UpdateTag(PackageTag newTag) text = L10n.Tr("Custom"); tooltip = string.Empty; break; + case PackageTag.Local: + text = L10n.Tr("Local"); + tooltip = string.Empty; + break; + case PackageTag.Git: + text = L10n.Tr("Git"); + tooltip = string.Empty; + break; case PackageTag.Deprecated: text = L10n.Tr("D"); tooltip = L10n.Tr("Deprecated"); @@ -70,6 +78,10 @@ public override void Refresh(IPackageVersion version) UpdateTag(PackageTag.None); else if (version.HasTag(PackageTag.Custom)) UpdateTag(PackageTag.Custom); + else if (version.HasTag(PackageTag.Local)) + UpdateTag(PackageTag.Local); + else if (version.HasTag(PackageTag.Git)) + UpdateTag(PackageTag.Git); else if (version.HasTag(PackageTag.Deprecated)) // We don't want to see the Deprecated tag in the packageItem, but we also want to hide any other tags UpdateTag(m_IsVersionItem ? PackageTag.Deprecated : PackageTag.None); diff --git a/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageScopedRegistryTagLabel.cs b/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageScopedRegistryTagLabel.cs index f237ea73bc..58f4c8f044 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageScopedRegistryTagLabel.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageScopedRegistryTagLabel.cs @@ -15,7 +15,7 @@ public PackageScopedRegistryTagLabel() private bool IsVisible(IPackageVersion version) { - return (version as UpmPackageVersion)?.isUnityPackage == false && !string.IsNullOrEmpty(version.version?.Prerelease); + return (version as UpmPackageVersion)?.HasTag(PackageTag.Unity) == false && !string.IsNullOrEmpty(version.version?.Prerelease); } public override void Refresh(IPackageVersion version) diff --git a/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageSimpleTagLabel.cs b/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageSimpleTagLabel.cs index 7bae16e8c2..68e2bf3ff1 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageSimpleTagLabel.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageSimpleTagLabel.cs @@ -12,7 +12,7 @@ internal class PackageSimpleTagLabel : PackageBaseTagLabel public PackageSimpleTagLabel(PackageTag tag, string text) { m_Tag = tag; - name = "tag" + tag.ToString(); + name = "tag" + tag; this.text = text; } diff --git a/Modules/PackageManagerUI/Editor/UI/ScopedRegistriesSettings.cs b/Modules/PackageManagerUI/Editor/UI/ScopedRegistriesSettings.cs index 765bad5a3f..1047c27510 100644 --- a/Modules/PackageManagerUI/Editor/UI/ScopedRegistriesSettings.cs +++ b/Modules/PackageManagerUI/Editor/UI/ScopedRegistriesSettings.cs @@ -57,7 +57,7 @@ public ScopedRegistriesSettings() scopedRegistriesInfoBox.Q static ReflectedPropertyBagProvider s_PropertyBagProvider = null; - internal static bool HasProvider => null != s_PropertyBagProvider; + // The reflected property bag provider is created inside of a job to lessen the impact on domain reload. + // If it is queried before the job finishes, we go through the slower path. + static ReflectedPropertyBagProvider ReflectedPropertyBagProvider => s_PropertyBagProvider ??= new ReflectedPropertyBagProvider(); internal static List AllTypes => s_RegisteredTypes; @@ -123,7 +124,6 @@ internal static IPropertyBag GetPropertyBag() /// The resolved property bag. internal static IPropertyBag GetPropertyBag(Type type) { - WaitForJobs(); if (s_PropertyBags.TryGetValue(type, out var propertyBag)) { return propertyBag; @@ -149,21 +149,15 @@ internal static IPropertyBag GetPropertyBag(Type type) return null; } - if (null != s_PropertyBagProvider) + propertyBag = ReflectedPropertyBagProvider.CreatePropertyBag(type); + if (null == propertyBag) { - propertyBag = s_PropertyBagProvider.CreatePropertyBag(type); - - if (null == propertyBag) - { - - s_PropertyBags.TryAdd(type, null); - - } - else - { - (propertyBag as IPropertyBagRegister)?.Register(); - return propertyBag; - } + s_PropertyBags.TryAdd(type, null); + } + else + { + (propertyBag as IPropertyBagRegister)?.Register(); + return propertyBag; } return null; diff --git a/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabase.cs b/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabase.cs index 6c27561059..73bf4e3c0b 100644 --- a/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabase.cs +++ b/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabase.cs @@ -766,14 +766,20 @@ public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabase { if (m_PropertyDatabase.disposed) return m_PropertyDatabase.disposedView.TryLoad(recordKey, out data); - if (m_MemoryStoreView.TryLoad(recordKey, out data)) - return true; - if (!m_FileStoreView.TryLoad(recordKey, out data)) + data = PropertyDatabaseRecordValue.invalid; + if (m_MemoryStoreView.TryLoad(recordKey, out PropertyDatabaseRecord memoryRecord, true)) + { + // If data is invalid, it was deliberately made invalid, so it should be invalid in the + // filestore too. + data = memoryRecord.recordValue; + return memoryRecord.IsValid(); + } + if (!m_FileStoreView.TryLoad(recordKey, out PropertyDatabaseRecord fileRecord)) return false; // Cache loaded value into memory store. - var record = CreateRecord(recordKey, data); - m_MemoryStoreView.Store(record, !m_DelayedSync); + data = fileRecord.recordValue; + m_MemoryStoreView.Store(fileRecord, !m_DelayedSync); return true; } } @@ -783,8 +789,11 @@ public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out IPropertyDatabas { if (m_PropertyDatabase.disposed) return m_PropertyDatabase.disposedView.TryLoad(recordKey, out data); - if (m_VolatileMemoryStoreView.TryLoad(recordKey, out data)) + if (m_VolatileMemoryStoreView.TryLoad(recordKey, out IPropertyDatabaseRecord volatileRecord)) + { + data = volatileRecord.value; return true; + } var success = TryLoad(recordKey, out PropertyDatabaseRecordValue recordValue); data = recordValue; @@ -856,7 +865,7 @@ public void Invalidate(ulong documentKey) } m_VolatileMemoryStoreView.Invalidate(documentKey, !m_DelayedSync); m_MemoryStoreView.Invalidate(documentKey, !m_DelayedSync); - m_FileStoreView.Invalidate(documentKey, !m_DelayedSync); + m_FileStoreView.InvalidateInMemory(documentKey, !m_DelayedSync); m_PropertyDatabase.StoresChanged(); } } @@ -871,7 +880,7 @@ public void Invalidate(in PropertyDatabaseRecordKey recordKey) } m_VolatileMemoryStoreView.Invalidate(recordKey, !m_DelayedSync); m_MemoryStoreView.Invalidate(recordKey, !m_DelayedSync); - m_FileStoreView.Invalidate(recordKey, !m_DelayedSync); + m_FileStoreView.InvalidateInMemory(m_MemoryStoreView, recordKey, !m_DelayedSync); m_PropertyDatabase.StoresChanged(); } } @@ -886,7 +895,7 @@ internal void Invalidate(uint documentKeyHiWord) } m_VolatileMemoryStoreView.Invalidate(documentKeyHiWord, !m_DelayedSync); m_MemoryStoreView.Invalidate(documentKeyHiWord, !m_DelayedSync); - m_FileStoreView.Invalidate(documentKeyHiWord, !m_DelayedSync); + m_FileStoreView.InvalidateInMemory(documentKeyHiWord, !m_DelayedSync); m_PropertyDatabase.StoresChanged(); } } @@ -901,7 +910,7 @@ public void InvalidateMask(ulong documentKeyMask) } m_VolatileMemoryStoreView.InvalidateMask(documentKeyMask, !m_DelayedSync); m_MemoryStoreView.InvalidateMask(documentKeyMask, !m_DelayedSync); - m_FileStoreView.InvalidateMask(documentKeyMask, !m_DelayedSync); + m_FileStoreView.InvalidateMaskInMemory(documentKeyMask, !m_DelayedSync); m_PropertyDatabase.StoresChanged(); } } @@ -916,7 +925,7 @@ internal void InvalidateMask(uint documentKeyHiWordMask) } m_VolatileMemoryStoreView.InvalidateMask(documentKeyHiWordMask, !m_DelayedSync); m_MemoryStoreView.InvalidateMask(documentKeyHiWordMask, !m_DelayedSync); - m_FileStoreView.InvalidateMask(documentKeyHiWordMask, !m_DelayedSync); + m_FileStoreView.InvalidateMaskInMemory(documentKeyHiWordMask, !m_DelayedSync); m_PropertyDatabase.StoresChanged(); } } @@ -1107,15 +1116,16 @@ internal void MergeStores() using (new RaceConditionDetector(m_PropertyDatabase)) { // Merge both stores - newMemoryStoreView.MergeWith(m_FileStoreView); - newMemoryStoreView.MergeWith(m_MemoryStoreView); + newMemoryStoreView.MergeWith(m_FileStoreView, false); + newMemoryStoreView.MergeWith(m_MemoryStoreView, false); // Write new memory store to file. var tempFilePath = GetTempFilePath(m_FileStore.filePath); newMemoryStoreView.SaveToFile(tempFilePath); - // Swap file store with new one + // Swap file store with new one, and clear the invalidated documents (since the invalid records were not saved) m_FileStore.SwapFile(tempFilePath); + m_FileStore.ClearInvalidatedDocuments(); // Clear the memory store after file was swapped. If you do it before, you risk // entering a state where another thread could try to read between the moment the clear is done diff --git a/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabaseRecord.cs b/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabaseRecord.cs index 09f2475b01..58aaea5d8b 100644 --- a/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabaseRecord.cs +++ b/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabaseRecord.cs @@ -850,7 +850,7 @@ public int CompareTo(PropertyDatabaseRecordKey other) public bool IsValid() { - return valid == 1; + return validRecord; } public void ToBinary(BinaryWriter bw) diff --git a/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabaseStore.cs b/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabaseStore.cs index 3a190f0a18..a7849f107a 100644 --- a/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabaseStore.cs +++ b/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabaseStore.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -20,24 +21,30 @@ interface IPropertyLockable interface IPropertyDatabaseStore : IPropertyLockable { - bool Store(in PropertyDatabaseRecord record); - bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabaseRecordValue data); - bool TryLoad(in PropertyDatabaseRecordKey recordKey, out IPropertyDatabaseRecordValue data); - bool TryLoad(ulong documentKey, out IEnumerable records); + bool TryLoad(in PropertyDatabaseRecordKey recordKey, out IPropertyDatabaseRecord data, bool loadInvalid); + bool TryLoad(ulong documentKey, out IEnumerable records, bool loadInvalid); void Invalidate(ulong documentKey); void Invalidate(in PropertyDatabaseRecordKey recordKey); void Invalidate(uint documentKeyHiWord); void InvalidateMask(ulong documentKeyMask); void InvalidateMask(uint documentKeyHiWordMask); - IEnumerable EnumerateAll(); + IEnumerable EnumerateAll(bool enumerateInvalid); void Clear(); IPropertyDatabaseStoreView GetView(); } + interface IPropertyDatabaseSerializableStore : IPropertyDatabaseStore + { + bool Store(in PropertyDatabaseRecord record); + bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabaseRecord data, bool loadInvalid); + IEnumerable EnumerateAllSerializableRecords(bool enumerateInvalid); + IPropertyDatabaseSerializableStoreView GetSerializableStoreView(); + } + interface IPropertyDatabaseVolatileStore : IPropertyDatabaseStore { bool Store(in PropertyDatabaseRecordKey recordKey, object value); - bool TryLoad(in PropertyDatabaseRecordKey recordKey, out object data); + bool TryLoad(in PropertyDatabaseRecordKey recordKey, out object data, bool loadInvalid); } interface IPropertyDatabaseStoreView : IDisposable, IPropertyLockable @@ -45,27 +52,34 @@ interface IPropertyDatabaseStoreView : IDisposable, IPropertyLockable long length { get; } long byteSize { get; } - PropertyDatabaseRecord this[long index] { get; } + IPropertyDatabaseRecord this[long index] { get; } - bool Store(in PropertyDatabaseRecord record, bool sync); - bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabaseRecordValue data); - bool TryLoad(in PropertyDatabaseRecordKey recordKey, out IPropertyDatabaseRecordValue data); - bool TryLoad(ulong documentKey, out IEnumerable records); + bool TryLoad(in PropertyDatabaseRecordKey recordKey, out IPropertyDatabaseRecord data, bool loadInvalid); + bool TryLoad(ulong documentKey, out IEnumerable records, bool loadInvalid); void Invalidate(ulong documentKey, bool sync); void Invalidate(in PropertyDatabaseRecordKey recordKey, bool sync); void Invalidate(uint documentKeyHiWord, bool sync); void InvalidateMask(ulong documentKeyMask, bool sync); void InvalidateMask(uint documentKeyHiWordMask, bool sync); - IEnumerable EnumerateAll(); + IEnumerable EnumerateAll(bool enumerateInvalid); void Clear(); void Sync(); bool Find(in PropertyDatabaseRecordKey recordKey, out long index); } + interface IPropertyDatabaseSerializableStoreView : IPropertyDatabaseStoreView + { + new PropertyDatabaseRecord this[long index] { get; } + + bool Store(in PropertyDatabaseRecord record, bool sync); + bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabaseRecord data, bool loadInvalid); + IEnumerable EnumerateAllSerializableRecords(bool enumerateInvalid); + } + interface IPropertyDatabaseVolatileStoreView : IPropertyDatabaseStoreView { bool Store(in PropertyDatabaseRecordKey recordKey, object value, bool sync); - bool TryLoad(in PropertyDatabaseRecordKey recordKey, out object data); + bool TryLoad(in PropertyDatabaseRecordKey recordKey, out object data, bool loadInvalid); } readonly struct PropertyDatabaseDocumentKeyRange : IBinarySearchRange @@ -112,6 +126,11 @@ public static ulong GetULongFromHiWord(uint hiWord) { return (ulong)hiWord << 32; } + + public static uint ToHiWord(ulong documentKey) + { + return (uint)((documentKey & k_HighMask) >> 32); + } } readonly struct PropertyDatabaseDocumentKeyMaskRange : IBinarySearchRange @@ -138,6 +157,16 @@ public bool EndIsInRange(PropertyDatabaseRecordKey end) // Always return true, since we want to go to the end of records return true; } + + public static bool KeyMatchesMask(PropertyDatabaseRecordKey key, ulong mask) + { + return DocumentKeyMatchesMask(key.documentKey, mask); + } + + public static bool DocumentKeyMatchesMask(ulong documentKey, ulong mask) + { + return (documentKey & mask) != 0; + } } static class PropertyDatabaseRecordFinder @@ -276,28 +305,16 @@ abstract class BasePropertyDatabaseStore : IPropertyDatabaseStore { ReaderWriterLockSlim m_Lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); - public bool Store(in PropertyDatabaseRecord record) + public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out IPropertyDatabaseRecord data, bool loadInvalid = false) { using (var view = GetView()) - return view.Store(record, true); + return view.TryLoad(recordKey, out data, loadInvalid); } - public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabaseRecordValue data) + public bool TryLoad(ulong documentKey, out IEnumerable records, bool loadInvalid = false) { using (var view = GetView()) - return view.TryLoad(recordKey, out data); - } - - public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out IPropertyDatabaseRecordValue data) - { - using (var view = GetView()) - return view.TryLoad(recordKey, out data); - } - - public bool TryLoad(ulong documentKey, out IEnumerable records) - { - using (var view = GetView()) - return view.TryLoad(documentKey, out records); + return view.TryLoad(documentKey, out records, loadInvalid); } public void Invalidate(ulong documentKey) @@ -330,10 +347,10 @@ public void InvalidateMask(uint documentKeyHiWordMask) view.InvalidateMask(documentKeyHiWordMask, true); } - public IEnumerable EnumerateAll() + public IEnumerable EnumerateAll(bool enumerateInvalid = false) { using (var view = GetView()) - return view.EnumerateAll(); + return view.EnumerateAll(enumerateInvalid); } public void Clear() @@ -360,48 +377,144 @@ public IDisposable LockWrite() } } - abstract class BasePropertyDatabaseMemoryStore : BasePropertyDatabaseStore - where T : struct + abstract class BasePropertyDatabaseSerializableStore : BasePropertyDatabaseStore, IPropertyDatabaseSerializableStore + { + public bool Store(in PropertyDatabaseRecord record) + { + using (var view = GetSerializableStoreView()) + return view.Store(record, true); + } + + public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabaseRecord data, bool loadInvalid = false) + { + using (var view = GetSerializableStoreView()) + return view.TryLoad(recordKey, out data, loadInvalid); + } + + public IEnumerable EnumerateAllSerializableRecords(bool enumerateInvalid = false) + { + using (var view = GetSerializableStoreView()) + return view.EnumerateAllSerializableRecords(enumerateInvalid); + } + + public abstract IPropertyDatabaseSerializableStoreView GetSerializableStoreView(); + } + + class MemoryDataStore : IList { - protected List m_Store; + List m_Data; + + public int Count => m_Data.Count; + public bool IsReadOnly => false; - public List data => m_Store; + public T this[int index] + { + get => m_Data[index]; + set => m_Data[index] = value; + } - public BasePropertyDatabaseMemoryStore() + public MemoryDataStore() { - m_Store = new List(); + m_Data = new List(); } - public BasePropertyDatabaseMemoryStore(List initialStore) + public MemoryDataStore(IEnumerable initialData) { - m_Store = initialStore; + m_Data = initialData.ToList(); + } + + public void Add(T item) + { + m_Data.Add(item); + } + + public void Clear() + { + m_Data.Clear(); + } + + public void Resize(int capacity) + { + m_Data.Capacity = capacity; + } + + public bool Contains(T item) + { + return m_Data.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + m_Data.CopyTo(array, arrayIndex); + } + + public bool Remove(T item) + { + return m_Data.Remove(item); + } + + public void Assign(List newData) + { + m_Data = newData; + } + + public IEnumerator GetEnumerator() + { + return m_Data.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public int IndexOf(T item) + { + return m_Data.IndexOf(item); + } + + public void Insert(int index, T item) + { + m_Data.Insert(index, item); + } + + public void RemoveAt(int index) + { + m_Data.RemoveAt(index); } } - class PropertyDatabaseMemoryStore : BasePropertyDatabaseMemoryStore + class PropertyDatabaseMemoryStore : BasePropertyDatabaseSerializableStore, IPropertyDatabaseSerializableStore { + protected MemoryDataStore m_Store; + public PropertyDatabaseMemoryStore() - {} + { + m_Store = new MemoryDataStore(); + } - public PropertyDatabaseMemoryStore(List initialStore) - : base(initialStore) - {} + public PropertyDatabaseMemoryStore(IEnumerable initialStore) + { + m_Store = new MemoryDataStore(initialStore); + } - public override IPropertyDatabaseStoreView GetView() + public override IPropertyDatabaseStoreView GetView() => GetSerializableStoreView(); + + public override IPropertyDatabaseSerializableStoreView GetSerializableStoreView() { return new PropertyDatabaseMemoryStoreView(m_Store, this); } } - struct PropertyDatabaseMemoryStoreView : IPropertyDatabaseStoreView, IBinarySearchRangeData + struct PropertyDatabaseMemoryStoreView : IPropertyDatabaseSerializableStoreView, IBinarySearchRangeData { bool m_Disposed; - List m_StoreData; + MemoryDataStore m_MemoryDataStore; PropertyDatabaseMemoryStore m_Store; - public PropertyDatabaseMemoryStoreView(List storeData, PropertyDatabaseMemoryStore store) + public PropertyDatabaseMemoryStoreView(MemoryDataStore memoryDataStore, PropertyDatabaseMemoryStore store) { - m_StoreData = storeData; + m_MemoryDataStore = memoryDataStore; m_Store = store; m_Disposed = false; } @@ -411,7 +524,7 @@ public void Dispose() if (m_Disposed) return; m_Store = null; - m_StoreData = null; + m_MemoryDataStore = null; m_Disposed = true; } @@ -425,40 +538,36 @@ public bool Store(in PropertyDatabaseRecord record, bool sync) using (LockWrite()) { if (insert) - m_StoreData.Insert((int)index, record); + m_MemoryDataStore.Insert((int)index, record); else - m_StoreData[(int)index] = record; + m_MemoryDataStore[(int)index] = record; return true; } } } - public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabaseRecordValue data) + public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabaseRecord data, bool loadInvalid = false) { - data = PropertyDatabaseRecordValue.invalid; + data = PropertyDatabaseRecord.invalid; using (LockRead()) { var foundRecord = Find(recordKey, out var index); if (!foundRecord) return false; - var record = m_StoreData[(int)index]; - if (!record.IsValid()) - return false; - - data = record.recordValue; - return true; + data = m_MemoryDataStore[(int)index]; + return data.IsValid() || loadInvalid; } } - public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out IPropertyDatabaseRecordValue data) + public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out IPropertyDatabaseRecord data, bool loadInvalid = false) { - var success = TryLoad(recordKey, out PropertyDatabaseRecordValue record); + var success = TryLoad(recordKey, out PropertyDatabaseRecord record, loadInvalid); data = record; return success; } - public bool TryLoad(ulong documentKey, out IEnumerable records) + public bool TryLoad(ulong documentKey, out IEnumerable records, bool loadInvalid = false) { records = null; using (LockRead()) @@ -467,12 +576,11 @@ public bool TryLoad(ulong documentKey, out IEnumerable if (binarySearchRange == BinarySearchRange.invalid) return false; - var result = new List(); for (var i = binarySearchRange.startOffset; i < binarySearchRange.endOffset; ++i) { - var record = m_StoreData[(int)i]; - if (record.IsValid()) + var record = m_MemoryDataStore[(int)i]; + if (record.IsValid() || loadInvalid) result.Add(record); } @@ -527,9 +635,9 @@ public void Invalidate(in PropertyDatabaseRecordKey recordKey, bool sync) using (LockWrite()) { - var record = m_StoreData[(int)index]; + var record = m_MemoryDataStore[(int)index]; var newRecord = new PropertyDatabaseRecord(record.recordKey, record.recordValue, false); - m_StoreData[(int)index] = newRecord; + m_MemoryDataStore[(int)index] = newRecord; } } } @@ -564,57 +672,118 @@ public void InvalidateMask(uint documentKeyHiWordMask, bool sync) InvalidateMask(documentKeyMask, sync); } - public IEnumerable EnumerateAll() + public IEnumerable EnumerateAll(bool enumerateInvalid = false) + { + return EnumerateAllSerializableRecords(enumerateInvalid).Cast(); + } + + public IEnumerable EnumerateAllSerializableRecords(bool enumerateInvalid = false) { using (LockRead()) { - return m_StoreData.Where(p => p.IsValid()).Cast().ToList(); + return m_MemoryDataStore.Where(p => p.IsValid() || enumerateInvalid).ToList(); } } - public long length => m_StoreData.Count; + public long length => m_MemoryDataStore.Count; public long byteSize => length * PropertyDatabaseRecord.size; - public PropertyDatabaseRecordKey this[long index] => m_StoreData[(int)index].recordKey; + public PropertyDatabaseRecordKey this[long index] => m_MemoryDataStore[(int)index].recordKey; - PropertyDatabaseRecord IPropertyDatabaseStoreView.this[long index] => m_StoreData[(int)index]; + IPropertyDatabaseRecord IPropertyDatabaseStoreView.this[long index] => m_MemoryDataStore[(int)index]; + PropertyDatabaseRecord IPropertyDatabaseSerializableStoreView.this[long index] => m_MemoryDataStore[(int)index]; - public void MergeWith(IPropertyDatabaseStore store) + public void MergeWith(IPropertyDatabaseSerializableStore store, bool overrideWithInvalid) { - using (var otherView = store.GetView()) - MergeWith(otherView); + using (var otherView = store.GetSerializableStoreView()) + MergeWith(otherView, overrideWithInvalid); } - public void MergeWith(IPropertyDatabaseStoreView view) + public void MergeWith(IPropertyDatabaseSerializableStoreView view, bool overrideWithInvalid) { using (LockWrite()) using (view.LockRead()) { - for (var i = 0; i < view.length; ++i) - { - var record = view[i]; - if (record.IsValid()) - Store(record, true); - } + MergeWith(view.EnumerateAllSerializableRecords(overrideWithInvalid), overrideWithInvalid); } } - public void MergeWith(IEnumerable records) + public void MergeWith(IEnumerable records, bool overrideWithInvalid) { + var newRecordsList = records.ToList(); + var newRecordsCount = newRecordsList.Count; + using (LockWrite()) { - foreach (var record in records) + if (m_MemoryDataStore.Count == 0) + { + m_MemoryDataStore.Resize(newRecordsCount); + foreach (var record in newRecordsList) + { + if (record.IsValid() || overrideWithInvalid) + m_MemoryDataStore.Add(record); // Assume already in order + } + } + else { - if (record.IsValid()) - Store(record, true); + var existingRecordsCount = m_MemoryDataStore.Count; + + var newData = new List(existingRecordsCount + newRecordsCount); + + var existingRecordsIndex = 0; + var newRecordsIndex = 0; + while (existingRecordsIndex < existingRecordsCount && newRecordsIndex < newRecordsCount) + { + var existingRecord = m_MemoryDataStore[existingRecordsIndex]; + var newRecord = newRecordsList[newRecordsIndex]; + + var compare = existingRecord.CompareTo(newRecord); + if (compare < 0) + { + newData.Add(existingRecord); + ++existingRecordsIndex; + } + else if (compare > 0) + { + if (newRecord.IsValid() || overrideWithInvalid) + newData.Add(newRecord); + ++newRecordsIndex; + } + else + { + if (newRecord.IsValid() || overrideWithInvalid) + newData.Add(newRecord); + else + newData.Add(existingRecord); + ++existingRecordsIndex; + ++newRecordsIndex; + } + } + + // Either the existing records or the new records have not finished merging. Try them both + while (existingRecordsIndex < existingRecordsCount) + { + newData.Add(m_MemoryDataStore[existingRecordsIndex]); + ++existingRecordsIndex; + } + + while (newRecordsIndex < newRecordsCount) + { + var newRecord = newRecordsList[newRecordsIndex]; + if (newRecord.IsValid() || overrideWithInvalid) + newData.Add(newRecord); + ++newRecordsIndex; + } + + m_MemoryDataStore.Assign(newData); } } } public void Clear() { - using (m_Store.LockWrite()) - m_StoreData.Clear(); + using (LockWrite()) + m_MemoryDataStore.Clear(); } public void SaveToFile(string filePath) @@ -628,7 +797,7 @@ public void SaveToFile(string filePath) { var bw = new BinaryWriter(fs); bw.Write(PropertyDatabase.version); - foreach (var databaseRecord in m_StoreData) + foreach (var databaseRecord in m_MemoryDataStore) { databaseRecord.ToBinary(bw); } @@ -643,9 +812,9 @@ void InvalidateRange(BinarySearchRange binarySearchRange) { for (var i = binarySearchRange.startOffset; i < binarySearchRange.endOffset; ++i) { - var record = m_StoreData[(int)i]; + var record = m_MemoryDataStore[(int)i]; var newRecord = new PropertyDatabaseRecord(record.recordKey, record.recordValue, false); - m_StoreData[(int)i] = newRecord; + m_MemoryDataStore[(int)i] = newRecord; } } } @@ -656,38 +825,44 @@ void InvalidateMaskRange(BinarySearchRange binarySearchRange, ulong documentKeyM { for (var i = binarySearchRange.startOffset; i < binarySearchRange.endOffset; ++i) { - var record = m_StoreData[(int)i]; - if ((record.key.documentKey & documentKeyMask) != 0) + var record = m_MemoryDataStore[(int)i]; + if (PropertyDatabaseDocumentKeyMaskRange.KeyMatchesMask(record.key, documentKeyMask)) { var newRecord = new PropertyDatabaseRecord(record.recordKey, record.recordValue, false); - m_StoreData[(int)i] = newRecord; + m_MemoryDataStore[(int)i] = newRecord; } } } } } - class PropertyDatabaseFileStore : BasePropertyDatabaseStore + class PropertyDatabaseFileStore : BasePropertyDatabaseSerializableStore { public string filePath { get; } event Action m_FileStoreChanged; event Action m_FileStoreAboutToChange; + HashSet m_InvalidatedDocumentKeys; + HashSet m_InvalidatedDocumentKeyHiWords; + HashSet m_InvalidatedDocumentKeyMasks; + public PropertyDatabaseFileStore(string filePath) { this.filePath = filePath; + m_InvalidatedDocumentKeys = new HashSet(); + m_InvalidatedDocumentKeyHiWords = new HashSet(); + m_InvalidatedDocumentKeyMasks = new HashSet(); } public override IPropertyDatabaseStoreView GetView() { - return new PropertyDatabaseFileStoreView(filePath, this); + return GetSerializableStoreView(); } - public PropertyDatabaseMemoryStore ToMemoryStore() + public override IPropertyDatabaseSerializableStoreView GetSerializableStoreView() { - using (var view = new PropertyDatabaseFileStoreView(filePath, this)) - return view.ToMemoryStore(); + return new PropertyDatabaseFileStoreView(filePath, this, m_InvalidatedDocumentKeys, m_InvalidatedDocumentKeyHiWords, m_InvalidatedDocumentKeyMasks); } public void SwapFile(string filePathToSwap) @@ -709,6 +884,16 @@ public void SwapFile(string filePathToSwap) } } + public void ClearInvalidatedDocuments() + { + using (LockWrite()) + { + m_InvalidatedDocumentKeys.Clear(); + m_InvalidatedDocumentKeyHiWords.Clear(); + m_InvalidatedDocumentKeyMasks.Clear(); + } + } + public void RegisterFileStoreChangedHandler(Action handler) { using (LockWrite()) @@ -748,15 +933,20 @@ public void NotifyFileStoreAboutToChange() // This needs to be a class, since it registers a itself for changes and the event modifies the filestream. // With a struct only the copy would get modified. - class PropertyDatabaseFileStoreView : IPropertyDatabaseStoreView, IBinarySearchRangeData + class PropertyDatabaseFileStoreView : IPropertyDatabaseSerializableStoreView, IBinarySearchRangeData { bool m_Disposed; FileStream m_Fs; BinaryReader m_Br; BinaryWriter m_Bw; PropertyDatabaseFileStore m_Store; + bool m_NeedsSync; - public PropertyDatabaseFileStoreView(string filePath, PropertyDatabaseFileStore store) + HashSet m_InvalidatedDocumentKeys; + HashSet m_InvalidatedDocumentKeyHiWords; + HashSet m_InvalidatedDocumentKeyMasks; + + public PropertyDatabaseFileStoreView(string filePath, PropertyDatabaseFileStore store, HashSet invalidatedDocumentKeys, HashSet invalidatedDocumentKeyHiWords, HashSet invalidatedDocumentKeyMasks) { length = 0; m_Disposed = false; @@ -764,6 +954,9 @@ public PropertyDatabaseFileStoreView(string filePath, PropertyDatabaseFileStore m_Br = null; m_Bw = null; m_Store = store; + m_InvalidatedDocumentKeys = invalidatedDocumentKeys; + m_InvalidatedDocumentKeyHiWords = invalidatedDocumentKeyHiWords; + m_InvalidatedDocumentKeyMasks = invalidatedDocumentKeyMasks; // All fields must be assigned before calling any functions. store.RegisterFileStoreChangedHandler(HandleFileStoreChanged); store.RegisterFileStoreAboutToChangeHandler(HandleFileStoreAboutToChange); @@ -810,39 +1003,33 @@ public bool Store(in PropertyDatabaseRecord record, bool sync) throw new NotSupportedException(); } - public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabaseRecordValue data) + public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabaseRecord data, bool loadInvalid = false) { - data = PropertyDatabaseRecordValue.invalid; + data = PropertyDatabaseRecord.invalid; using (LockRead()) { var foundRecord = Find(recordKey, out var index); if (!foundRecord) return false; - var record = GetRecord(index); - if (!record.IsValid()) - return false; - - data = record.recordValue; - return true; + data = GetRecord(index); + return data.IsValid() || loadInvalid; } } - public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out IPropertyDatabaseRecordValue data) + public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out IPropertyDatabaseRecord data, bool loadInvalid = false) { - var success = TryLoad(recordKey, out PropertyDatabaseRecordValue record); + var success = TryLoad(recordKey, out PropertyDatabaseRecord record, loadInvalid); data = record; return success; } - public bool TryLoad(ulong documentKey, out IEnumerable records) + public bool TryLoad(ulong documentKey, out IEnumerable records, bool loadInvalid = false) { records = null; using (LockRead()) { - if (m_Fs == null) - return false; - var binarySearchRange = PropertyDatabaseRecordFinder.FindRange(this, documentKey); + var binarySearchRange = FindRange(documentKey); if (binarySearchRange == BinarySearchRange.invalid) return false; @@ -850,7 +1037,7 @@ public bool TryLoad(ulong documentKey, out IEnumerable for (var i = binarySearchRange.startOffset; i < binarySearchRange.endOffset; ++i) { var record = GetRecord(i); - if (record.IsValid()) + if (record.IsValid() || loadInvalid) result.Add(record); } @@ -863,9 +1050,7 @@ public void Invalidate(ulong documentKey, bool sync) { using (LockUpgradeableRead()) { - if (m_Fs == null) - return; - var binarySearchRange = PropertyDatabaseRecordFinder.FindRange(this, documentKey); + var binarySearchRange = FindRange(documentKey); if (binarySearchRange == BinarySearchRange.invalid) return; @@ -873,12 +1058,18 @@ public void Invalidate(ulong documentKey, bool sync) } } + public void InvalidateInMemory(ulong documentKey, bool sync) + { + using (LockWrite()) + { + m_InvalidatedDocumentKeys.Add(documentKey); + } + } + public void Invalidate(in PropertyDatabaseRecordKey recordKey, bool sync) { using (LockUpgradeableRead()) { - if (m_Fs == null) - return; var foundRecord = Find(recordKey, out var index); if (!foundRecord) return; @@ -892,13 +1083,25 @@ public void Invalidate(in PropertyDatabaseRecordKey recordKey, bool sync) } } + public void InvalidateInMemory(PropertyDatabaseMemoryStoreView memoryView, in PropertyDatabaseRecordKey recordKey, bool sync) + { + using (LockRead()) + { + var foundRecord = Find(recordKey, out var index); + if (!foundRecord) + return; + + var record = GetRecord(index); + var newRecord = new PropertyDatabaseRecord(record.recordKey, record.recordValue, false); + memoryView.Store(newRecord, sync); + } + } + public void Invalidate(uint documentKeyHiWord, bool sync) { using (LockUpgradeableRead()) { - if (m_Fs == null) - return; - var binarySearchRange = PropertyDatabaseRecordFinder.FindHiWordRange(this, documentKeyHiWord); + var binarySearchRange = FindRange(documentKeyHiWord); if (binarySearchRange == BinarySearchRange.invalid) return; @@ -906,13 +1109,19 @@ public void Invalidate(uint documentKeyHiWord, bool sync) } } + public void InvalidateInMemory(uint documentKeyHiWord, bool sync) + { + using (LockWrite()) + { + m_InvalidatedDocumentKeyHiWords.Add(documentKeyHiWord); + } + } + public void InvalidateMask(ulong documentKeyMask, bool sync) { using (LockUpgradeableRead()) { - if (m_Fs == null) - return; - var binarySearchRange = PropertyDatabaseRecordFinder.FindMaskRange(this, documentKeyMask); + var binarySearchRange = FindMaskRange(documentKeyMask); if (binarySearchRange == BinarySearchRange.invalid) return; @@ -920,28 +1129,44 @@ public void InvalidateMask(ulong documentKeyMask, bool sync) } } + public void InvalidateMaskInMemory(ulong documentKeyMask, bool sync) + { + using (LockRead()) + { + m_InvalidatedDocumentKeyMasks.Add(documentKeyMask); + } + } + public void InvalidateMask(uint documentKeyHiWordMask, bool sync) { var documentKeyMask = PropertyDatabaseDocumentKeyHiWordRange.GetULongFromHiWord(documentKeyHiWordMask); InvalidateMask(documentKeyMask, sync); } - public IEnumerable EnumerateAll() + public void InvalidateMaskInMemory(uint documentKeyHiWordMask, bool sync) + { + var documentKeyMask = PropertyDatabaseDocumentKeyHiWordRange.GetULongFromHiWord(documentKeyHiWordMask); + InvalidateMaskInMemory(documentKeyMask, sync); + } + + public IEnumerable EnumerateAll(bool enumerateInvalid = false) + { + return EnumerateAllSerializableRecords(enumerateInvalid).Cast(); + } + + public IEnumerable EnumerateAllSerializableRecords(bool enumerateInvalid = false) { using (LockRead()) { if (m_Fs == null) - return Enumerable.Empty(); + yield break; - var allRecords = new List((int)length); for (var i = 0; i < length; ++i) { var record = GetRecord(i); - if (record.IsValid()) - allRecords.Add(record); + if (record.IsValid() || enumerateInvalid) + yield return record; } - - return allRecords; } } @@ -955,12 +1180,16 @@ public void Clear() m_Fs.Seek(0, SeekOrigin.Begin); m_Bw.Write(PropertyDatabase.version); m_Fs.Flush(true); + m_Store.ClearInvalidatedDocuments(); m_Store.NotifyFileStoreChanged(); } } public void Sync() { + if (!m_NeedsSync) + return; + m_NeedsSync = false; using (LockWrite()) { if (m_Fs == null) @@ -971,6 +1200,9 @@ public void Sync() public bool Find(in PropertyDatabaseRecordKey recordKey, out long index) { + index = -1; + if (m_Fs == null) + return false; using (LockRead()) return PropertyDatabaseRecordFinder.Find(this, recordKey, out index); } @@ -990,32 +1222,13 @@ public IDisposable LockWrite() return m_Store.LockWrite(); } - public PropertyDatabaseMemoryStore ToMemoryStore() - { - using (LockRead()) - { - if (length == 0) - return new PropertyDatabaseMemoryStore(); - - var localStore = new List((int)length); - - for (var i = 0; i < length; ++i) - { - m_Fs.Seek(GetFileOffset(i), SeekOrigin.Begin); - var record = PropertyDatabaseRecord.FromBinary(m_Br); - localStore.Add(record); - } - - return new PropertyDatabaseMemoryStore(localStore); - } - } - public long length { get; private set; } public long byteSize => length * PropertyDatabaseRecord.size + sizeof(int); public PropertyDatabaseRecordKey this[long index] => GetRecordKey(index); - PropertyDatabaseRecord IPropertyDatabaseStoreView.this[long index] => GetRecord(index); + IPropertyDatabaseRecord IPropertyDatabaseStoreView.this[long index] => GetRecord(index); + PropertyDatabaseRecord IPropertyDatabaseSerializableStoreView.this[long index] => GetRecord(index); void OpenFileStream(string path) { @@ -1061,7 +1274,8 @@ PropertyDatabaseRecord GetRecord(long index) var fileOffset = GetFileOffset((int)index); m_Fs.Seek(fileOffset, SeekOrigin.Begin); - return PropertyDatabaseRecord.FromBinary(m_Br); + var record = PropertyDatabaseRecord.FromBinary(m_Br); + return IsRecordKeyValid(record.recordKey) ? record : new PropertyDatabaseRecord(record.recordKey, record.recordValue, false); } PropertyDatabaseRecordKey GetRecordKey(long index) @@ -1076,7 +1290,20 @@ PropertyDatabaseRecordKey GetRecordKey(long index) return PropertyDatabaseRecordKey.FromBinary(m_Br); } - void WriteRecord(in PropertyDatabaseRecord record, long index, bool flush = true) + bool IsRecordKeyValid(PropertyDatabaseRecordKey recordKey) + { + var documentKey = recordKey.documentKey; + if (m_InvalidatedDocumentKeys.Contains(documentKey)) + return false; + var documentKeyHiWord = PropertyDatabaseDocumentKeyHiWordRange.ToHiWord(documentKey); + if (m_InvalidatedDocumentKeyHiWords.Contains(documentKeyHiWord)) + return false; + if (m_InvalidatedDocumentKeyMasks.Any(mask => PropertyDatabaseDocumentKeyMaskRange.DocumentKeyMatchesMask(documentKey, mask))) + return false; + return true; + } + + void WriteRecord(in PropertyDatabaseRecord record, long index, bool sync = true) { if (m_Fs == null) return; @@ -1086,9 +1313,10 @@ void WriteRecord(in PropertyDatabaseRecord record, long index, bool flush = true var fileOffset = GetFileOffset((int)index); m_Bw.Seek(fileOffset, SeekOrigin.Begin); record.ToBinary(m_Bw); + m_NeedsSync = true; - if (flush) - m_Fs.Flush(true); + if (sync) + Sync(); } int GetFileOffset(int recordIndex) @@ -1118,7 +1346,7 @@ void InvalidateMaskRange(BinarySearchRange binarySearchRange, ulong documentKeyM for (var i = binarySearchRange.startOffset; i < binarySearchRange.endOffset; ++i) { var record = GetRecord(i); - if ((record.key.documentKey & documentKeyMask) != 0) + if (PropertyDatabaseDocumentKeyMaskRange.KeyMatchesMask(record.key, documentKeyMask)) { var newRecord = new PropertyDatabaseRecord(record.recordKey, record.recordValue, false); WriteRecord(newRecord, i, false); @@ -1128,6 +1356,49 @@ void InvalidateMaskRange(BinarySearchRange binarySearchRange, ulong documentKeyM Sync(); } } + + public IEnumerable EnumerateRange(BinarySearchRange range) + { + using (LockRead()) + { + for (var i = range.startOffset; i < range.endOffset; ++i) + yield return GetRecord(i); + } + } + + public IEnumerable EnumerateMaskRange(BinarySearchRange range, ulong documentKeyMask) + { + using (LockRead()) + { + for (var i = range.startOffset; i < range.endOffset; ++i) + { + var record = GetRecord(i); + if (PropertyDatabaseDocumentKeyMaskRange.KeyMatchesMask(record.key, documentKeyMask)) + yield return record; + } + } + } + + public BinarySearchRange FindRange(ulong documentKey) + { + return m_Fs == null ? BinarySearchRange.invalid : PropertyDatabaseRecordFinder.FindRange(this, documentKey); + } + + public BinarySearchRange FindRange(uint documentKeyHiWord) + { + return m_Fs == null ? BinarySearchRange.invalid : PropertyDatabaseRecordFinder.FindHiWordRange(this, documentKeyHiWord); + } + + public BinarySearchRange FindMaskRange(ulong documentKeyMask) + { + return m_Fs == null ? BinarySearchRange.invalid : PropertyDatabaseRecordFinder.FindMaskRange(this, documentKeyMask); + } + + public BinarySearchRange FindMaskRange(uint documentKeyHiWordMask) + { + var documentKeyMask = PropertyDatabaseDocumentKeyHiWordRange.GetULongFromHiWord(documentKeyHiWordMask); + return FindMaskRange(documentKeyMask); + } } struct PropertyDatabaseVolatileRecordValue : IPropertyDatabaseRecordValue @@ -1155,6 +1426,8 @@ public PropertyDatabaseVolatileRecordValue(object value) public static int size => PropertyDatabaseRecordKey.size + sizeof(bool) + PropertyDatabaseVolatileRecordValue.size; + public static PropertyDatabaseVolatileRecord invalid => new(); + public PropertyDatabaseVolatileRecord(in PropertyDatabaseRecordKey key, object value) { this.recordKey = key; @@ -1170,8 +1443,20 @@ public PropertyDatabaseVolatileRecord(in PropertyDatabaseRecordKey key, object v } } - class PropertyDatabaseVolatileMemoryStore : BasePropertyDatabaseMemoryStore, IPropertyDatabaseVolatileStore + class PropertyDatabaseVolatileMemoryStore : BasePropertyDatabaseStore, IPropertyDatabaseVolatileStore { + protected MemoryDataStore m_Store; + + public PropertyDatabaseVolatileMemoryStore() + { + m_Store = new MemoryDataStore(); + } + + public PropertyDatabaseVolatileMemoryStore(IEnumerable initialStore) + { + m_Store = new MemoryDataStore(initialStore); + } + public override IPropertyDatabaseStoreView GetView() { return new PropertyDatabaseVolatileMemoryStoreView(this, m_Store); @@ -1183,10 +1468,10 @@ public bool Store(in PropertyDatabaseRecordKey recordKey, object value) return view.Store(recordKey, value, true); } - public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out object data) + public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out object data, bool loadInvalid = false) { using (var view = (PropertyDatabaseVolatileMemoryStoreView)GetView()) - return view.TryLoad(recordKey, out data); + return view.TryLoad(recordKey, out data, loadInvalid); } } @@ -1194,12 +1479,12 @@ struct PropertyDatabaseVolatileMemoryStoreView : IPropertyDatabaseVolatileStoreV { bool m_Disposed; PropertyDatabaseVolatileMemoryStore m_VolatileStore; - List m_StoreData; + MemoryDataStore m_MemoryDataStore; - public PropertyDatabaseVolatileMemoryStoreView(PropertyDatabaseVolatileMemoryStore volatileStore, List storeData) + public PropertyDatabaseVolatileMemoryStoreView(PropertyDatabaseVolatileMemoryStore volatileStore, MemoryDataStore memoryDataStore) { m_VolatileStore = volatileStore; - m_StoreData = storeData; + m_MemoryDataStore = memoryDataStore; m_Disposed = false; } @@ -1209,7 +1494,7 @@ public void Dispose() return; m_VolatileStore = null; - m_StoreData = null; + m_MemoryDataStore = null; m_Disposed = true; } @@ -1228,32 +1513,32 @@ public IDisposable LockWrite() return m_VolatileStore.LockWrite(); } - public long length => m_StoreData.Count; + public long length => m_MemoryDataStore.Count; public long byteSize => length * PropertyDatabaseVolatileRecord.size; - PropertyDatabaseRecordKey IBinarySearchRangeData.this[long index] => m_StoreData[(int)index].key; + PropertyDatabaseRecordKey IBinarySearchRangeData.this[long index] => m_MemoryDataStore[(int)index].key; - public PropertyDatabaseRecord this[long index] => throw new NotSupportedException(); + public IPropertyDatabaseRecord this[long index] => throw new NotSupportedException(); public bool Store(in PropertyDatabaseRecord record, bool sync) { throw new NotSupportedException(); } - public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabaseRecordValue data) + public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabaseRecord data, bool loadInvalid = false) { throw new NotSupportedException(); } - public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out IPropertyDatabaseRecordValue data) + public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out IPropertyDatabaseRecord data, bool loadInvalid = false) { - var success = TryLoad(recordKey, out PropertyDatabaseVolatileRecordValue record); + var success = TryLoad(recordKey, out PropertyDatabaseVolatileRecord record, loadInvalid); data = record; return success; } - public bool TryLoad(ulong documentKey, out IEnumerable records) + public bool TryLoad(ulong documentKey, out IEnumerable records, bool loadInvalid = false) { records = null; using (LockRead()) @@ -1265,8 +1550,8 @@ public bool TryLoad(ulong documentKey, out IEnumerable var result = new List(); for (var i = binarySearchRange.startOffset; i < binarySearchRange.endOffset; ++i) { - var record = m_StoreData[(int)i]; - if (record.valid) + var record = m_MemoryDataStore[(int)i]; + if (record.validRecord || loadInvalid) result.Add(record); } @@ -1297,9 +1582,9 @@ public void Invalidate(in PropertyDatabaseRecordKey recordKey, bool sync) using (LockWrite()) { - var record = m_StoreData[(int)index]; + var record = m_MemoryDataStore[(int)index]; var newRecord = new PropertyDatabaseVolatileRecord(record.key, record.recordValue.value, false); - m_StoreData[(int)index] = newRecord; + m_MemoryDataStore[(int)index] = newRecord; } } } @@ -1334,18 +1619,18 @@ public void InvalidateMask(uint documentKeyHiWordMask, bool sync) InvalidateMask(documentKeyMask, sync); } - public IEnumerable EnumerateAll() + public IEnumerable EnumerateAll(bool enumerateInvalid = false) { using (LockRead()) { - return m_StoreData.Where(p => p.valid).Cast().ToList(); + return m_MemoryDataStore.Where(p => p.valid || enumerateInvalid).Cast().ToList(); } } public void Clear() { using (LockWrite()) - m_StoreData.Clear(); + m_MemoryDataStore.Clear(); } public void Sync() @@ -1368,36 +1653,32 @@ public bool Store(in PropertyDatabaseRecordKey recordKey, object value, bool syn using (LockWrite()) { if (insert) - m_StoreData.Insert((int)index, newRecord); + m_MemoryDataStore.Insert((int)index, newRecord); else - m_StoreData[(int)index] = newRecord; + m_MemoryDataStore[(int)index] = newRecord; return true; } } } - public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out object data) + public bool TryLoad(in PropertyDatabaseRecordKey recordKey, out object data, bool loadInvalid = false) { - var success = TryLoad(recordKey, out PropertyDatabaseVolatileRecordValue record); - data = record.value; + var success = TryLoad(recordKey, out PropertyDatabaseVolatileRecord record, loadInvalid); + data = record.recordValue.value; return success; } - bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabaseVolatileRecordValue data) + bool TryLoad(in PropertyDatabaseRecordKey recordKey, out PropertyDatabaseVolatileRecord data, bool loadInvalid = false) { - data = new PropertyDatabaseVolatileRecordValue(); + data = PropertyDatabaseVolatileRecord.invalid; using (LockRead()) { var foundRecord = Find(recordKey, out var index); if (!foundRecord) return false; - var record = m_StoreData[(int)index]; - if (!record.valid) - return false; - - data = record.recordValue; - return true; + data = m_MemoryDataStore[(int)index]; + return data.valid || loadInvalid; } } @@ -1407,9 +1688,9 @@ void InvalidateRange(BinarySearchRange binarySearchRange) { for (var i = binarySearchRange.startOffset; i < binarySearchRange.endOffset; ++i) { - var record = m_StoreData[(int)i]; + var record = m_MemoryDataStore[(int)i]; var newRecord = new PropertyDatabaseVolatileRecord(record.key, record.recordValue.value, false); - m_StoreData[(int)i] = newRecord; + m_MemoryDataStore[(int)i] = newRecord; } } } @@ -1420,11 +1701,11 @@ void InvalidateMaskRange(BinarySearchRange binarySearchRange, ulong documentKeyM { for (var i = binarySearchRange.startOffset; i < binarySearchRange.endOffset; ++i) { - var record = m_StoreData[(int)i]; - if ((record.key.documentKey & documentKeyMask) != 0) + var record = m_MemoryDataStore[(int)i]; + if (PropertyDatabaseDocumentKeyMaskRange.KeyMatchesMask(record.key, documentKeyMask)) { var newRecord = new PropertyDatabaseVolatileRecord(record.key, record.recordValue.value, false); - m_StoreData[(int)i] = newRecord; + m_MemoryDataStore[(int)i] = newRecord; } } } diff --git a/Modules/QuickSearch/Editor/PropertyDatabase/PropertyStringTable.cs b/Modules/QuickSearch/Editor/PropertyDatabase/PropertyStringTable.cs index 2edb21565f..0674add93a 100644 --- a/Modules/QuickSearch/Editor/PropertyDatabase/PropertyStringTable.cs +++ b/Modules/QuickSearch/Editor/PropertyDatabase/PropertyStringTable.cs @@ -201,6 +201,7 @@ class PropertyStringTableView : IDisposable, IPropertyLockable BinaryWriter m_Bw; PropertyStringTableHeader m_Header; PropertyStringTable m_StringTable; + bool m_NeedsSync; public int version { @@ -513,6 +514,7 @@ public void Grow(int newStringCount) WriteHeader(false); + m_NeedsSync = true; if (!m_DelayedSync) Sync(); } @@ -537,6 +539,8 @@ public void Clear() m_Fs.Seek(0, SeekOrigin.Begin); WriteHeader(false); m_Fs.SetLength(newFileSize); + + m_NeedsSync = true; Sync(); } } @@ -605,6 +609,7 @@ void WriteHeader(bool notify) m_Fs.Seek(0, SeekOrigin.Begin); m_Header.ToBinary(m_Bw); + m_NeedsSync = true; if (notify && !m_DelayedSync) Sync(); } @@ -630,6 +635,7 @@ void WriteSymbol(int symbolIndex, int symbol) { m_Fs.Seek(GetSymbolsOffset() + symbolIndex * PropertyStringTable.symbolByteSize, SeekOrigin.Begin); WriteInt32(symbol); + m_NeedsSync = true; } } @@ -647,6 +653,7 @@ void WriteStringAtSymbol(int symbolIndex, int symbol, string str, PropertyString // Notify other views that the WriteHeader(false); + m_NeedsSync = true; if (!m_DelayedSync) Sync(); } @@ -679,6 +686,9 @@ void FlushFile() public void Sync() { + if (!m_NeedsSync) + return; + m_NeedsSync = false; using (LockWrite()) { FlushFile(); diff --git a/Modules/QuickSearch/Editor/QueryBuilder/QueryBlock.cs b/Modules/QuickSearch/Editor/QueryBuilder/QueryBlock.cs index 398fae3ed2..0879a3f3bc 100644 --- a/Modules/QuickSearch/Editor/QueryBuilder/QueryBlock.cs +++ b/Modules/QuickSearch/Editor/QueryBuilder/QueryBlock.cs @@ -136,7 +136,6 @@ void OpenMenu(Event evt) if (menu.GetItemCount() > 0) { menu.ShowAsContext(); - evt.Use(); } } diff --git a/Modules/QuickSearch/Editor/SearchList.cs b/Modules/QuickSearch/Editor/SearchList.cs index d7e425e897..86daa140ab 100644 --- a/Modules/QuickSearch/Editor/SearchList.cs +++ b/Modules/QuickSearch/Editor/SearchList.cs @@ -814,6 +814,7 @@ public ConcurrentSearchList(SearchContext searchContext) : base(searchContext) { m_UnorderedItems = new ConcurrentBag(); searchContext.sessionStarted += SearchContextOnsessionStarted; + m_SearchStarted = searchContext.searchInProgress; } protected override void Dispose(bool disposing) diff --git a/Modules/QuickSearch/Editor/SearchService.cs b/Modules/QuickSearch/Editor/SearchService.cs index c83aebc133..0ace22d218 100644 --- a/Modules/QuickSearch/Editor/SearchService.cs +++ b/Modules/QuickSearch/Editor/SearchService.cs @@ -337,7 +337,7 @@ public static List GetItems(SearchContext context, SearchFlags optio // Transfer all options from options to context.options context.options |= options; - + int fetchProviderCount = 0; var allItems = new List(3); @@ -384,6 +384,10 @@ static void HandleItemsIteratorSession(object iterator, List allItem { if (iterator != null && context.options.HasAny(SearchFlags.Synchronous)) { + var session = context.sessions.GetProviderSession(provider); + session.Reset(context.sessions.currentSessionContext, iterator, k_MaxFetchTimeMs, k_MaxSessionTimeMs); + session.Start(); + using (var stackedEnumerator = new SearchEnumerator(iterator)) { while (stackedEnumerator.MoveNext()) @@ -392,6 +396,8 @@ static void HandleItemsIteratorSession(object iterator, List allItem allItems.Add(stackedEnumerator.Current); } } + + session.Stop(); } else { @@ -789,7 +795,7 @@ public static void CreateIndex( if (options.HasNone(IndexingOptions.Temporary)) { indexName = System.IO.Path.GetFileNameWithoutExtension(indexPath); - if (!AssetDatabase.GetAssetFolderInfo(indexPath, out var rootFolder, out var immutable) || immutable) + if (!AssetDatabase.TryGetAssetFolderInfo(indexPath, out var rootFolder, out var immutable) || immutable) indexPath = AssetDatabase.GenerateUniqueAssetPath($"Assets/{indexName}.index"); } else diff --git a/Modules/QuickSearch/Editor/Utilities/Utils.cs b/Modules/QuickSearch/Editor/Utilities/Utils.cs index cfb74493f1..ae7defff83 100644 --- a/Modules/QuickSearch/Editor/Utilities/Utils.cs +++ b/Modules/QuickSearch/Editor/Utilities/Utils.cs @@ -481,11 +481,6 @@ internal static object JsonDeserialize(string json) return Json.Deserialize(json); } - internal static int GetNumCharactersThatFitWithinWidth(GUIStyle style, string text, float width) - { - return style.GetNumCharactersThatFitWithinWidth(text, width); - } - internal static string GetNextWord(string src, ref int index) { // Skip potential white space BEFORE the actual word we are extracting diff --git a/Modules/SceneTemplateEditor/DependencyListView.cs b/Modules/SceneTemplateEditor/DependencyListView.cs index 91c875ebdd..b2f1640679 100644 --- a/Modules/SceneTemplateEditor/DependencyListView.cs +++ b/Modules/SceneTemplateEditor/DependencyListView.cs @@ -161,6 +161,7 @@ public DependencyListView(List itemsSource, int itemHeight, var listViewContainer = new VisualElement(); listViewContainer.AddToClassList(k_ListView); listViewContainer.style.flexGrow = 1; + listViewContainer.style.maxHeight = (Mathf.Min(m_OriginalItems.Count, 30) + 2) * m_ItemSize; listView = new ListView(m_FilteredItems, itemHeight, MakeItem, BindItem); listView.name = k_ListInternalView; @@ -169,7 +170,8 @@ public DependencyListView(List itemsSource, int itemHeight, listView.RegisterCallback(OnKeyUpEvent); listView.selectionType = SelectionType.Multiple; listView.itemsChosen += OnDoubleClick; - listView.style.maxHeight = Mathf.Max(m_OriginalItems.Count * m_ItemSize + 100, listView.style.maxHeight.value.value); + listView.style.minHeight = 0; + listView.style.maxHeight = (Mathf.Min(m_OriginalItems.Count, 30) + 1) * m_ItemSize; var searchField = new ToolbarSearchField(); searchField.name = "dependency-listview-toolbar-searchfield"; @@ -238,7 +240,6 @@ VisualElement MakeHeader() }); m_CloneHeaderToggle.AddToClassList("scene-template-asset-inspector-dependency-header-clone-column"); changeAllRowElement.Add(m_CloneHeaderToggle); - return changeAllRowElement; } @@ -274,10 +275,7 @@ void BindItem(VisualElement el, int modelIndex) instantiationModeProperty.enumValueIndex = (int)newInstantiationType; // Sync Selection if the dependency is part of it: - if (listView.selectedIndices.Contains(modelIndex)) - SyncListSelectionToValue(newInstantiationType); - m_SerializedObject.ApplyModifiedProperties(); - + SyncListSelectionToValue(newInstantiationType); UpdateGlobalCloneToggle(); }); } @@ -323,16 +321,9 @@ void OnKeyUpEvent(KeyUpEvent e) void SyncListSelectionToValue(TemplateInstantiationMode mode) { - if (listView.selectedIndex != -1) + foreach(var item in GetSelectedItems()) { - var listContent = listView.Q("unity-content-container"); - foreach (var row in listContent.Children()) - { - if (row.ClassListContains("unity-list-view__item--selected")) - { - SetDependencyInstantiationMode(row, mode); - } - } + SetDependencyInstantiationMode(item, mode); } m_SerializedObject.ApplyModifiedProperties(); } @@ -354,22 +345,24 @@ static void SetDependencyInstantiationMode(VisualElement row, TemplateInstantiat } } - IEnumerable GetSelectedDependencies() + IEnumerable GetSelectedItems() { - var selectedItems = new List(); - if (listView.selectedIndex != -1) + if (listView.selectedIndex == -1) + yield break; + + var listContent = listView.Q("unity-content-container"); + foreach (var row in listContent.Children()) { - var listContent = listView.Q("unity-content-container"); - foreach (var row in listContent.Children()) + if (row.ClassListContains("unity-collection-view__item--selected")) { - var prop = (SerializedProperty)row.userData; - if (row.ClassListContains("unity-list-view__item--selected")) - { - selectedItems.Add(prop); - } + yield return row; } } - return selectedItems; + } + + IEnumerable GetSelectedDependencies() + { + return GetSelectedItems().Select(item => (SerializedProperty)item.userData); } static void OnDoubleClick(IEnumerable objs) diff --git a/Modules/SceneTemplateEditor/ReferenceUtils.cs b/Modules/SceneTemplateEditor/ReferenceUtils.cs index 35c762cd79..8d2407fd85 100644 --- a/Modules/SceneTemplateEditor/ReferenceUtils.cs +++ b/Modules/SceneTemplateEditor/ReferenceUtils.cs @@ -10,18 +10,18 @@ namespace UnityEditor.SceneTemplate { internal static class ReferenceUtils { - public static void GetSceneDependencies(SceneAsset scene, List dependencies) + public static void GetSceneDependencies(SceneAsset scene, List dependencies, HashSet editorOnlyDependencies = null) { var path = AssetDatabase.GetAssetPath(scene); - GetSceneDependencies(path, dependencies); + GetSceneDependencies(path, dependencies, editorOnlyDependencies); } - public static void GetSceneDependencies(Scene scene, List dependencies) + public static void GetSceneDependencies(Scene scene, List dependencies, HashSet editorOnlyDependencies = null) { - GetSceneDependencies(scene.path, dependencies); + GetSceneDependencies(scene.path, dependencies, editorOnlyDependencies); } - public static void GetSceneDependencies(string scenePath, List dependencies) + public static void GetSceneDependencies(string scenePath, List dependencies, HashSet editorOnlyDependencies = null) { var dependencyPaths = AssetDatabase.GetDependencies(scenePath); @@ -35,6 +35,16 @@ public static void GetSceneDependencies(string scenePath, List dependenc var dependencyType = AssetDatabase.GetMainAssetTypeAtPath(dependencyPath); if (dependencyType == null) continue; + if (dependencyType == typeof(MonoScript)) + { + var scriptDependencies = AssetDatabase.GetDependencies(dependencyPath); + foreach(var scriptDepPath in scriptDependencies) + { + if (scriptDepPath != dependencyPath) + editorOnlyDependencies.Add(scriptDepPath); + } + } + var typeInfo = SceneTemplateProjectSettings.Get().GetDependencyInfo(dependencyType); if (typeInfo.ignore) continue; diff --git a/Modules/SceneTemplateEditor/SceneTemplateAsset.cs b/Modules/SceneTemplateEditor/SceneTemplateAsset.cs index 276196f831..dd9decdf42 100644 --- a/Modules/SceneTemplateEditor/SceneTemplateAsset.cs +++ b/Modules/SceneTemplateEditor/SceneTemplateAsset.cs @@ -21,6 +21,7 @@ public enum TemplateInstantiationMode [Serializable] [ExcludeFromPreset] [AssetFileNameExtension("scenetemplate")] + [HelpURL("https://docs.unity3d.com/2023.1/Documentation/Manual/scene-templates.html")] public class SceneTemplateAsset : ScriptableObject { internal const string extension = "scenetemplate"; @@ -82,7 +83,8 @@ internal bool UpdateDependencies() var sceneCloneableDependenciesFolder = Path.Combine(sceneFolder, sceneName).Replace("\\", "/"); var depList = new List(); - ReferenceUtils.GetSceneDependencies(scenePath, depList); + var editorOnlyDependencies = new HashSet(); + ReferenceUtils.GetSceneDependencies(scenePath, depList, editorOnlyDependencies); var newDependenciesAdded = false; @@ -104,6 +106,10 @@ internal bool UpdateDependencies() { instantiationMode = TemplateInstantiationMode.Clone; } + else if (editorOnlyDependencies.Contains(dependencyPath)) + { + instantiationMode = TemplateInstantiationMode.Reference; + } } return new DependencyInfo() diff --git a/Modules/SceneTemplateEditor/SceneTemplateAssetInspectorWindow.cs b/Modules/SceneTemplateEditor/SceneTemplateAssetInspectorWindow.cs index 53f84adf22..31730ca000 100644 --- a/Modules/SceneTemplateEditor/SceneTemplateAssetInspectorWindow.cs +++ b/Modules/SceneTemplateEditor/SceneTemplateAssetInspectorWindow.cs @@ -36,7 +36,6 @@ internal class SceneTemplateAssetInspectorWindow : Editor private static readonly string k_SnapshotTargetPopupName = "snapshot"; private static readonly string k_CreatePipelineTooltip = L10n.Tr("Create a new Scene Template Pipeline."); private static readonly string k_CreatePipelineButtonLabel = L10n.Tr("Create New Scene Template Pipeline"); - private static readonly string k_PipelineHelpUrl = "https://docs.unity3d.com/2020.2/Documentation/Manual/scene-templates.html"; private List m_DependenciesProperty = new List(); private Texture2D m_HelpIcon; @@ -91,6 +90,7 @@ public override VisualElement CreateInspectorGUI() root.style.flexDirection = FlexDirection.Column; var detailElement = new VisualElement(); + detailElement.style.marginRight = 6f; // Template scene var templateSceneProperty = serializedObject.FindProperty(SceneTemplateUtils.TemplateScenePropertyName); @@ -146,31 +146,24 @@ public override VisualElement CreateInspectorGUI() }); detailElement.Add(description); + // Pin in new scene dialog var templateAddToDefaultsProperty = serializedObject.FindProperty(SceneTemplateUtils.TemplateAddToDefaultsPropertyName); - var defaultTemplateField = new VisualElement(); - defaultTemplateField.style.flexDirection = FlexDirection.Row; - var addToDefaultsPropertyField = new PropertyField(templateAddToDefaultsProperty, " "); + var addToDefaultsPropertyField = new PropertyField(templateAddToDefaultsProperty, L10n.Tr("Pin in New Scene Dialog")); + addToDefaultsPropertyField.tooltip = L10n.Tr("Pin in New Scene Dialog. Ensuring this template is shown before unpinned template in the list."); addToDefaultsPropertyField.RegisterCallback>(e => TriggerSceneTemplateModified()); - addToDefaultsPropertyField.style.flexShrink = 0; - defaultTemplateField.Add(addToDefaultsPropertyField); - var label = new Label(L10n.Tr("Pin in New Scene Dialog")); - label.tooltip = L10n.Tr("Pin in New Scene Dialog. Ensuring this template is shown before unpinned template in the list."); - label.style.unityTextAlign = TextAnchor.MiddleLeft; - label.style.overflow = Overflow.Hidden; - label.style.textOverflow = TextOverflow.Ellipsis; - label.style.flexShrink = 1; - defaultTemplateField.Add(label); - detailElement.Add(defaultTemplateField); + detailElement.Add(addToDefaultsPropertyField); root.Add(CreateFoldoutInspector(detailElement, L10n.Tr("Details"), "SceneTemplateInspectorDetailsFoldout")); // Template thumbnail var templateThumbnailProperty = serializedObject.FindProperty(SceneTemplateUtils.TemplateThumbnailPropertyName); var templateThumbnailBadgeProperty = serializedObject.FindProperty(SceneTemplateUtils.TemplateThumbnailBadgePropertyName); var thumbnailField = MakeThumbnailField(templateThumbnailProperty, templateThumbnailBadgeProperty); + thumbnailField.style.marginRight = 6f; root.Add(CreateFoldoutInspector(thumbnailField, L10n.Tr("Thumbnail"), "SceneTemplateInspectorThumbnailFoldout")); // SceneTemplatePipeline var sceneTemplatePipeline = new VisualElement(); + sceneTemplatePipeline.style.marginRight = 6f; var pipelineProperty = serializedObject.FindProperty(SceneTemplateUtils.TemplatePipelineName); var pipelineField = new PropertyField(pipelineProperty, L10n.Tr("Scene Template Pipeline")); pipelineField.tooltip = k_SceneTemplateInfo; @@ -189,7 +182,9 @@ public override VisualElement CreateInspectorGUI() createPipelineButton.AddToClassList(Styles.classUnityBaseFieldInput); buttonRow.Add(createPipelineButton); sceneTemplatePipeline.Add(buttonRow); - root.Add(CreateFoldoutInspectorWithHelp(sceneTemplatePipeline, L10n.Tr("Scene Template Pipeline"), "SceneTemplatePipelineFoldout", k_PipelineHelpUrl)); + var version = UnityEditorInternal.InternalEditorUtility.GetUnityVersion(); + var url = $"https://docs.unity3d.com/{version.Major}.{version.Minor}/Documentation/Manual/scene-templates-customizing-scene-instantiation.html"; + root.Add(CreateFoldoutInspectorWithHelp(sceneTemplatePipeline, L10n.Tr("Scene Template Pipeline"), "SceneTemplatePipelineFoldout", url)); // Dependencies root.Add(CreateFoldoutInspector(BuildDependencyRows(), L10n.Tr("Dependencies"), "SceneTemplateDependenciesFoldout")); diff --git a/Modules/SceneTemplateEditor/SceneTemplateDialog.cs b/Modules/SceneTemplateEditor/SceneTemplateDialog.cs index f4065c6d26..61e1166866 100644 --- a/Modules/SceneTemplateEditor/SceneTemplateDialog.cs +++ b/Modules/SceneTemplateEditor/SceneTemplateDialog.cs @@ -189,14 +189,12 @@ private void BuildUI() var sceneTemplatesContainer = new VisualElement(); sceneTemplatesContainer.AddToClassList(Styles.classTemplatesContainer); sceneTemplatesContainer.AddToClassList(Styles.sceneTemplateDialogBorder); - // mainContainer.Add(sceneTemplatesContainer); CreateAllSceneTemplateListsUI(sceneTemplatesContainer); // Create a container for the template description (right side) var descriptionContainer = new VisualElement(); descriptionContainer.AddToClassList(Styles.classDescriptionContainer); descriptionContainer.AddToClassList(Styles.classBorder); - // mainContainer.Add(descriptionContainer); CreateTemplateDescriptionUI(descriptionContainer); if (EditorPrefs.HasKey(GetKeyName(nameof(m_Splitter)))) @@ -319,6 +317,9 @@ private void RefreshTemplateGridView() m_GridView.SetPinned(m_SceneTemplateInfos.Where(template => template.isPinned).Select(template => template.GetHashCode())); m_GridView.SetSelection(m_LastSelectedTemplate.GetHashCode()); + if (m_GridView.filterString != null && !m_GridView.filterString.Equals(string.Empty)) + m_GridView.filterString = m_GridView.filterString; + m_GridView.onPinnedChanged += OnPinnedChanged; m_GridView.onSelectionChanged += OnTemplateListViewSelectionChanged; } @@ -400,12 +401,18 @@ private void CreateTemplateDescriptionUI(VisualElement rootContainer) rootContainer.RegisterCallback(evt => m_PreviewArea?.UpdatePreviewAreaSize()); // Text container + var scrollViewContainer = new ScrollView { style = { flexGrow = 1 } }; + rootContainer.Add(scrollViewContainer); + + // Title var sceneTitleLabel = new Label(); + scrollViewContainer.Add(sceneTitleLabel); sceneTitleLabel.name = k_SceneTemplateTitleLabelName; sceneTitleLabel.AddToClassList(Styles.classWrappingText); - rootContainer.Add(sceneTitleLabel); + // Asset path var assetPathSection = new VisualElement(); + scrollViewContainer.Add(assetPathSection); assetPathSection.name = k_SceneTemplatePathSection; { var scenePathLabel = new Label(); @@ -450,9 +457,10 @@ private void CreateTemplateDescriptionUI(VisualElement rootContainer) } assetPathSection.Add(editLocateRow); } - rootContainer.Add(assetPathSection); + // Description var descriptionSection = new VisualElement(); + scrollViewContainer.Add(descriptionSection); descriptionSection.name = k_SceneTemplateDescriptionSection; { var descriptionLabel = new Label(); @@ -465,7 +473,8 @@ private void CreateTemplateDescriptionUI(VisualElement rootContainer) sceneDescriptionLabel.name = k_SceneTemplateDescriptionName; descriptionSection.Add(sceneDescriptionLabel); } - rootContainer.Add(descriptionSection); + + rootContainer.Add(scrollViewContainer); } private void UpdateTemplateDescriptionUI(SceneTemplateInfo newSceneTemplateInfo) diff --git a/Modules/SceneTemplateEditor/SceneTemplateUtils.cs b/Modules/SceneTemplateEditor/SceneTemplateUtils.cs index fc38a1f074..fffb9a5fa6 100644 --- a/Modules/SceneTemplateEditor/SceneTemplateUtils.cs +++ b/Modules/SceneTemplateEditor/SceneTemplateUtils.cs @@ -204,7 +204,7 @@ internal static List GetSceneTemplateInfos() var assetName = Path.GetFileNameWithoutExtension(templateData.Item1); var isReadOnly = false; - if (templateData.Item1.StartsWith("Packages/") && AssetDatabase.GetAssetFolderInfo(templateData.Item1, out var isRootFolder, out var isImmutable)) + if (templateData.Item1.StartsWith("Packages/") && AssetDatabase.TryGetAssetFolderInfo(templateData.Item1, out var isRootFolder, out var isImmutable)) { isReadOnly = isImmutable; } diff --git a/Modules/ShortcutManager/ShortcutManagerWindowView.cs b/Modules/ShortcutManager/ShortcutManagerWindowView.cs index b80f344024..488de44eeb 100644 --- a/Modules/ShortcutManager/ShortcutManagerWindowView.cs +++ b/Modules/ShortcutManager/ShortcutManagerWindowView.cs @@ -749,7 +749,8 @@ void ShortcutSelectionChanged(IEnumerable selection) void ShortcutTableRightClickDown(MouseDownEvent evt) { - evt.StopPropagation(); + if(!m_ShortcutsTable.scrollView.verticalScroller.worldBound.Contains(evt.mousePosition)) + evt.StopPropagation(); var slider = m_ShortcutsTable.Q(className: Scroller.verticalVariantUssClassName); var clickedIndex = (int)((evt.localMousePosition.y + slider.value) / m_ShortcutsTable.ResolveItemHeight()); @@ -1441,6 +1442,8 @@ private void RegisterEvents(VisualElement input) input.RegisterCallback((evt) => { StartNewCombination(); evt.StopPropagation(); + evt.propagation |= EventBase.EventPropagation.Cancellable; + evt.PreventDefault(); textSelection.MoveTextEnd(); }, TrickleDown.TrickleDown); input.RegisterCallback((evt) => diff --git a/Modules/ShortcutManagerEditor/ShortcutProfileManager.cs b/Modules/ShortcutManagerEditor/ShortcutProfileManager.cs index cbd7b04ff0..f6100e5a02 100644 --- a/Modules/ShortcutManagerEditor/ShortcutProfileManager.cs +++ b/Modules/ShortcutManagerEditor/ShortcutProfileManager.cs @@ -296,7 +296,10 @@ public void ModifyShortcutEntry(Identifier identifier, IEnumerable e.identifier.Equals(identifier)); var oldBinding = new ShortcutBinding(shortcutEntry.combinations); diff --git a/Modules/TerrainEditor/Overlays/BrushAttributes.cs b/Modules/TerrainEditor/Overlays/BrushAttributes.cs index c613cf9f7c..e9f9e0a054 100644 --- a/Modules/TerrainEditor/Overlays/BrushAttributes.cs +++ b/Modules/TerrainEditor/Overlays/BrushAttributes.cs @@ -12,7 +12,7 @@ namespace UnityEditor.TerrainTools { - [Overlay(typeof(SceneView), "Brush Attributes")] + [Overlay(typeof(SceneView), "Brush Attributes", defaultDockPosition = DockPosition.Top, defaultDockZone = DockZone.TopToolbar)] [Icon("TerrainOverlays/BrushSettingIcons/BrushAttributes.png")] internal class BrushAttributes : ToolbarOverlay, ITransientOverlay, ICreateHorizontalToolbar, ICreateVerticalToolbar { @@ -20,16 +20,14 @@ public bool visible { get { - if (packageIsInstalled) return false; // no core brushAttributes when package is installed var currTool = TerrainInspector.GetActiveTerrainTool() as ITerrainPaintToolWithOverlays; - if (currTool == null) - return false; - return currTool.HasBrushAttributes && BrushesOverlay.IsSelectedObjectTerrain(); + if (currTool == null) return false; + bool directlyInheritsOverlays = currTool.GetType().BaseType.GetGenericTypeDefinition() == typeof(TerrainPaintToolWithOverlays<>).GetGenericTypeDefinition(); + return currTool.HasBrushAttributes && BrushesOverlay.IsSelectedObjectTerrain() && directlyInheritsOverlays; } } internal static BrushAttributes s_Instance; - private bool packageIsInstalled; BrushAttributes() : base( @@ -37,7 +35,6 @@ public bool visible BrushSize.k_Id) { s_Instance = this; - packageIsInstalled = TerrainToolsPackageInstalled(); // only rebuild if the next tool is/isn't PaintDetailsTool ToolManager.activeToolChanged += RebuildAttributesOverlays; @@ -51,14 +48,6 @@ public override void OnWillBeDestroyed() ToolManager.activeContextChanged -= RebuildAttributesOverlays; } - private bool TerrainToolsPackageInstalled() - { - // check if package is installed - var upm = UnityEditor.PackageManager.PackageInfo.GetAllRegisteredPackages(); - var terrainPackageInfo = upm.Where(pi => pi.name == "com.unity.terrain-tools"); - return terrainPackageInfo.Any(); // if q returns any then yes a package is installed - } - // this function serves to prevent calling RebuildContent() more than necessary private ITerrainPaintToolWithOverlays lastPaintTool = null; private void RebuildAttributesOverlays() @@ -79,7 +68,6 @@ private void RebuildAttributesOverlays() // set last == curr lastPaintTool = currTool; - } // call this function for horizontal and vertical toolbar create @@ -195,11 +183,14 @@ public BrushOpacity() }; UpdateOverlayDirection(true); - ToolManager.activeToolChanged += UpdateValues; - ToolManager.activeContextChanged += UpdateValues; - TerrainInspector.BrushStrengthChanged += UpdateValues; - BrushAttributes.s_Instance.layoutChanged += UpdateOverlayDirection; // when the overlay is dragged, see if the direction needs to be updated - BrushAttributes.s_Instance.collapsedChanged += UpdateOverlayDirection; + RegisterCallback(e => + { + ToolManager.activeToolChanged += UpdateValues; + ToolManager.activeContextChanged += UpdateValues; + TerrainInspector.BrushStrengthChanged += UpdateValues; + BrushAttributes.s_Instance.layoutChanged += UpdateOverlayDirection; // when the overlay is dragged, see if the direction needs to be updated + BrushAttributes.s_Instance.collapsedChanged += UpdateOverlayDirection; + }); RegisterCallback(e => { @@ -299,11 +290,14 @@ public BrushSize() { UpdateOverlayDirection(true); - ToolManager.activeToolChanged += UpdateValues; - ToolManager.activeContextChanged += UpdateValues; - TerrainInspector.BrushSizeChanged += UpdateValues; - BrushAttributes.s_Instance.layoutChanged += UpdateOverlayDirection; // when the overlay is dragged, see if the direction needs to be updated - BrushAttributes.s_Instance.collapsedChanged += UpdateOverlayDirection; + RegisterCallback(e => + { + ToolManager.activeToolChanged += UpdateValues; + ToolManager.activeContextChanged += UpdateValues; + TerrainInspector.BrushSizeChanged += UpdateValues; + BrushAttributes.s_Instance.layoutChanged += UpdateOverlayDirection; // when the overlay is dragged, see if the direction needs to be updated + BrushAttributes.s_Instance.collapsedChanged += UpdateOverlayDirection; + }); RegisterCallback(e => { @@ -389,11 +383,14 @@ public BrushTargetStrength() }; UpdateOverlayDirection(true); - ToolManager.activeToolChanged += UpdateValues; - ToolManager.activeContextChanged += UpdateValues; - PaintDetailsTool.BrushTargetStrengthChanged += UpdateValues; - BrushAttributes.s_Instance.layoutChanged += UpdateOverlayDirection; // when the overlay is dragged, see if the direction needs to be updated - BrushAttributes.s_Instance.collapsedChanged += UpdateOverlayDirection; + RegisterCallback(e => + { + ToolManager.activeToolChanged += UpdateValues; + ToolManager.activeContextChanged += UpdateValues; + PaintDetailsTool.BrushTargetStrengthChanged += UpdateValues; + BrushAttributes.s_Instance.layoutChanged += UpdateOverlayDirection; // when the overlay is dragged, see if the direction needs to be updated + BrushAttributes.s_Instance.collapsedChanged += UpdateOverlayDirection; + }); RegisterCallback(e => { diff --git a/Modules/TerrainEditor/Overlays/BrushesOverlay.cs b/Modules/TerrainEditor/Overlays/BrushesOverlay.cs index 3c0be48239..e7308b0603 100644 --- a/Modules/TerrainEditor/Overlays/BrushesOverlay.cs +++ b/Modules/TerrainEditor/Overlays/BrushesOverlay.cs @@ -75,7 +75,7 @@ internal static void OnGUI(BrushGUIEditFlags flags = BrushGUIEditFlags.All) // brush masks ---------------- - [Overlay(typeof(SceneView), "Brush Masks")] + [Overlay(typeof(SceneView), "Brush Masks", defaultDockPosition = DockPosition.Top, defaultDockZone = DockZone.LeftToolbar, defaultDockIndex = 10)] [Icon("TerrainOverlays/BrushSettingIcons/BrushMask.png")] internal class BrushMaskOverlay : ToolbarOverlay, ITransientOverlay { diff --git a/Modules/TerrainEditor/Overlays/CondensedSlider.cs b/Modules/TerrainEditor/Overlays/CondensedSlider.cs index 8d6b3b4e18..04ae11ad95 100644 --- a/Modules/TerrainEditor/Overlays/CondensedSlider.cs +++ b/Modules/TerrainEditor/Overlays/CondensedSlider.cs @@ -136,21 +136,15 @@ private void CreateSlider(float min, float max, SliderDirection direction) var slider = m_Slider.Q("unity-tracker"); slider.ClearClassList(); slider.AddToClassList("condensed-slider__slider-tracker"); - m_Slider.RegisterCallback(e => - { - if (direction == SliderDirection.Horizontal) - slider.style.height = e.newRect.height; - else - slider.style.width = e.newRect.width; - }); + m_Slider.Q("unity-dragger").style.display = DisplayStyle.None; m_Slider.Q("unity-dragger-border").style.display = DisplayStyle.None; var content = new VisualElement(); + content.name = "content"; content.AddToClassList("condensed-slider__content--"+directionClassSuffix); content.pickingMode = PickingMode.Ignore; m_Slider.Add(content); - m_Slider.RegisterCallback(e => content.style.width = e.newRect.width); var imageField = new VisualElement(); imageField.AddToClassList("condensed-slider__image"); imageField.AddToClassList("condensed-slider__image--"+directionClassSuffix); @@ -166,12 +160,13 @@ private void CreateSlider(float min, float max, SliderDirection direction) m_LabelField.pickingMode = PickingMode.Ignore; content.Add(m_LabelField); - var contentTextField = new VisualElement(); + contentTextField.name = "contentTextField"; contentTextField.AddToClassList("condensed-slider__content-textfield--"+directionClassSuffix); contentTextField.pickingMode = PickingMode.Ignore; m_Slider.Add(contentTextField); var textField = new FloatField(); + textField.name = "textField"; textField.AddToClassList("condensed-slider__label"); textField.AddToClassList("condensed-slider__textfield--"+directionClassSuffix); textField.style.display = DisplayStyle.None; @@ -183,59 +178,130 @@ private void CreateSlider(float min, float max, SliderDirection direction) textField.style.marginTop = 34; } - textField.RegisterValueChangedCallback(e => UpdateValue(e.newValue, false)); contentTextField.Add(textField); - m_Slider.RegisterValueChangedCallback(e => - { - SetValueWithoutNotify(e.newValue); - }); - // open the textfield when right clicking on the slider - m_Slider.RegisterCallback(e => + RegisterCallback(RegisterCallbacks); + RegisterCallback(UnregisterCallbacks); + } + + private void RegisterCallbacks(AttachToPanelEvent e) + { + var textField = m_Slider.Q("textField") as FloatField; + var contentTextField = m_Slider.Q("contentTextField"); ; + m_Slider.RegisterCallback(OnSliderRectChange); + m_Slider.RegisterCallback(OnSliderWidthChange); + textField.RegisterValueChangedCallback(TextFieldValueChange); + m_Slider.RegisterValueChangedCallback(SliderSetValue); + m_Slider.RegisterCallback(SliderMouseDownEvent); + m_Slider.RegisterCallback(SliderMouseUpEvent); + contentTextField.RegisterCallback(TextFieldMouseDownEvent); + textField.RegisterCallback(TextFieldKeyDownEvent); + } + + private void UnregisterCallbacks(DetachFromPanelEvent e) + { + var textField = m_Slider.Q("textField") as FloatField; + var contentTextField = m_Slider.Q("contentTextField"); + m_Slider.UnregisterCallback(OnSliderRectChange); + m_Slider.UnregisterCallback(OnSliderWidthChange); + textField.UnregisterValueChangedCallback(TextFieldValueChange); + m_Slider.UnregisterValueChangedCallback(SliderSetValue); + m_Slider.UnregisterCallback(SliderMouseDownEvent); + m_Slider.UnregisterCallback(SliderMouseUpEvent); + contentTextField.UnregisterCallback(TextFieldMouseDownEvent); + textField.UnregisterCallback(TextFieldKeyDownEvent); + } + + private void OnSliderRectChange(GeometryChangedEvent e) + { + var slider = m_Slider.Q("unity-tracker"); + if (direction == SliderDirection.Horizontal) + slider.style.height = e.newRect.height; + else + slider.style.width = e.newRect.width; + } + + private void OnSliderWidthChange(GeometryChangedEvent e) + { + var content = m_Slider.Q("content"); + content.style.width = e.newRect.width; + } + + private void TextFieldValueChange(ChangeEvent e) + { + UpdateValue(e.newValue, false); + } + + private void SliderSetValue(ChangeEvent e) + { + SetValueWithoutNotify(e.newValue); + } + + private void SliderMouseDownEvent(MouseDownEvent e) + { + if (e.button == (int)MouseButton.RightMouse) { - if (e.button == (int)MouseButton.RightMouse) - { - e.StopPropagation(); - e.PreventDefault(); + e.StopPropagation(); + e.PreventDefault(); + + var textField = m_Slider.Q("textField") as FloatField; + var contentTextField = m_Slider.Q("contentTextField"); + if (textField != null) + { textField.value = m_Slider.value; textField.style.display = DisplayStyle.Flex; - m_LabelField.style.display = DisplayStyle.None; - contentTextField.pickingMode = PickingMode.Position; } - }); - // Stop propagating the mouse up to avoid context menus - m_Slider.RegisterCallback(e => + + m_LabelField.style.display = DisplayStyle.None; + contentTextField.pickingMode = PickingMode.Position; + } + } + + private void SliderMouseUpEvent(MouseUpEvent e) + { + if (e.button == (int)MouseButton.RightMouse) { - if (e.button == (int)MouseButton.RightMouse) - { - e.StopPropagation(); - e.PreventDefault(); - } - }); - // Any click inside the hidden element closes the textfield - contentTextField.RegisterCallback(e => + e.StopPropagation(); + e.PreventDefault(); + } + } + + private void TextFieldMouseDownEvent(MouseDownEvent e) + { + var textField = m_Slider.Q("textField") as FloatField; + var contentTextField = m_Slider.Q("contentTextField"); + + contentTextField.pickingMode = PickingMode.Ignore; + if (textField != null) { - contentTextField.pickingMode = PickingMode.Ignore; if (textField.style.display == DisplayStyle.Flex) { textField.style.display = DisplayStyle.None; m_LabelField.style.display = DisplayStyle.Flex; } - }); - // closes the textfield on escape or return - textField.RegisterCallback(e => + } + + } + + private void TextFieldKeyDownEvent(KeyDownEvent e) + { + var textField = m_Slider.Q("textField") as FloatField; + var contentTextField = m_Slider.Q("contentTextField"); + + if (e.keyCode == KeyCode.Escape || e.keyCode == KeyCode.Return) { - if (e.keyCode == KeyCode.Escape || e.keyCode == KeyCode.Return) + contentTextField.pickingMode = PickingMode.Ignore; + + if (textField != null) { - contentTextField.pickingMode = PickingMode.Ignore; if (textField.style.display == DisplayStyle.Flex) { textField.style.display = DisplayStyle.None; m_LabelField.style.display = DisplayStyle.Flex; } } - }); + } } public void UpdateDirection(SliderDirection newDirection, float min, float max) @@ -244,9 +310,7 @@ public void UpdateDirection(SliderDirection newDirection, float min, float max) direction = newDirection; Clear(); ClearClassList(); - CreateSlider(min, max, newDirection); - } } diff --git a/Modules/TerrainEditor/Overlays/TerrainTransientToolbarOverlay.cs b/Modules/TerrainEditor/Overlays/TerrainTransientToolbarOverlay.cs index 58cb3b6af8..bddd32cfdb 100644 --- a/Modules/TerrainEditor/Overlays/TerrainTransientToolbarOverlay.cs +++ b/Modules/TerrainEditor/Overlays/TerrainTransientToolbarOverlay.cs @@ -36,7 +36,7 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse } } - [Overlay(typeof(SceneView), "Terrain Tools")] + [Overlay(typeof(SceneView), "Terrain Tools", defaultDockPosition = DockPosition.Top, defaultDockZone = DockZone.LeftToolbar, defaultDockIndex = -1)] internal class TerrainTransientToolbarOverlay : ToolbarOverlay, ITransientOverlay, ICreateHorizontalToolbar, ICreateVerticalToolbar { bool m_OverlaysPackageInstalled; diff --git a/Modules/TextCoreTextEngine/Managed/TextGenerator.cs b/Modules/TextCoreTextEngine/Managed/TextGenerator.cs index 95290aa01d..1cced7f7c3 100644 --- a/Modules/TextCoreTextEngine/Managed/TextGenerator.cs +++ b/Modules/TextCoreTextEngine/Managed/TextGenerator.cs @@ -75,6 +75,7 @@ internal class TextGenerationSettings : IEquatable public float uvLineOffset; public VertexSortingOrder geometrySortingOrder = VertexSortingOrder.Normal; public bool inverseYAxis; + public bool isIMGUI; public float charWidthMaxAdj; internal TextInputSource inputSource = TextInputSource.TextString; @@ -94,20 +95,6 @@ public int cachedHashCode } } - private bool m_CachedGeometryHashCodeIsIntialized = false; - private int m_CachedGeometryHashCode; - public int cachedGeomertyHashCode - { - get - { - if (!m_CachedGeometryHashCodeIsIntialized) - { - m_CachedGeometryHashCode = GetGeomertyHashCode(); - m_CachedGeometryHashCodeIsIntialized = true; - } - return m_CachedGeometryHashCode; - } - } public bool Equals(TextGenerationSettings other) { @@ -138,7 +125,7 @@ public bool Equals(TextGenerationSettings other) verticalMapping == other.verticalMapping && uvLineOffset.Equals(other.uvLineOffset) && geometrySortingOrder == other.geometrySortingOrder && inverseYAxis == other.inverseYAxis && charWidthMaxAdj.Equals(other.charWidthMaxAdj) && inputSource == other.inputSource && - isOrthographic.Equals(other.isOrthographic) && isPlaceholder.Equals(other.isPlaceholder); + isOrthographic.Equals(other.isOrthographic) && isPlaceholder.Equals(other.isPlaceholder) && isIMGUI.Equals(other.isIMGUI); } public override bool Equals(object obj) @@ -204,57 +191,10 @@ public override int GetHashCode() hashCode.Add(charWidthMaxAdj); hashCode.Add((int)inputSource); hashCode.Add(isPlaceholder); + hashCode.Add(isIMGUI); return hashCode.ToHashCode(); } - public int GetGeomertyHashCode() - { - unchecked - { - var hashCode = (text != null ? text.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ screenRect.GetHashCode(); - hashCode = (hashCode * 397) ^ margins.GetHashCode(); - hashCode = (hashCode * 397) ^ scale.GetHashCode(); - hashCode = (hashCode * 397) ^ (fontAsset != null ? fontAsset.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (spriteAsset != null ? spriteAsset.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (int)fontStyle; - hashCode = (hashCode * 397) ^ (int)textAlignment; - hashCode = (hashCode * 397) ^ (int)overflowMode; - hashCode = (hashCode * 397) ^ wordWrap.GetHashCode(); - hashCode = (hashCode * 397) ^ wordWrappingRatio.GetHashCode(); - hashCode = (hashCode * 397) ^ fontSize.GetHashCode(); - hashCode = (hashCode * 397) ^ autoSize.GetHashCode(); - hashCode = (hashCode * 397) ^ fontSizeMin.GetHashCode(); - hashCode = (hashCode * 397) ^ fontSizeMax.GetHashCode(); - hashCode = (hashCode * 397) ^ enableKerning.GetHashCode(); - hashCode = (hashCode * 397) ^ richText.GetHashCode(); - hashCode = (hashCode * 397) ^ isRightToLeft.GetHashCode(); - hashCode = (hashCode * 397) ^ extraPadding.GetHashCode(); - hashCode = (hashCode * 397) ^ parseControlCharacters.GetHashCode(); - hashCode = (hashCode * 397) ^ characterSpacing.GetHashCode(); - hashCode = (hashCode * 397) ^ wordSpacing.GetHashCode(); - hashCode = (hashCode * 397) ^ lineSpacing.GetHashCode(); - hashCode = (hashCode * 397) ^ paragraphSpacing.GetHashCode(); - hashCode = (hashCode * 397) ^ lineSpacingMax.GetHashCode(); - hashCode = (hashCode * 397) ^ maxVisibleCharacters; - hashCode = (hashCode * 397) ^ maxVisibleWords; - hashCode = (hashCode * 397) ^ maxVisibleLines; - hashCode = (hashCode * 397) ^ firstVisibleCharacter; - hashCode = (hashCode * 397) ^ useMaxVisibleDescender.GetHashCode(); - hashCode = (hashCode * 397) ^ (int)fontWeight; - hashCode = (hashCode * 397) ^ pageToDisplay; - hashCode = (hashCode * 397) ^ (int)horizontalMapping; - hashCode = (hashCode * 397) ^ (int)verticalMapping; - hashCode = (hashCode * 397) ^ uvLineOffset.GetHashCode(); - hashCode = (hashCode * 397) ^ (int)geometrySortingOrder; - hashCode = (hashCode * 397) ^ inverseYAxis.GetHashCode(); - hashCode = (hashCode * 397) ^ charWidthMaxAdj.GetHashCode(); - hashCode = (hashCode * 397) ^ (int)textWrappingMode; - hashCode = (hashCode * 397) ^ isOrthographic.GetHashCode(); - return hashCode; - } - } - public static bool operator ==(TextGenerationSettings left, TextGenerationSettings right) { return Equals(left, right); @@ -3590,7 +3530,7 @@ protected bool ValidateHtmlTag(TextProcessingElement[] chars, int startIndex, ou else if (tagValueType == TagValueType.StringValue) { // Compute HashCode value for the named tag. - if (unicode != '"') + if (generationSettings.isIMGUI || unicode != '"') { m_XmlAttribute[attributeIndex].valueHashCode = (m_XmlAttribute[attributeIndex].valueHashCode << 5) + m_XmlAttribute[attributeIndex].valueHashCode ^ TextGeneratorUtilities.ToUpperFast((char)unicode); m_XmlAttribute[attributeIndex].valueLength += 1; @@ -3640,7 +3580,6 @@ protected bool ValidateHtmlTag(TextProcessingElement[] chars, int startIndex, ou if (attributeFlag == 2 && unicode == ' ') attributeFlag = 0; - } if (!isValidHtmlTag) @@ -4215,7 +4154,21 @@ protected bool ValidateHtmlTag(TextProcessingElement[] chars, int startIndex, ou case MarkupTag.A: if (m_isTextLayoutPhase && !m_IsCalculatingPreferredValues) { - if (m_XmlAttribute[1].nameHashCode == (int)MarkupTag.HREF) + // For IMGUI, we want to treat the a tag as we do with the link tag + if (generationSettings.isIMGUI) + { + int index = textInfo.linkCount; + + if (index + 1 > textInfo.linkInfo.Length) + TextInfo.Resize(ref textInfo.linkInfo, index + 1); + + textInfo.linkInfo[index].hashCode = (int)MarkupTag.HREF; + textInfo.linkInfo[index].linkTextfirstCharacterIndex = m_CharacterCount; + + textInfo.linkInfo[index].linkIdFirstCharacterIndex = 3; + textInfo.linkInfo[index].SetLinkId(m_HtmlTag, 2, m_XmlAttribute[1].valueLength + m_XmlAttribute[1].valueStartIndex - 2); + } + else if (m_XmlAttribute[1].nameHashCode == (int)MarkupTag.HREF) { // Make sure linkInfo array is of appropriate size. int index = textInfo.linkCount; @@ -4394,7 +4347,7 @@ protected bool ValidateHtmlTag(TextProcessingElement[] chars, int startIndex, ou m_HtmlColor = Color.red; m_ColorStack.Add(m_HtmlColor); return true; - case -992792864: // + case (int)MarkupTag.LIGHTBLUE: // m_HtmlColor = new Color32(173, 216, 230, 255); m_ColorStack.Add(m_HtmlColor); return true; @@ -4402,7 +4355,7 @@ protected bool ValidateHtmlTag(TextProcessingElement[] chars, int startIndex, ou m_HtmlColor = Color.blue; m_ColorStack.Add(m_HtmlColor); return true; - case 3680713: // + case (int)MarkupTag.GREY: // m_HtmlColor = new Color32(128, 128, 128, 255); m_ColorStack.Add(m_HtmlColor); return true; diff --git a/Modules/TextCoreTextEngine/Managed/TextHandle.cs b/Modules/TextCoreTextEngine/Managed/TextHandle.cs index d5dbc4e649..b97fbc05ec 100644 --- a/Modules/TextCoreTextEngine/Managed/TextHandle.cs +++ b/Modules/TextCoreTextEngine/Managed/TextHandle.cs @@ -88,8 +88,6 @@ public bool IsDirty() return true; } - internal float lastTimeUsed; - public Vector2 GetCursorPositionFromStringIndexUsingCharacterHeight(int index, bool inverseYAxis = true) { if (textGenerationSettings == null) diff --git a/Modules/TextCoreTextEngine/Managed/TextMarkupTagsCommon.cs b/Modules/TextCoreTextEngine/Managed/TextMarkupTagsCommon.cs index abc6613b2e..83b82ba02a 100644 --- a/Modules/TextCoreTextEngine/Managed/TextMarkupTagsCommon.cs +++ b/Modules/TextCoreTextEngine/Managed/TextMarkupTagsCommon.cs @@ -125,6 +125,8 @@ internal enum MarkupTag : int BLACK = 81074727, WHITE = 105680263, PURPLE = -1250222130, + GREY = 2638345, + LIGHTBLUE= 341063360, // Unicode Characters BR = 2256, //
Line Feed (LF) \u0A diff --git a/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorer.cs b/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorer.cs index 8852dfa3ef..a66c682aee 100644 --- a/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorer.cs +++ b/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorer.cs @@ -22,6 +22,7 @@ internal enum BuilderElementInfoVisibilityState TypeName = 1 << 0, ClassList = 1 << 1, StyleSheets = 1 << 2, + FullSelectorText = 1 << 3, All = ~0 } @@ -34,6 +35,7 @@ internal enum BuilderElementInfoVisibilityState protected ElementHierarchyView m_ElementHierarchyView; protected BuilderSelection m_Selection; bool m_SelectionMadeExternally; + [SerializeField] protected BuilderElementInfoVisibilityState m_ElementInfoVisibilityState; BuilderClassDragger m_ClassDragger; BuilderExplorerDragger m_ExplorerDragger; @@ -101,6 +103,21 @@ public BuilderExplorer( m_ShouldRebuildHierarchyOnStyleChange = true; } + internal void ChangeVisibilityState(BuilderElementInfoVisibilityState state) + { + m_ElementInfoVisibilityState ^= state; + m_ElementHierarchyView.elementInfoVisibilityState = m_ElementInfoVisibilityState; + SaveViewData(); + UpdateHierarchyAndSelection(m_ElementHierarchyView.hasUnsavedChanges); + } + + internal override void OnViewDataReady() + { + base.OnViewDataReady(); + OverwriteFromViewData(this, viewDataKey); + m_ElementHierarchyView.elementInfoVisibilityState = m_ElementInfoVisibilityState; + } + public void ClearHighlightOverlay() { m_ElementHierarchyView.ClearHighlightOverlay(); @@ -167,9 +184,9 @@ public void UpdateHierarchyAndSelection(bool hasUnsavedChanges) public virtual void HierarchyChanged(VisualElement element, BuilderHierarchyChangeType changeType) { if (element == null || - (changeType & (BuilderHierarchyChangeType.ChildrenAdded | + (changeType & (BuilderHierarchyChangeType.ChildrenAdded | BuilderHierarchyChangeType.ChildrenRemoved | - BuilderHierarchyChangeType.Attributes | + BuilderHierarchyChangeType.Attributes | BuilderHierarchyChangeType.ClassList)) != 0) { UpdateHierarchyAndSelection(m_Selection.hasUnsavedChanges); diff --git a/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorerItem.cs b/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorerItem.cs index 232b673d8b..b06c14168e 100644 --- a/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorerItem.cs +++ b/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorerItem.cs @@ -2,6 +2,7 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using System.Collections.Generic; using UnityEngine.UIElements; using UnityEngine; @@ -13,6 +14,7 @@ internal class BuilderExplorerItem : VisualElement VisualElement m_ReorderZoneAbove; VisualElement m_ReorderZoneBelow; TextField m_RenameTextField; + internal List