From 1577d01d95dbe7acf9896524641fab5de7fd4bcf Mon Sep 17 00:00:00 2001 From: Unity Technologies Date: Wed, 13 Mar 2024 21:20:06 +0000 Subject: [PATCH 01/89] Unity 6000.0.0b11 C# reference source code --- .../PlayerBuildProgramLibrary.Data/Data.cs | 1 + .../SpeedTree/SpeedTree9Importer.cs | 84 +++++++++++++---- .../SpeedTree/SpeedTreeImporterSettings.cs | 1 + Editor/Mono/Audio/AudioContainerWindow.cs | 20 ++-- .../Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs | 2 + Editor/Mono/BuildProfile/BuildProfile.cs | 40 +++++--- Editor/Mono/BuildProfile/BuildProfileAPI.cs | 32 +++++++ .../Mono/BuildProfile/BuildProfileContext.cs | 67 +++++++++++-- .../Mono/BuildProfile/BuildProfileCreate.cs | 2 +- .../BuildProfile/SharedPlatformSettings.cs | 2 +- Editor/Mono/Collab/CollabChangeItem.cs | 8 -- Editor/Mono/Collab/CollabTesting.cs | 1 - Editor/Mono/ConsoleWindow.cs | 2 +- Editor/Mono/EditorApplication.cs | 55 ++++++----- Editor/Mono/EditorBuildSettings.bindings.cs | 2 +- Editor/Mono/EditorGUIUtility.cs | 49 +--------- Editor/Mono/EditorMode/ModeService.cs | 11 ++- Editor/Mono/EditorSettings.bindings.cs | 3 + Editor/Mono/EditorTextSettings.cs | 11 +++ .../Mono/EditorUserBuildSettings.bindings.cs | 3 +- Editor/Mono/EditorWindow.cs | 1 + Editor/Mono/GUI/AboutWindow.cs | 19 +++- Editor/Mono/GUI/DockArea.cs | 2 +- Editor/Mono/GUI/Toolbars/Toolbar.cs | 1 + Editor/Mono/GUIView.cs | 10 +- Editor/Mono/HostView.cs | 1 + .../AdvancedDropdown/AdvancedDropdownGUI.cs | 32 +++++-- .../AdvancedDropdownWindow.cs | 1 + Editor/Mono/Inspector/Core/InspectorWindow.cs | 64 ++++++------- Editor/Mono/Inspector/Core/PreviewWindow.cs | 2 + Editor/Mono/Inspector/Core/PropertyEditor.cs | 18 +++- .../Mono/Inspector/EditorSettingsInspector.cs | 18 ++++ .../PlayerSettingsEditor.cs | 12 ++- Editor/Mono/InternalEditorUtility.bindings.cs | 4 + Editor/Mono/Modules/BeeBuildPostprocessor.cs | 6 +- .../Modules/DefaultBuildProfileExtension.cs | 6 +- Editor/Mono/Modules/PlatformSupportModule.cs | 5 + Editor/Mono/PlayerSettings.bindings.cs | 48 +--------- .../AssetPipelinePreferences.cs | 2 - Editor/Mono/ProjectBrowser/SearchFilter.cs | 4 +- Editor/Mono/SceneView/SceneViewMotion.cs | 15 +-- Editor/Mono/ScriptingDefinesHelper.cs | 52 +++++++++++ Editor/Mono/SerializedObject.bindings.cs | 8 +- Editor/Mono/Tools/EditorToolCache.cs | 7 +- Editor/Mono/UIElements/Controls/CurveField.cs | 2 +- .../UIElements/Inspector/EditorElement.cs | 2 + .../UIElements/Inspector/InspectorElement.cs | 4 +- Editor/Mono/WindowBackendManager.cs | 1 + .../ImportSettings/ModelImporterRigEditor.cs | 93 ++++++++++++++++--- .../ModelImporting/ModelImporter.bindings.cs | 7 ++ .../BuildProfileEditor/BuildProfileWindow.cs | 9 +- .../Managed/HierarchyNodeTypeHandlerBase.cs | 32 ++++--- .../HierarchyViewModel.bindings.cs | 2 +- Modules/IMGUI/GUIUtility.bindings.cs | 3 + .../External/EditorGameServiceExtension.cs | 15 +-- .../Editor/UI/PackageSelectionEditor.cs | 2 +- .../BottlenecksDetailsViewModelBuilder.cs | 4 +- .../ProfilerWindow/ProfilerWindow.cs | 2 +- .../PropertyBags/Internal/PropertyBagStore.cs | 22 ----- .../Runtime/PropertyBags/PropertyBag.cs | 12 --- .../Module/PropertiesEditorInitialization.cs | 2 +- .../ShortcutManagerEditor/IShortcutContext.cs | 3 - Modules/Terrain/Public/TerrainData.GPUCopy.cs | 5 +- .../TextCoreTextEngine/Managed/TextHandle.cs | 10 +- .../Managed/FontAssetCreatorWindow.cs | 7 +- .../Editor/Builder/BuilderSelection.cs | 3 +- .../Utilities/BuilderAssetUtilities.cs | 34 ++++++- .../Builder/Viewport/BuilderViewport.cs | 3 + .../Controllers/BaseTreeViewController.cs | 19 ++++ .../DynamicHeightVirtualizationController.cs | 40 ++++++-- .../UIElements/Core/Controls/BaseListView.cs | 23 +++++ .../UIElements/Core/Controls/BaseTreeView.cs | 79 ++++++++++++---- .../Controls/BaseVerticalCollectionView.cs | 2 + Modules/UIElements/Core/Controls/Foldout.cs | 42 ++++++++- .../UIElements/Core/Controls/ScrollView.cs | 68 +++++++++++--- .../Core/GameObjects/RuntimePanel.cs | 2 +- Modules/UIElements/Core/IMGUIContainer.cs | 7 ++ .../UIElements/Core/Layout/LayoutConfig.cs | 12 +-- .../UIElements/Core/Layout/LayoutManager.cs | 19 ++-- .../Core/Layout/LayoutNode+Style.cs | 5 - Modules/UIElements/Core/Layout/LayoutNode.cs | 27 ++---- .../Model/Components/LayoutConfigData.cs | 4 +- .../Model/Components/LayoutDataStore.cs | 11 +-- .../Layout/Model/Components/LayoutNodeData.cs | 41 +++++++- .../Model/Components/LayoutStyleData.cs | 2 - .../Core/Layout/Model/LayoutList.cs | 8 +- Modules/UIElements/Core/Panel.cs | 38 ++++---- .../UIElements/Core/Text/PanelTextSettings.cs | 14 ++- .../UIElements/Core/Text/UITKTextJobSystem.cs | 13 +-- Modules/UIElements/Core/TextElement.cs | 3 +- Modules/UIElements/Core/TextElementEdition.cs | 14 ++- Modules/UIElements/Core/UIElementsUtility.cs | 9 +- .../UIElements/Core/UXML/VisualTreeAsset.cs | 7 +- Modules/UIElementsEditor/EditorMonitor.cs | 14 ++- Modules/UIElementsEditor/EditorPanel.cs | 57 ++++++++++++ .../UIElementsEditorInitialization.cs | 2 +- .../UIElementsEditor/VisualTreeAssetEditor.cs | 2 + .../WindowBackends/DefaultWindowBackend.cs | 10 +- .../CertificateHandler.bindings.cs | 4 +- .../DownloadHandler.bindings.cs | 4 +- .../UploadHandler/UploadHandler.bindings.cs | 4 +- .../VisualEffectResource.bindings.cs | 3 +- Projects/CSharp/UnityEditor.csproj | 11 ++- Projects/CSharp/UnityEngine.csproj | 2 +- README.md | 2 +- .../Rendering/GPUDrivenRendering.bindings.cs | 13 +++ .../Export/Scripting/Awaitable.DelayedCall.cs | 38 ++++++-- Runtime/Export/iOS/iOSReplayKit.bindings.cs | 2 + 108 files changed, 1161 insertions(+), 529 deletions(-) create mode 100644 Editor/Mono/BuildProfile/BuildProfileAPI.cs delete mode 100644 Editor/Mono/Collab/CollabChangeItem.cs create mode 100644 Editor/Mono/ScriptingDefinesHelper.cs diff --git a/Editor/IncrementalBuildPipeline/PlayerBuildProgramLibrary.Data/Data.cs b/Editor/IncrementalBuildPipeline/PlayerBuildProgramLibrary.Data/Data.cs index 35507fb75a..2c0759d7eb 100644 --- a/Editor/IncrementalBuildPipeline/PlayerBuildProgramLibrary.Data/Data.cs +++ b/Editor/IncrementalBuildPipeline/PlayerBuildProgramLibrary.Data/Data.cs @@ -93,6 +93,7 @@ public class Il2CppConfig public string[] AdditionalArgs = new string[0]; public string CompilerFlags; public string LinkerFlags; + public string LinkerFlagsFile; public string ExtraTypes; public bool CreateSymbolFiles; public bool AllowDebugging; diff --git a/Editor/Mono/AssetPipeline/SpeedTree/SpeedTree9Importer.cs b/Editor/Mono/AssetPipeline/SpeedTree/SpeedTree9Importer.cs index 28c853c1ff..1820d3540b 100644 --- a/Editor/Mono/AssetPipeline/SpeedTree/SpeedTree9Importer.cs +++ b/Editor/Mono/AssetPipeline/SpeedTree/SpeedTree9Importer.cs @@ -115,10 +115,12 @@ public STMeshGeometry(int vertexCount, int UVCount, int indexLod) /// public delegate void OnCustomEditorSettings(ref SerializedProperty diffusionProfileAsset, ref SerializedProperty diffusionProfileHash); + [SerializeField] + internal SpeedTreeImporterOutputData m_OutputImporterData; + // Cache main objects, created during import process. private AssetImportContext m_Context; private SpeedTree9Reader m_Tree; - private SpeedTreeImporterOutputData m_OutputImporterData; private Shader m_Shader; private SpeedTreeWindAsset m_WindAsset; private STRenderPipeline m_RenderPipeline; @@ -214,6 +216,8 @@ public override void OnImportAsset(AssetImportContext ctx) ctx.AddObjectToAsset(m_OutputImporterData.name, m_OutputImporterData); ctx.DependsOnCustomDependency(ImporterSettings.kMaterialSettingsDependencyname); + AddDependencyOnExtractedMaterials(); + TriggerAllCabback(); } @@ -621,7 +625,7 @@ private void CreateMaterialsForCurrentLOD(STMaterial stMaterial, int lodIndex, b // Explicity regenerate materials, should happen when bumping the material version for example. if (regenerateMaterials) { - extractedMat = CreateMaterial(stMaterial, lodIndex, stMatName, m_PathFromDirectory); + extractedMat = CreateMaterial(stMaterial, lodIndex, extractedMat.name, m_PathFromDirectory); SetMaterialTextureAndColorProperties(stMaterial, extractedMat, lodIndex, m_PathFromDirectory); } @@ -630,10 +634,10 @@ private void CreateMaterialsForCurrentLOD(STMaterial stMaterial, int lodIndex, b RetrieveMaterialSpecialProperties(extractedMat); } - var existedMatIndex = m_OutputImporterData.lodMaterials.materials.FindIndex(m => m.material.name == stMatName); + var existedMatIndex = m_OutputImporterData.lodMaterials.materials.FindIndex(m => m.defaultName == stMatName); if (existedMatIndex == -1) { - m_OutputImporterData.lodMaterials.materials.Add(new MaterialInfo { material = extractedMat, exported = true }); + m_OutputImporterData.lodMaterials.materials.Add(new MaterialInfo { material = extractedMat, defaultName = stMatName, exported = true }); m_OutputImporterData.lodMaterials.matNameToIndex[stMatName] = m_OutputImporterData.lodMaterials.materials.Count - 1; } else @@ -646,7 +650,7 @@ private void CreateMaterialsForCurrentLOD(STMaterial stMaterial, int lodIndex, b { Material newMat = CreateMaterial(stMaterial, lodIndex, stMatName, m_PathFromDirectory); - m_OutputImporterData.lodMaterials.materials.Add(new MaterialInfo { material = newMat, exported = false }); + m_OutputImporterData.lodMaterials.materials.Add(new MaterialInfo { material = newMat, defaultName = stMatName, exported = false }); m_OutputImporterData.lodMaterials.matNameToIndex.Add(stMatName, m_OutputImporterData.lodMaterials.materials.Count - 1); } @@ -675,7 +679,7 @@ private void CreateAssetIdentifiersAndAddMaterialsToContext() } } - m_OutputImporterData.materialsIdentifiers.Add(new AssetIdentifier(matInfo.material.GetType(), matInfo.material.name)); + m_OutputImporterData.materialsIdentifiers.Add(new AssetIdentifier(matInfo.material.GetType(), matInfo.defaultName)); } } @@ -738,7 +742,7 @@ private void RegenerateAndPopulateExternalMaterials(string assetPath) m_OutputImporterData.materialsIdentifiers.Add(new AssetIdentifier(matInfo.material.GetType(), matInfo.material.name)); // Remap the new material to the importer 'ExternalObjectMap'. - if (TryGetExternalMaterial(matInfo.material.name, out var extractedMat)) + if (TryGetExternalMaterial(matInfo.defaultName, out var extractedMat)) { string newMatPath = AssetDatabase.GetAssetPath(extractedMat); @@ -750,7 +754,7 @@ private void RegenerateAndPopulateExternalMaterials(string assetPath) AssetDatabase.CreateAsset(matInfo.material, newMatPath); } - if (TryGetSourceAssetIdentifierFromName(matInfo.material.name, out var assetIdentifier)) + if (TryGetSourceAssetIdentifierFromName(matInfo.defaultName, out var assetIdentifier)) { AddRemap(assetIdentifier, matInfo.material); } @@ -816,17 +820,17 @@ private bool SetMaterialTexture(Material mat, STMaterial stMaterial, int indexMa { MaterialMap stMatMap = stMaterial.Maps[indexMap]; string mapPath = stMatMap.Path; - if (stMatMap.Used && !string.IsNullOrEmpty(mapPath)) - { - string finalTexturePath = path + mapPath; - Texture2D tex = (m_Context != null) - ? m_Context.GetReferenceToAssetMainObject(finalTexturePath) as Texture2D - : AssetDatabase.LoadAssetAtPath(finalTexturePath, typeof(Texture2D)) as Texture2D; + if (!stMatMap.Used) + return false; + + if (!string.IsNullOrEmpty(mapPath)) + { + Texture2D texture = LoadTexture(mapPath, path); - if (tex != null) + if (texture != null) { - mat.SetTexture(property, tex); + mat.SetTexture(property, texture); return true; } } @@ -835,6 +839,35 @@ private bool SetMaterialTexture(Material mat, STMaterial stMaterial, int indexMa return false; } + private Texture2D LoadTexture(string mapPath, string path) + { + string texturePath = path + mapPath; + + Texture2D texture = (m_Context != null) + ? m_Context.GetReferenceToAssetMainObject(texturePath) as Texture2D + : AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)) as Texture2D; + + if (texture != null) + return texture; + + // Textures are not located near the asset, let's check if they were moved somewhere else. + string mapPathWithoutExtension = Path.GetFileNameWithoutExtension(mapPath); + string[] textureAssets = AssetDatabase.FindAssets(mapPathWithoutExtension); + + if (textureAssets != null && textureAssets.Length > 0) + { + string assetPathFromGUID = AssetDatabase.GUIDToAssetPath(textureAssets[0]); + + texture = (m_Context != null) + ? m_Context.GetReferenceToAssetMainObject(assetPathFromGUID) as Texture2D + : AssetDatabase.LoadAssetAtPath(assetPathFromGUID, typeof(Texture2D)) as Texture2D; + + return texture; + } + + return null; + } + private bool TryGetInstanceIDFromMaterialProperty(Material material, int propertyName, out int id) { if (!material.HasProperty(propertyName)) @@ -1094,6 +1127,25 @@ internal void SetMaterialsVersionToCurrent() m_MaterialVersion = SPEEDTREE_9_MATERIAL_VERSION; MarkDirty(); } + + private void AddDependencyOnExtractedMaterials() + { + Dictionary extMap = GetExternalObjectMap(); + + foreach (var entry in extMap) + { + if (entry.Value != null) + { + string matPath = AssetDatabase.GetAssetPath(entry.Value); + + m_Context.DependsOnImportedAsset(matPath); + + // Necessary to avoid the warning "Import of asset setup artifact dependency to but dependency isn't used + // and therefore not registered in the asset database". + AssetDatabase.LoadAssetAtPath(matPath, typeof(Material)); + } + } + } #endregion #region Wind diff --git a/Editor/Mono/AssetPipeline/SpeedTree/SpeedTreeImporterSettings.cs b/Editor/Mono/AssetPipeline/SpeedTree/SpeedTreeImporterSettings.cs index 3e5d07af25..a6a84b45ee 100644 --- a/Editor/Mono/AssetPipeline/SpeedTree/SpeedTreeImporterSettings.cs +++ b/Editor/Mono/AssetPipeline/SpeedTree/SpeedTreeImporterSettings.cs @@ -85,6 +85,7 @@ internal class PerLODSettings internal class MaterialInfo { public Material material = null; + public string defaultName = null; public bool exported = false; } diff --git a/Editor/Mono/Audio/AudioContainerWindow.cs b/Editor/Mono/Audio/AudioContainerWindow.cs index c608ed7f67..277b9f74d2 100644 --- a/Editor/Mono/Audio/AudioContainerWindow.cs +++ b/Editor/Mono/Audio/AudioContainerWindow.cs @@ -122,21 +122,19 @@ static void OnCreateButtonClicked() void OnEnable() { Instance = this; - m_DiceIconOff = EditorGUIUtility.IconContent("AudioRandomContainer On Icon").image as Texture2D; m_DiceIconOn = EditorGUIUtility.IconContent("AudioRandomContainer Icon").image as Texture2D; - SetTitle(); - - m_IsInitializing = false; - m_Day0ElementsInitialized = false; - m_ContainerElementsInitialized = false; } void OnDisable() { Instance = null; State.OnDestroy(); + UnsubscribeFromGUICallbacksAndEvents(); + m_IsInitializing = false; + m_Day0ElementsInitialized = false; + m_ContainerElementsInitialized = false; m_CachedElements.Clear(); m_AddedElements.Clear(); } @@ -272,6 +270,11 @@ void InitializeContainerElements() void SubscribeToGUICallbacksAndEvents() { + if (!m_ContainerElementsInitialized || m_IsSubscribedToGUICallbacksAndEvents) + { + return; + } + SubscribeToPreviewCallbacksAndEvents(); SubscribeToVolumeCallbacksAndEvents(); SubscribeToPitchCallbacksAndEvents(); @@ -283,6 +286,11 @@ void SubscribeToGUICallbacksAndEvents() void UnsubscribeFromGUICallbacksAndEvents() { + if (!m_ContainerElementsInitialized || !m_IsSubscribedToGUICallbacksAndEvents) + { + return; + } + UnsubscribeFromPreviewCallbacksAndEvents(); UnsubscribeFromVolumeCallbacksAndEvents(); UnsubscribeFromPitchCallbacksAndEvents(); diff --git a/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs b/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs index a860e27b47..23f1ab7aa8 100644 --- a/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs +++ b/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs @@ -35,6 +35,8 @@ public abstract class Sysroot public abstract string GetToolchainPath(); public abstract string GetIl2CppCompilerFlags(); public abstract string GetIl2CppLinkerFlags(); + // The sysroot package does not currently contain an implemenation for this method, adding a default implementation to avoid breaking stuff + public virtual string GetIl2CppLinkerFlagsFile() => null; } } diff --git a/Editor/Mono/BuildProfile/BuildProfile.cs b/Editor/Mono/BuildProfile/BuildProfile.cs index c6e25ef88a..8dee9d232e 100644 --- a/Editor/Mono/BuildProfile/BuildProfile.cs +++ b/Editor/Mono/BuildProfile/BuildProfile.cs @@ -11,55 +11,61 @@ namespace UnityEditor.Build.Profile { /// - /// TODO EPIC: https://jira.unity3d.com/browse/PLAT-5745 + /// Provides a set of configuration settings you can use to build your application on a particular platform. /// [RequiredByNativeCode(GenerateProxy = true)] [StructLayout(LayoutKind.Sequential)] - [VisibleToOtherModules] - internal sealed partial class BuildProfile : ScriptableObject + [ExcludeFromObjectFactory] + [ExcludeFromPreset] + public sealed partial class BuildProfile : ScriptableObject { /// /// Build Target used to fetch module and build profile extension. /// [SerializeField] BuildTarget m_BuildTarget = BuildTarget.NoTarget; - public BuildTarget buildTarget + [VisibleToOtherModules] + internal BuildTarget buildTarget { get => m_BuildTarget; - internal set => m_BuildTarget = value; + set => m_BuildTarget = value; } /// /// Subtarget, Default for all non-Standalone platforms. /// [SerializeField] StandaloneBuildSubtarget m_Subtarget; - public StandaloneBuildSubtarget subtarget + [VisibleToOtherModules] + internal StandaloneBuildSubtarget subtarget { get => m_Subtarget; - internal set => m_Subtarget = value; + set => m_Subtarget = value; } /// /// Module name used to fetch build profiles. /// [SerializeField] string m_ModuleName; - public string moduleName + [VisibleToOtherModules] + internal string moduleName { get => m_ModuleName; - internal set => m_ModuleName = value; + set => m_ModuleName = value; } /// /// Platform module specific build settings; e.g. AndroidBuildSettings. /// [SerializeReference] BuildProfilePlatformSettingsBase m_PlatformBuildProfile; - public BuildProfilePlatformSettingsBase platformBuildProfile + [VisibleToOtherModules] + internal BuildProfilePlatformSettingsBase platformBuildProfile { get => m_PlatformBuildProfile; - internal set => m_PlatformBuildProfile = value; + set => m_PlatformBuildProfile = value; } [SerializeField] private EditorBuildSettingsScene[] m_Scenes = Array.Empty(); - public EditorBuildSettingsScene[] scenes + [VisibleToOtherModules] + internal EditorBuildSettingsScene[] scenes { get { @@ -101,6 +107,14 @@ internal bool IsActiveBuildProfileOrPlatform() return profileModuleName == activeModuleName && subtarget == EditorUserBuildSettings.standaloneBuildSubtarget; } + [VisibleToOtherModules] + internal bool CanBuildLocally() + { + // Note: A platform build profile may have a non-null value even if its module is not installed. + // This scenario is true for server platform profiles, which are the same type as the standalone one. + return platformBuildProfile != null && BuildProfileModuleUtil.IsModuleInstalled(moduleName, subtarget); + } + void OnEnable() { // Check if the platform support module has been installed, @@ -144,7 +158,7 @@ void CheckSceneListConsistency() RemoveAt(i); continue; } - + if (!isGuidValid) scene.guid = AssetDatabase.GUIDFromAssetPath(scene.path); diff --git a/Editor/Mono/BuildProfile/BuildProfileAPI.cs b/Editor/Mono/BuildProfile/BuildProfileAPI.cs new file mode 100644 index 0000000000..09dbe84772 --- /dev/null +++ b/Editor/Mono/BuildProfile/BuildProfileAPI.cs @@ -0,0 +1,32 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEditor.Build.Profile +{ + public sealed partial class BuildProfile + { + /// + /// Gets the active build profile. + /// + /// + /// The active build profile. Returns null when a classic platform is active. + /// + public static BuildProfile GetActiveBuildProfile() + { + return BuildProfileContext.instance.activeProfile; + } + + /// + /// Sets the active build profile. + /// + /// + /// The build profile to be set as the active build profile. + /// When the value is null, Unity sets the classic platform as active. + /// + public static void SetActiveBuildProfile(BuildProfile buildProfile) + { + BuildProfileContext.instance.activeProfile = buildProfile; + } + } +} diff --git a/Editor/Mono/BuildProfile/BuildProfileContext.cs b/Editor/Mono/BuildProfile/BuildProfileContext.cs index 045c1d67f7..6fe9260060 100644 --- a/Editor/Mono/BuildProfile/BuildProfileContext.cs +++ b/Editor/Mono/BuildProfile/BuildProfileContext.cs @@ -50,7 +50,7 @@ internal BuildProfile activeProfile get { // Active Build profile may be deleted from the project. - if (m_ActiveProfile != null && BuildProfileModuleUtil.IsModuleInstalled(m_ActiveProfile.moduleName, m_ActiveProfile.subtarget)) + if (m_ActiveProfile != null && m_ActiveProfile.CanBuildLocally()) return m_ActiveProfile; m_ActiveProfile = null; @@ -175,12 +175,6 @@ internal static BuildProfile GetActiveOrClassicBuildProfile( internal static bool TryGetActiveOrClassicPlatformSettingsBase( BuildTarget target, StandaloneBuildSubtarget subTarget, out T result) where T : BuildProfilePlatformSettingsBase { - if (!EditorUserBuildSettings.IsBuildProfileScriptingAvailable()) - { - result = null; - return false; - } - BuildProfile buildProfile = GetActiveOrClassicBuildProfile(target, subTarget); if (buildProfile != null && buildProfile.platformBuildProfile is T platformProfile) { @@ -194,6 +188,11 @@ internal static bool TryGetActiveOrClassicPlatformSettingsBase( internal BuildProfile GetForClassicPlatform(BuildTarget target, StandaloneBuildSubtarget subTarget) { + if (!BuildProfileModuleUtil.IsStandalonePlatform(target)) + subTarget = StandaloneBuildSubtarget.Default; + else if (subTarget == StandaloneBuildSubtarget.Default) + subTarget = StandaloneBuildSubtarget.Player; + var key = GetKey(target, subTarget); return m_BuildModuleNameToClassicPlatformProfile.GetValueOrDefault(key); } @@ -244,6 +243,34 @@ internal static bool IsClassicPlatformProfile(BuildProfile profile) return result; } + /// + /// Sync the active build profile to EditorUserBuildSettings to ensure they are in a consistent state. + /// + void SyncActiveProfileToFallback() + { + if (!EditorUserBuildSettings.isBuildProfileAvailable) + return; + + var buildProfile = activeProfile ?? GetForClassicPlatform(EditorUserBuildSettings.activeBuildTarget, EditorUserBuildSettings.standaloneBuildSubtarget); + + if (buildProfile == null) + { + EditorUserBuildSettings.isBuildProfileAvailable = false; + return; + } + + EditorUserBuildSettings.CopyFromBuildProfile(buildProfile); + + string module = BuildTargetDiscovery.GetModuleNameForBuildTarget(buildProfile.buildTarget); + var extension = ModuleManager.GetBuildProfileExtension(module); + if (extension != null) + { + extension.CopyPlatformSettingsFromBuildProfile(buildProfile.platformBuildProfile); + } + + EditorUserBuildSettings.isBuildProfileAvailable = false; + } + void OnDisable() { Save(); @@ -256,10 +283,18 @@ void OnDisable() if (sharedProfile != null) SaveBuildProfileInProject(sharedProfile); + + SyncActiveProfileToFallback(); + + EditorApplication.quitting -= SyncActiveProfileToFallback; } void OnEnable() { + EditorUserBuildSettings.isBuildProfileAvailable = true; + EditorApplication.quitting -= SyncActiveProfileToFallback; + EditorApplication.quitting += SyncActiveProfileToFallback; + classicPlatformProfiles = new List(); // Load platform build profiles from ProjectSettings folder. @@ -282,9 +317,6 @@ void OnEnable() continue; } - if (!BuildProfileModuleUtil.IsModuleInstalled(profileObj.moduleName, profileObj.subtarget)) - continue; - m_BuildModuleNameToClassicPlatformProfile.Add((profileObj.moduleName, profileObj.subtarget), profileObj); classicPlatformProfiles.Add(profileObj); } @@ -300,6 +332,21 @@ void OnEnable() } instance.sharedProfile = sharedProfileObj; + + var buildProfile = instance.activeProfile ?? GetForClassicPlatform(EditorUserBuildSettings.activeBuildTarget, EditorUserBuildSettings.standaloneBuildSubtarget); + + // profile can be null if we're in the middle of creating classic profiles + if (buildProfile == null) + return; + + EditorUserBuildSettings.CopyToBuildProfile(buildProfile); + + string module = BuildTargetDiscovery.GetModuleNameForBuildTarget(buildProfile.buildTarget); + var extension = ModuleManager.GetBuildProfileExtension(module); + if (extension != null) + { + extension.CopyPlatformSettingsToBuildProfile(buildProfile.platformBuildProfile); + } } /// diff --git a/Editor/Mono/BuildProfile/BuildProfileCreate.cs b/Editor/Mono/BuildProfile/BuildProfileCreate.cs index 539db67f51..f8d18b0db0 100644 --- a/Editor/Mono/BuildProfile/BuildProfileCreate.cs +++ b/Editor/Mono/BuildProfile/BuildProfileCreate.cs @@ -10,7 +10,7 @@ namespace UnityEditor.Build.Profile { - internal sealed partial class BuildProfile + public sealed partial class BuildProfile { [UsedImplicitly] internal static event Action onBuildProfileEnable; diff --git a/Editor/Mono/BuildProfile/SharedPlatformSettings.cs b/Editor/Mono/BuildProfile/SharedPlatformSettings.cs index c7f80d93ad..d31cc41f38 100644 --- a/Editor/Mono/BuildProfile/SharedPlatformSettings.cs +++ b/Editor/Mono/BuildProfile/SharedPlatformSettings.cs @@ -368,7 +368,7 @@ void SyncSharedSettings(string name) { var platformSettingsBase = profile.platformBuildProfile; if (platformSettingsBase == null) - return; + continue; switch (name) { diff --git a/Editor/Mono/Collab/CollabChangeItem.cs b/Editor/Mono/Collab/CollabChangeItem.cs deleted file mode 100644 index ad380552c0..0000000000 --- a/Editor/Mono/Collab/CollabChangeItem.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using System.Runtime.InteropServices; -using UnityEngine.Bindings; - diff --git a/Editor/Mono/Collab/CollabTesting.cs b/Editor/Mono/Collab/CollabTesting.cs index 06c451a530..d244a0443a 100644 --- a/Editor/Mono/Collab/CollabTesting.cs +++ b/Editor/Mono/Collab/CollabTesting.cs @@ -64,7 +64,6 @@ public static void Execute() if (_enumerator == null) return; - try { if (!_enumerator.MoveNext()) diff --git a/Editor/Mono/ConsoleWindow.cs b/Editor/Mono/ConsoleWindow.cs index 264f8c48be..4086585822 100644 --- a/Editor/Mono/ConsoleWindow.cs +++ b/Editor/Mono/ConsoleWindow.cs @@ -886,7 +886,7 @@ internal static string StacktraceWithHyperlinks(string stacktraceText, int calls filePathPart.Substring(lineIndex + 1, (endLineIndex) - (lineIndex + 1)); string filePath = filePathPart.Substring(0, lineIndex); - textWithHyperlinks.Append($"{lines[i].Substring(0, filePathIndex)}{filePath}:{lineString})\n"); + textWithHyperlinks.Append($"{lines[i].Substring(0, filePathIndex)}{filePath}:{lineString})\n"); continue; // continue to evade the default case } diff --git a/Editor/Mono/EditorApplication.cs b/Editor/Mono/EditorApplication.cs index 44436baa44..d419ff9b10 100644 --- a/Editor/Mono/EditorApplication.cs +++ b/Editor/Mono/EditorApplication.cs @@ -45,10 +45,15 @@ public enum PauseState public class ApplicationTitleDescriptor { + [Obsolete("Do not create your own instance of ApplicationTitleDescriptor. Use the one provided by EditorApplication.updateMainWindowTitle instead.")] public ApplicationTitleDescriptor(string projectName, string unityVersion, string activeSceneName, string targetName, bool codeCoverageEnabled) + : this(projectName, "Unity", unityVersion, activeSceneName, targetName, codeCoverageEnabled) {} + + internal ApplicationTitleDescriptor(string projectName, string unityProductName, string unityVersion, string activeSceneName, string targetName, bool codeCoverageEnabled) { title = ""; this.projectName = projectName; + this.unityProductName = unityProductName; this.unityVersion = unityVersion; this.activeSceneName = activeSceneName; this.targetName = targetName; @@ -57,6 +62,7 @@ public ApplicationTitleDescriptor(string projectName, string unityVersion, strin public string title; public string projectName { get; private set; } + public string unityProductName { get; private set; } public string unityVersion { get; private set; } public string activeSceneName { get; private set; } public string targetName { get; private set; } @@ -319,7 +325,7 @@ internal static string GetDefaultMainWindowTitle(ApplicationTitleDescriptor desc title += $" - {desc.targetName}"; } - title += $" - Unity {desc.unityVersion}"; + title += $" - {desc.unityProductName} ({desc.unityVersion})"; if (desc.codeCoverageEnabled) { @@ -340,33 +346,26 @@ internal static string BuildMainWindowTitle() internal static ApplicationTitleDescriptor GetApplicationTitleDescriptor() { - var activeSceneName = L10n.Tr("Untitled"); - if (!string.IsNullOrEmpty(SceneManager.GetActiveScene().path)) - { - activeSceneName = Path.GetFileNameWithoutExtension(SceneManager.GetActiveScene().path); - } - - ApplicationTitleDescriptor desc; - if (PreferencesProvider.useProjectPathInTitle) - { - desc = new ApplicationTitleDescriptor( - Path.GetFullPath(Path.Combine(Application.dataPath, "..")), - (Unsupported.IsSourceBuild() || Unsupported.IsDeveloperMode()) ? InternalEditorUtility.GetUnityDisplayVersion() : Application.unityVersion, - activeSceneName, - BuildPipeline.GetBuildTargetGroupDisplayName(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget)), - Coverage.enabled - ); - } - else - { - desc = new ApplicationTitleDescriptor( - GetDefaultProjectName(), - (Unsupported.IsSourceBuild() || Unsupported.IsDeveloperMode()) ? InternalEditorUtility.GetUnityDisplayVersion() : Application.unityVersion, - activeSceneName, - BuildPipeline.GetBuildTargetGroupDisplayName(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget)), - Coverage.enabled - ); - } + var activeSceneName = string.IsNullOrEmpty(SceneManager.GetActiveScene().path) + ? L10n.Tr("Untitled") + : Path.GetFileNameWithoutExtension(SceneManager.GetActiveScene().path); + + var unityVersion = Unsupported.IsSourceBuild() || Unsupported.IsDeveloperMode() + ? InternalEditorUtility.GetUnityDisplayVersion() + : Application.unityVersion; + + var projectString = PreferencesProvider.useProjectPathInTitle + ? Path.GetFullPath(Path.Combine(Application.dataPath, "..")) + : GetDefaultProjectName(); + + var desc = new ApplicationTitleDescriptor( + projectString, + InternalEditorUtility.GetUnityProductName(), + unityVersion, + activeSceneName, + BuildPipeline.GetBuildTargetGroupDisplayName(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget)), + Coverage.enabled + ); desc.title = GetDefaultMainWindowTitle(desc); diff --git a/Editor/Mono/EditorBuildSettings.bindings.cs b/Editor/Mono/EditorBuildSettings.bindings.cs index bb75dd494c..bc15374261 100644 --- a/Editor/Mono/EditorBuildSettings.bindings.cs +++ b/Editor/Mono/EditorBuildSettings.bindings.cs @@ -109,7 +109,7 @@ public static EditorBuildSettingsScene[] scenes [RequiredByNativeCode] static EditorBuildSettingsScene[] GetActiveBuildProfileSceneList() { - if (BuildProfileContext.instance.activeProfile is null) + if (!EditorUserBuildSettings.isBuildProfileAvailable || BuildProfileContext.instance.activeProfile is null) return null; return BuildProfileContext.instance.activeProfile.scenes; diff --git a/Editor/Mono/EditorGUIUtility.cs b/Editor/Mono/EditorGUIUtility.cs index 54406b156e..6f4c7eb27d 100644 --- a/Editor/Mono/EditorGUIUtility.cs +++ b/Editor/Mono/EditorGUIUtility.cs @@ -351,50 +351,6 @@ internal static Rect DrawEditorHeaderItems(Rect rectangle, UnityObject[] targetO return rectangle; } - /// - /// Use this container and helper class when implementing lock behaviour on a window when also using an . - /// - [Serializable] - internal class EditorLockTrackerWithActiveEditorTracker : EditorLockTracker - { - internal override bool isLocked - { - get - { - if (m_Tracker != null) - { - base.isLocked = m_Tracker.isLocked; - return m_Tracker.isLocked; - } - return base.isLocked; - } - set - { - if (m_Tracker != null) - { - m_Tracker.isLocked = value; - } - base.isLocked = value; - } - } - - [SerializeField, HideInInspector] - ActiveEditorTracker m_Tracker; - - internal ActiveEditorTracker tracker - { - get { return m_Tracker; } - set - { - m_Tracker = value; - if (m_Tracker != null) - { - isLocked = m_Tracker.isLocked; - } - } - } - } - /// /// Use this container and helper class when implementing lock behaviour on a window. /// @@ -1838,6 +1794,11 @@ public static int GetObjectPickerControlID() return ObjectSelector.get.objectSelectorID; } + internal static string GetHyperlinkColorForSkin() + { + return skinIndex == EditorResources.darkSkinIndex ? "#40a0ff" : "#0000FF"; + } + // Enum for tracking what styles the editor uses internal enum EditorLook { diff --git a/Editor/Mono/EditorMode/ModeService.cs b/Editor/Mono/EditorMode/ModeService.cs index a2a6a49294..9566cd6f3d 100644 --- a/Editor/Mono/EditorMode/ModeService.cs +++ b/Editor/Mono/EditorMode/ModeService.cs @@ -137,7 +137,7 @@ static ModeService() { Log("Initialize"); - LoadModes(true); + LoadModes(); modeChanged += OnModeChangeMenus; modeChanged += OnModeChangeLayouts; @@ -360,18 +360,19 @@ private static void OnRegisteredPackages(PackageManager.PackageRegistrationEvent LoadModes(); } - private static void LoadModes(bool checkStartupMode = false) + private static void LoadModes() { Log("LoadModes"); ScanModes(); - + var currentModeIndex = GetSessionModeIndex(); if (currentModeIndex == -1) { currentModeIndex = LoadProjectPrefModeIndex(); } - if (checkStartupMode && HasStartupMode()) + + if (!initialModeChanged && HasStartupMode()) { var requestEditorMode = Application.GetValueForARGV("editor-mode"); var modeIndex = GetModeIndexById(requestEditorMode); @@ -387,6 +388,8 @@ private static void LoadModes(bool checkStartupMode = false) private static void SaveSessionMode() { + if (!HasCapability(ModeCapability.Remember, true)) + return; SessionState.SetString(k_ModeCurrentIdKeyName, currentId); } diff --git a/Editor/Mono/EditorSettings.bindings.cs b/Editor/Mono/EditorSettings.bindings.cs index cbb847638d..b81b93a458 100644 --- a/Editor/Mono/EditorSettings.bindings.cs +++ b/Editor/Mono/EditorSettings.bindings.cs @@ -316,5 +316,8 @@ public enum NamingScheme [StaticAccessor("GetEditorSettings()", StaticAccessorType.Dot)] internal static extern bool inspectorUseIMGUIDefaultInspector { get; set; } + + [StaticAccessor("GetEditorSettings()", StaticAccessorType.Dot)] + public static extern bool referencedClipsExactNaming { get; set; } } } diff --git a/Editor/Mono/EditorTextSettings.cs b/Editor/Mono/EditorTextSettings.cs index f7d00c25fd..296324fc0f 100644 --- a/Editor/Mono/EditorTextSettings.cs +++ b/Editor/Mono/EditorTextSettings.cs @@ -59,7 +59,11 @@ internal static EditorTextSettings defaultTextSettings { s_DefaultTextSettings = EditorGUIUtility.Load(s_DefaultEditorTextSettingPath) as EditorTextSettings; if (s_DefaultTextSettings) + { UpdateLocalizationFontAsset(); + UpdateDefaultTextStyleSheet(); + GUISkin.m_SkinChanged += UpdateDefaultTextStyleSheet; + } } return s_DefaultTextSettings; @@ -99,6 +103,13 @@ internal static void UpdateLocalizationFontAsset() defaultTextSettings.emojiFallbackTextAssets.Add(emojiFallback); } + internal static void UpdateDefaultTextStyleSheet() + { + s_DefaultTextSettings.defaultStyleSheet = EditorGUIUtility.Load(EditorGUIUtility.skinIndex == EditorResources.darkSkinIndex ? s_DarkEditorTextStyleSheetPath : s_LightEditorTextStyleSheetPath) as TextStyleSheet; + } + internal static readonly string s_DefaultEditorTextSettingPath = "UIPackageResources/Editor Text Settings.asset"; + internal static readonly string s_DarkEditorTextStyleSheetPath = "UIPackageResources/Dark Editor Text StyleSheet.asset"; + internal static readonly string s_LightEditorTextStyleSheetPath = "UIPackageResources/Light Editor Text StyleSheet.asset"; } } diff --git a/Editor/Mono/EditorUserBuildSettings.bindings.cs b/Editor/Mono/EditorUserBuildSettings.bindings.cs index bb73b4e3f0..87cd22e516 100644 --- a/Editor/Mono/EditorUserBuildSettings.bindings.cs +++ b/Editor/Mono/EditorUserBuildSettings.bindings.cs @@ -1077,7 +1077,8 @@ public static int managedDebuggerFixedPort } } - internal static extern bool IsBuildProfileScriptingAvailable(); + internal static extern bool isBuildProfileAvailable { get; set; } + internal static extern void CopyFromBuildProfile(ScriptableObject buildProfile); internal static extern void CopyToBuildProfile(ScriptableObject buildProfile); } } diff --git a/Editor/Mono/EditorWindow.cs b/Editor/Mono/EditorWindow.cs index 9085255586..601d0984f1 100644 --- a/Editor/Mono/EditorWindow.cs +++ b/Editor/Mono/EditorWindow.cs @@ -1436,6 +1436,7 @@ internal void OnBackingScaleFactorChangedInternal() { if(overlayCanvas != null) overlayCanvas.Rebuild(); + OnBackingScaleFactorChanged(); } diff --git a/Editor/Mono/GUI/AboutWindow.cs b/Editor/Mono/GUI/AboutWindow.cs index 6772e00035..f376aff86c 100644 --- a/Editor/Mono/GUI/AboutWindow.cs +++ b/Editor/Mono/GUI/AboutWindow.cs @@ -12,7 +12,10 @@ namespace UnityEditor { internal class AboutWindow : EditorWindow { + const int VersionBoxLineHeight = 13; + const int VersionBoxHeight = VersionBoxLineHeight * 4; static readonly Vector2 WindowSize = new Vector2(640, 265); + static readonly Vector2 WindowSizeExpanded = new Vector2(WindowSize.x, WindowSize.y + VersionBoxLineHeight * 2); // Adding 2 more lines to the version box [RequiredByNativeCode] internal static void ShowAboutWindow() @@ -99,14 +102,20 @@ public void OnGUI() DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, 0); string branch = InternalEditorUtility.GetUnityBuildBranch(); EditorGUILayout.SelectableLabel( - string.Format("{0}{1}\nRevision: {2} {3}\nBuilt: {4:r}", - InternalEditorUtility.GetUnityDisplayVersionVerbose(), extensionVersion, - branch, InternalEditorUtility.GetUnityBuildHash(), dt.AddSeconds(t)), - Styles.versionStyle, GUILayout.MaxWidth(mainLayoutWidth), GUILayout.Height(38f)); + $"{InternalEditorUtility.GetUnityProductName()}\n" + + $"{InternalEditorUtility.GetUnityDisplayVersionVerbose()}{extensionVersion}\n" + + $"Revision: {branch} {InternalEditorUtility.GetUnityBuildHash()}\n" + + $"Built: {dt.AddSeconds(t):r}", + Styles.versionStyle, + GUILayout.MaxWidth(mainLayoutWidth), GUILayout.Height(VersionBoxHeight)); + + minSize = maxSize = WindowSizeExpanded; } else { - GUILayout.Label(string.Format("{0}{1}", InternalEditorUtility.GetUnityDisplayVersion(), extensionVersion), Styles.versionStyle); + GUILayout.Label( + $"{InternalEditorUtility.GetUnityProductName()}\n" + + $"{InternalEditorUtility.GetUnityDisplayVersion()}{extensionVersion}", Styles.versionStyle); } if (evt.type == EventType.ValidateCommand) diff --git a/Editor/Mono/GUI/DockArea.cs b/Editor/Mono/GUI/DockArea.cs index 11701f38dd..06434192be 100644 --- a/Editor/Mono/GUI/DockArea.cs +++ b/Editor/Mono/GUI/DockArea.cs @@ -1169,7 +1169,7 @@ private float DrawTab(Rect tabRegionRect, GUIStyle tabStyle, int tabIndex, float bool isActive = m_Panes[tabIndex] == EditorWindow.focusedWindow; - if (isActive) + if (isActive && !s_HasStaticTabsCapability) UpdateWindowTitle(m_Panes[tabIndex]); // UnsavedChanges decoration already taken care of. Rect tabContentRect = new Rect(roundedPosX, tabPositionRect.y, roundedWidth, tabPositionRect.height); diff --git a/Editor/Mono/GUI/Toolbars/Toolbar.cs b/Editor/Mono/GUI/Toolbars/Toolbar.cs index 0cd8cb7c6c..5b63f801b9 100644 --- a/Editor/Mono/GUI/Toolbars/Toolbar.cs +++ b/Editor/Mono/GUI/Toolbars/Toolbar.cs @@ -138,6 +138,7 @@ static VisualElement CreateRoot() protected override void OnBackingScaleFactorChanged() { + base.OnBackingScaleFactorChanged(); CreateContents(); } diff --git a/Editor/Mono/GUIView.cs b/Editor/Mono/GUIView.cs index 63c4a1b780..2ece4586fb 100644 --- a/Editor/Mono/GUIView.cs +++ b/Editor/Mono/GUIView.cs @@ -178,6 +178,11 @@ internal IWindowBackend windowBackend m_WindowBackend = value; m_WindowBackend?.OnCreate(this); + // When the native side has triggered OnBackingScaleFactorChanged, it will not send it again even if we are adding view to a hostView. + // (Docking, domain reload) + // It also occurs that the event is sent when the backend is not yet set in the view + // lets trigger the sizeChanged and OnBackingScaleFactorChanged to remedy any scenario + windowBackend?.SizeChanged(); } } @@ -212,7 +217,10 @@ protected virtual void OldOnGUI() {} // In that case, commands are not delegated (e.g., keyboard-based delete in Hierarchy/Project) protected virtual void OnGUI() {} - protected virtual void OnBackingScaleFactorChanged() { } + protected virtual void OnBackingScaleFactorChanged() + { + windowBackend?.OnBackingScaleFactorChanged(); + } protected override void SetPosition(Rect newPos) { diff --git a/Editor/Mono/HostView.cs b/Editor/Mono/HostView.cs index d2ebfc8d9e..b52ce0ba23 100644 --- a/Editor/Mono/HostView.cs +++ b/Editor/Mono/HostView.cs @@ -374,6 +374,7 @@ internal void OnLostFocus() protected override void OnBackingScaleFactorChanged() { + base.OnBackingScaleFactorChanged(); if (m_ActualView != null) m_ActualView.OnBackingScaleFactorChangedInternal(); } diff --git a/Editor/Mono/Inspector/Core/AdvancedDropdown/AdvancedDropdownGUI.cs b/Editor/Mono/Inspector/Core/AdvancedDropdown/AdvancedDropdownGUI.cs index ca26e20101..5ab273f096 100644 --- a/Editor/Mono/Inspector/Core/AdvancedDropdown/AdvancedDropdownGUI.cs +++ b/Editor/Mono/Inspector/Core/AdvancedDropdown/AdvancedDropdownGUI.cs @@ -43,6 +43,7 @@ internal static void LoadStyles() internal Rect m_SearchRect; internal Rect m_HeaderRect; + internal Rect areaRect { get; set; } internal virtual float searchHeight => m_SearchRect.height; internal virtual float headerHeight => m_HeaderRect.height; internal virtual GUIStyle lineStyle => Styles.itemStyle; @@ -57,12 +58,21 @@ public AdvancedDropdownGUI(AdvancedDropdownDataSource dataSource) internal virtual void DrawItem(AdvancedDropdownItem item, string name, Texture2D icon, bool enabled, bool drawArrow, bool selected, bool hasSearch) { var content = item.content; - var imgTemp = content.image; - //we need to pretend we have an icon to calculate proper width in case + + // We need to pretend we have an icon to calculate proper width in case + var lastContentImage = content.image; if (content.image == null) content.image = Texture2D.whiteTexture; + + // Clamp the rect width var rect = GetItemRect(content); - content.image = imgTemp; + var maxWidth = areaRect.width - GUI.skin.verticalScrollbar.fixedWidth; // todo: find a way to detect if we have a scrollbar + if (drawArrow) + maxWidth -= Styles.rightArrow.fixedWidth + Styles.rightArrow.margin.right; + if (maxWidth > 0) + rect.width = Math.Min(rect.width, maxWidth); + + content.image = lastContentImage; if (!string.IsNullOrEmpty(content.tooltip) && rect.Contains(Event.current.mousePosition) && !string.Equals(content.tooltip, content.text, StringComparison.Ordinal)) @@ -71,7 +81,7 @@ internal virtual void DrawItem(AdvancedDropdownItem item, string name, Texture2D if (Event.current.type != EventType.Repaint) return; - var imageTemp = content.image; + lastContentImage = content.image; if (m_DataSource.selectedIDs.Any() && m_DataSource.selectedIDs.Contains(item.id)) { var checkMarkRect = new Rect(rect); @@ -80,7 +90,7 @@ internal virtual void DrawItem(AdvancedDropdownItem item, string name, Texture2D rect.x += iconSize.x + 1; rect.width -= iconSize.x + 1; - //don't draw the icon if the check mark is present + // Don't draw the icon if the check mark is present content.image = null; } else if (content.image == null) @@ -89,20 +99,28 @@ internal virtual void DrawItem(AdvancedDropdownItem item, string name, Texture2D rect.x += iconSize.x + 1; rect.width -= iconSize.x + 1; } + EditorGUI.BeginDisabled(!enabled); + var lastStyleClipping = lineStyle.clipping; + lineStyle.clipping = TextClipping.Ellipsis; + DrawItemContent(item, rect, content, false, false, selected, selected); - content.image = imageTemp; + + lineStyle.clipping = lastStyleClipping; + content.image = lastContentImage; + if (drawArrow) { var yOffset = (lineStyle.fixedHeight - Styles.rightArrow.fixedHeight) / 2; Rect arrowRect = new Rect( - rect.xMax - Styles.rightArrow.fixedWidth - Styles.rightArrow.margin.right, + rect.xMax, rect.y + yOffset, Styles.rightArrow.fixedWidth, Styles.rightArrow.fixedHeight); Styles.rightArrow.Draw(arrowRect, false, false, false, false); } + EditorGUI.EndDisabled(); } diff --git a/Editor/Mono/Inspector/Core/AdvancedDropdown/AdvancedDropdownWindow.cs b/Editor/Mono/Inspector/Core/AdvancedDropdown/AdvancedDropdownWindow.cs index 69749d861d..88db9731a3 100644 --- a/Editor/Mono/Inspector/Core/AdvancedDropdown/AdvancedDropdownWindow.cs +++ b/Editor/Mono/Inspector/Core/AdvancedDropdown/AdvancedDropdownWindow.cs @@ -392,6 +392,7 @@ private void DrawDropdown(float anim, AdvancedDropdownItem group) areaPosition.y += kBorderThickness; areaPosition.height -= kBorderThickness * 2; areaPosition.width -= kBorderThickness * 2; + m_Gui.areaRect = areaPosition; GUILayout.BeginArea(m_Gui.GetAnimRect(areaPosition, anim)); // Header diff --git a/Editor/Mono/Inspector/Core/InspectorWindow.cs b/Editor/Mono/Inspector/Core/InspectorWindow.cs index e8264fa3fb..9b9d65cab2 100644 --- a/Editor/Mono/Inspector/Core/InspectorWindow.cs +++ b/Editor/Mono/Inspector/Core/InspectorWindow.cs @@ -22,7 +22,7 @@ internal class InspectorWindow : PropertyEditor, IPropertyView, IHasCustomMenu static readonly List m_AllInspectors = new List(); static bool s_AllOptimizedGUIBlocksNeedsRebuild; - [SerializeField] EditorGUIUtility.EditorLockTrackerWithActiveEditorTracker m_LockTracker = new EditorGUIUtility.EditorLockTrackerWithActiveEditorTracker(); + [SerializeField] EditorGUIUtility.EditorLockTracker m_LockTracker = new EditorGUIUtility.EditorLockTracker(); [SerializeField] PreviewWindow m_PreviewWindow; readonly HashSet m_UserSupportedDataModes = new(4); @@ -33,14 +33,10 @@ public bool isLocked { get { - //this makes sure the getter for InspectorWindow.tracker gets called and creates an ActiveEditorTracker if needed - m_LockTracker.tracker = tracker; return m_LockTracker.isLocked; } set { - //this makes sure the getter for InspectorWindow.tracker gets called and creates an ActiveEditorTracker if needed - m_LockTracker.tracker = tracker; m_LockTracker.isLocked = value; } } @@ -54,7 +50,7 @@ internal void Awake() protected override void OnDestroy() { - if (m_PreviewWindow != null) + if (m_PreviewWindow is { IsFloatingWindow: true }) m_PreviewWindow.Close(); if (m_Tracker != null && !m_Tracker.Equals(ActiveEditorTracker.sharedTracker)) { @@ -86,11 +82,8 @@ protected override void OnEnable() RestoreLockStateFromSerializedData(); if (m_LockTracker == null) - { - m_LockTracker = new EditorGUIUtility.EditorLockTrackerWithActiveEditorTracker(); - } + m_LockTracker = new EditorGUIUtility.EditorLockTracker(); - m_LockTracker.tracker = tracker; m_LockTracker.lockStateChanged.AddListener(LockStateChanged); m_Tracker.dataMode = GetDataModeController_Internal().dataMode; @@ -233,30 +226,24 @@ protected override void UpdateWindowObjectNameTitle() // The inspector window doesn't not track the object name. } + protected override void EnsureAppropriateTrackerIsInUse() + { + if (m_InspectorMode == InspectorMode.Normal && !isLocked) + m_Tracker = ActiveEditorTracker.sharedTracker; + else if (m_Tracker is null || m_Tracker.Equals(ActiveEditorTracker.sharedTracker)) + m_Tracker = new ActiveEditorTracker(); + } + protected override void CreateTracker() { - if (m_Tracker != null) - { - // Ensure that inspector mode - // This shouldn't be necessary but there are some non-reproducable bugs objects showing up as not able to multi-edit - // because this state goes out of sync. - m_Tracker.inspectorMode = m_InspectorMode; + if (m_Tracker != null && m_Tracker.inspectorMode == m_InspectorMode) return; - } - m_Tracker = sharedTrackerInUse ? new ActiveEditorTracker() : ActiveEditorTracker.sharedTracker; + EnsureAppropriateTrackerIsInUse(); m_Tracker.inspectorMode = m_InspectorMode; m_Tracker.RebuildIfNecessary(); } - bool sharedTrackerInUse - { - get - { - return m_AllInspectors.Any(i => i.m_Tracker != null && i.m_Tracker.Equals(ActiveEditorTracker.sharedTracker)); - } - } - protected virtual void ShowButton(Rect r) { m_LockTracker.ShowButton(r, Styles.lockButton); @@ -264,16 +251,25 @@ protected virtual void ShowButton(Rect r) private void LockStateChanged(bool lockState) { - if (lockState) + EnsureAppropriateTrackerIsInUse(); + + m_Tracker.isLocked = lockState; // Update the lock state of the ActiveEditorTracker in use + if (m_Tracker.isLocked != lockState) { - PrepareLockedObjectsForSerialization(); + // Sync LockTracker lock state if m_Tracker failed to lock e.g. if user tried to lock Packages folder https://fogbugz.unity3d.com/f/cases/1173185/ + m_LockTracker.isLocked = m_Tracker.isLocked; + return; } + + if (lockState) + PrepareLockedObjectsForSerialization(); else - { ClearSerializedLockedObjects(); - } - tracker.RebuildIfNecessary(); + if (lockState) + tracker.RebuildIfNecessary(); + else + tracker.ForceRebuild(); } protected override bool CloseIfEmpty() @@ -446,9 +442,7 @@ internal void SetObjectsLocked(List objs) private void RestoreLockStateFromSerializedData() { if (m_Tracker == null) - { return; - } // try to retrieve all Objects from their stored instance ids in the list. // this is only used for non persistent objects (scene objects) @@ -474,9 +468,11 @@ private void RestoreLockStateFromSerializedData() } } - // set the tracker to the serialized list. if it contains nulls or is empty, the tracker won't lock + // set the tracker to the serialized list. if it contains nulls or is empty, the tracker will be set to unlocked // this fixes case 775007 m_Tracker.SetObjectsLockedByThisTracker(m_ObjectsLockedBeforeSerialization); + // Sync LockTracker lock state with m_Tracker lock state in case m_ObjectsLockedBeforeSerialization is empty + m_LockTracker.isLocked = m_Tracker.isLocked; // since this method likely got called during OnEnable, and rebuilding the tracker could call OnDisable on all Editors, // some of which might not have gotten their enable yet, the rebuilding needs to happen delayed in EditorApplication.update EditorApplication.CallDelayed(tracker.RebuildIfNecessary, 0f); diff --git a/Editor/Mono/Inspector/Core/PreviewWindow.cs b/Editor/Mono/Inspector/Core/PreviewWindow.cs index 3ae0d02fd0..c01a32ebf5 100644 --- a/Editor/Mono/Inspector/Core/PreviewWindow.cs +++ b/Editor/Mono/Inspector/Core/PreviewWindow.cs @@ -16,6 +16,8 @@ internal class PreviewWindow : InspectorWindow VisualElement previewElement => m_previewElement ?? (m_previewElement = rootVisualElement.Q(className: "unity-inspector-preview")); + internal bool IsFloatingWindow => parent is { window.rootView: not null, window.showMode: not ShowMode.MainWindow }; + private readonly string k_PreviewName = "preview-container"; internal override BindingLogLevel defaultBindingLogLevel => BindingLogLevel.None; public void SetParentInspector(InspectorWindow inspector) diff --git a/Editor/Mono/Inspector/Core/PropertyEditor.cs b/Editor/Mono/Inspector/Core/PropertyEditor.cs index c28ee88510..30d7b6c1d0 100644 --- a/Editor/Mono/Inspector/Core/PropertyEditor.cs +++ b/Editor/Mono/Inspector/Core/PropertyEditor.cs @@ -475,6 +475,13 @@ internal static IEnumerable GetPropertyEditors() return m_AllPropertyEditors.AsEnumerable(); } + protected virtual void EnsureAppropriateTrackerIsInUse() + { + if (m_InspectorMode == InspectorMode.Normal) + m_Tracker = ActiveEditorTracker.sharedTracker; + else if (m_Tracker is null || m_Tracker.Equals(ActiveEditorTracker.sharedTracker)) + m_Tracker = new ActiveEditorTracker(); + } protected void SetMode(InspectorMode mode) { @@ -485,7 +492,12 @@ protected void SetMode(InspectorMode mode) // Clear the editors Element so that a real rebuild is done editorsElement.Clear(); m_EditorElementUpdater.Clear(); - tracker.inspectorMode = mode; + + EnsureAppropriateTrackerIsInUse(); + + m_Tracker.inspectorMode = m_InspectorMode; + m_Tracker.ForceRebuild(); + m_ResetKeyboardControl = true; SceneView.SetActiveEditorsDirty(true); } @@ -2547,6 +2559,8 @@ private Dictionary ProcessEditorElementsToRebuild(Editor[] if (!(ed.target is ParticleSystemRenderer)) { currentElement.ReinitCulled(newEditorsIndex, editors); + if (!InspectorElement.disabledThrottling) + m_EditorElementUpdater.Add(currentElement); // We need to move forward as the current element is the culled one, so we're not really // interested in it. @@ -2563,6 +2577,8 @@ private Dictionary ProcessEditorElementsToRebuild(Editor[] editors[newEditorsIndex].propertyViewer = this; currentElement.Reinit(newEditorsIndex, editors); + if (!InspectorElement.disabledThrottling) + m_EditorElementUpdater.Add(currentElement); editorToElementMap[ed.target.GetInstanceID()] = currentElement; ++newEditorsIndex; ++previousEditorsIndex; diff --git a/Editor/Mono/Inspector/EditorSettingsInspector.cs b/Editor/Mono/Inspector/EditorSettingsInspector.cs index e0ad22f936..0407ed384c 100644 --- a/Editor/Mono/Inspector/EditorSettingsInspector.cs +++ b/Editor/Mono/Inspector/EditorSettingsInspector.cs @@ -114,6 +114,8 @@ class Content public static readonly GUIContent numberingHierarchyScheme = EditorGUIUtility.TrTextContent("Game Object Naming"); public static readonly GUIContent numberingHierarchyDigits = EditorGUIUtility.TrTextContent("Game Object Digits"); public static readonly GUIContent numberingProjectSpace = EditorGUIUtility.TrTextContent("Space Before Number in Asset Names"); + + public static GUIContent referencedClipsExactNaming = EditorGUIUtility.TrTextContent("Exactly Match Referenced Clip Names", "Controls how referenced clips are matched with models that are animated in Legacy mode. If turned on, the model name and the referenced clip names must exactly match. If turned off, only the start of the model name needs to match the referenced clip name. Also controls the behavior of the \"Update referenced clips\" button for models that are animated in Humanoid mode. See the documentation for EditorSettings.referencedClipsExactNaming for more details."); } internal struct PopupElement @@ -739,6 +741,22 @@ private void DoAssetPipelineSettings() EditorUserSettings.idleImportWorkerShutdownDelayMilliseconds = (int)(newSeconds * 1000.0f); } } + + EditorGUI.BeginChangeCheck(); + bool referencedClipsExactNaming = EditorSettings.referencedClipsExactNaming; + referencedClipsExactNaming = EditorGUILayout.Toggle(Content.referencedClipsExactNaming, referencedClipsExactNaming); + if (EditorGUI.EndChangeCheck()) + { + if (EditorUtility.DisplayDialog( + "Warning: Long Import Times", + "Changing this setting might result in several models being re-imported", + $"Proceed", + "Cancel")) + { + EditorSettings.referencedClipsExactNaming = referencedClipsExactNaming; + AssetDatabase.Refresh(); + } + } } private void DoCacheServerSettings() diff --git a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs index 756f9cf702..b30e5fde9d 100644 --- a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs +++ b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs @@ -897,7 +897,7 @@ public override void OnInspectorGUI() { EditorGUI.EndEditingActiveTextField(); GUIUtility.keyboardControl = 0; - string[] defines = PlayerSettings.ConvertScriptingDefineStringToArray(EditorGUI.s_DelayedTextEditor.text); + string[] defines = ScriptingDefinesHelper.ConvertScriptingDefineStringToArray(EditorGUI.s_DelayedTextEditor.text); SetScriptingDefineSymbolsForGroup(validPlatforms[oldPlatform].namedBuildTarget, defines); } // Reset focus when changing between platforms. @@ -3044,10 +3044,12 @@ private void OtherSectionConfigurationGUI(BuildPlatform platform, ISettingEditor EditorGUILayout.PropertyField(m_ForceIOSSpeakersWhenRecording, SettingsContent.forceIOSSpeakersWhenRecording); } EditorGUILayout.PropertyField(m_UIRequiresPersistentWiFi, SettingsContent.UIRequiresPersistentWiFi); - EditorGUILayout.PropertyField(m_IOSURLSchemes, SettingsContent.iOSURLSchemes, true); } } + if (platform.namedBuildTarget == NamedBuildTarget.iOS || platform.namedBuildTarget == NamedBuildTarget.tvOS || platform.namedBuildTarget == NamedBuildTarget.VisionOS) + EditorGUILayout.PropertyField(m_IOSURLSchemes, SettingsContent.iOSURLSchemes, true); + if (settingsExtension != null) settingsExtension.ConfigurationSectionGUI(); @@ -3104,7 +3106,7 @@ private string GetScriptingDefineSymbolsForGroup(NamedBuildTarget buildTarget) private void SetScriptingDefineSymbolsForGroup(NamedBuildTarget buildTarget, string[] defines) { - m_ScriptingDefines.SetMapValue(buildTarget.TargetName, PlayerSettings.ConvertScriptingDefineArrayToString(defines)); + m_ScriptingDefines.SetMapValue(buildTarget.TargetName, ScriptingDefinesHelper.ConvertScriptingDefineArrayToString(defines)); } string[] GetAdditionalCompilerArgumentsForGroup(NamedBuildTarget buildTarget) @@ -3857,7 +3859,7 @@ void InitReorderableScriptingDefineSymbolsList(NamedBuildTarget namedBuildTarget { // Get Scripting Define Symbols data string defines = GetScriptingDefineSymbolsForGroup(namedBuildTarget); - scriptingDefinesList = new List(PlayerSettings.ConvertScriptingDefineStringToArray(serializedScriptingDefines)); + scriptingDefinesList = new List(ScriptingDefinesHelper.ConvertScriptingDefineStringToArray(serializedScriptingDefines)); // Initialize Reorderable List scriptingDefineSymbolsList = new ReorderableList(scriptingDefinesList, typeof(string), true, true, true, true); @@ -3870,7 +3872,7 @@ void InitReorderableScriptingDefineSymbolsList(NamedBuildTarget namedBuildTarget void UpdateScriptingDefineSymbolsLists() { - scriptingDefinesList = new List(PlayerSettings.ConvertScriptingDefineStringToArray(serializedScriptingDefines)); + scriptingDefinesList = new List(ScriptingDefinesHelper.ConvertScriptingDefineStringToArray(serializedScriptingDefines)); scriptingDefineSymbolsList.list = scriptingDefinesList; scriptingDefineSymbolsList.DoLayoutList(); hasScriptingDefinesBeenModified = false; diff --git a/Editor/Mono/InternalEditorUtility.bindings.cs b/Editor/Mono/InternalEditorUtility.bindings.cs index 78cc185ae9..8e82f1ea5c 100644 --- a/Editor/Mono/InternalEditorUtility.bindings.cs +++ b/Editor/Mono/InternalEditorUtility.bindings.cs @@ -131,6 +131,7 @@ private LoadFileAndForgetOperation(IntPtr ptr) : base(ptr) { } [NativeHeader("Runtime/Utilities/FileUtilities.h")] [NativeHeader("Runtime/Utilities/LaunchUtilities.h")] [NativeHeader("Runtime/Utilities/UnityConfiguration.h")] + [NativeHeader("Runtime/Utilities/UnityGitConfiguration.h")] public partial class InternalEditorUtility { public extern static bool isHumanControllingUs @@ -509,6 +510,9 @@ public static Version GetUnityVersion() [FreeFunction("UnityConfig::GetUnityBuildNumericRevision")] extern public static int GetUnityRevision(); + [FreeFunction("UnityConfig::GetUnityProductName")] + extern public static string GetUnityProductName(); + [FreeFunction("InternalEditorUtilityBindings::IsUnityBeta")] extern public static bool IsUnityBeta(); diff --git a/Editor/Mono/Modules/BeeBuildPostprocessor.cs b/Editor/Mono/Modules/BeeBuildPostprocessor.cs index 31bdd201da..c567bfe780 100644 --- a/Editor/Mono/Modules/BeeBuildPostprocessor.cs +++ b/Editor/Mono/Modules/BeeBuildPostprocessor.cs @@ -275,6 +275,8 @@ IEnumerable SplitArgs(string args) protected virtual string Il2CppLinkerFlagsFor(BuildPostProcessArgs args) => null; + protected virtual string Il2CppLinkerFlagsFileFor(BuildPostProcessArgs args) => null; + protected virtual string Il2CppDataRelativePath(BuildPostProcessArgs args) => "Data"; Il2CppConfig Il2CppConfigFor(BuildPostProcessArgs args) @@ -295,6 +297,7 @@ Il2CppConfig Il2CppConfigFor(BuildPostProcessArgs args) var toolchainPath = Il2CppToolchainPathFor(args); var compilerFlags = Il2CppCompilerFlagsFor(args); var linkerFlags = Il2CppLinkerFlagsFor(args); + var linkerFlagsFile = Il2CppLinkerFlagsFileFor(args); var relativeDataPath = Il2CppDataRelativePath(args); if (CrashReportingSettings.enabled) @@ -343,11 +346,12 @@ Il2CppConfig Il2CppConfigFor(BuildPostProcessArgs args) AllowDebugging = allowDebugging, CompilerFlags = compilerFlags, LinkerFlags = linkerFlags, + LinkerFlagsFile = linkerFlagsFile, SysRootPath = sysrootPath, ToolChainPath = toolchainPath, RelativeDataPath = relativeDataPath, ExtraTypes = extraTypesFile?.ToString(), - GenerateUsymFile = PlayerSettings.GetIl2CppStacktraceInformation(NamedBuildTarget.FromBuildTargetGroup(BuildPipeline.GetBuildTargetGroup(args.target))) == Il2CppStacktraceInformation.MethodFileLineNumber, + GenerateUsymFile = PlayerSettings.GetIl2CppStacktraceInformation(namedBuildTarget) == Il2CppStacktraceInformation.MethodFileLineNumber, UsymtoolPath = GetUsymtoolPath(), }; } diff --git a/Editor/Mono/Modules/DefaultBuildProfileExtension.cs b/Editor/Mono/Modules/DefaultBuildProfileExtension.cs index 2b751a187c..ac53748eaf 100644 --- a/Editor/Mono/Modules/DefaultBuildProfileExtension.cs +++ b/Editor/Mono/Modules/DefaultBuildProfileExtension.cs @@ -70,6 +70,10 @@ public virtual void CopyPlatformSettingsToBuildProfile(BuildProfilePlatformSetti { } + public virtual void CopyPlatformSettingsFromBuildProfile(BuildProfilePlatformSettingsBase platformSettings) + { + } + public virtual void OnDisable() { } @@ -441,7 +445,7 @@ public void ShowArrayBoundsChecksToggle() public virtual void ShowInternalPlatformBuildOptions() { } - + /// Helper method for rendering an IMGUI popup over an enum /// serialized property. /// diff --git a/Editor/Mono/Modules/PlatformSupportModule.cs b/Editor/Mono/Modules/PlatformSupportModule.cs index a6a891b0ff..30483726e4 100644 --- a/Editor/Mono/Modules/PlatformSupportModule.cs +++ b/Editor/Mono/Modules/PlatformSupportModule.cs @@ -390,6 +390,11 @@ VisualElement CreateSettingsGUI( /// void CopyPlatformSettingsToBuildProfile(BuildProfilePlatformSettingsBase platformSettingsBase); + /// + /// Copy platform settings from build profile to platform specific setting asset. + /// + void CopyPlatformSettingsFromBuildProfile(BuildProfilePlatformSettingsBase platformSettings); + void OnDisable(); } diff --git a/Editor/Mono/PlayerSettings.bindings.cs b/Editor/Mono/PlayerSettings.bindings.cs index 3817f6d6a0..3a155e7197 100644 --- a/Editor/Mono/PlayerSettings.bindings.cs +++ b/Editor/Mono/PlayerSettings.bindings.cs @@ -885,46 +885,6 @@ internal static extern string spritePackerPolicy set; } - internal static readonly char[] defineSplits = new[] { ';', ',', ' ' }; - - internal static string[] ConvertScriptingDefineStringToArray(string defines) - { - return defines.Split(defineSplits, StringSplitOptions.RemoveEmptyEntries); - } - - internal static string ConvertScriptingDefineArrayToString(string[] defines) - { - List list = new List(); - foreach (var define in defines) - { - string[] split = define.Split(' ', ';'); - - // Split each define element, since there can be multiple defines added - foreach (var item in split) - { - if (!string.IsNullOrEmpty(item)) - { - list.Add(item); - } - } - } - - // Remove duplicates - defines = list.Distinct().ToArray(); - - // Join all defines to one string - var joined = new StringBuilder(); - foreach (var define in defines) - { - if (joined.Length != 0) - joined.Append(';'); - - joined.Append(define); - } - - return joined.ToString(); - } - // TargetGroup no longer defines the entire build targets space. Now build targets are better // identified by a string key (wrapped into NamedBuildTarget), so all the following methods are being replaced. @@ -934,7 +894,7 @@ public static string GetScriptingDefineSymbolsForGroup(BuildTargetGroup targetGr [Obsolete("Use GetScriptingDefineSymbols(NamedBuildTarget buildTarget, out string[] defines) instead")] public static void GetScriptingDefineSymbolsForGroup(BuildTargetGroup targetGroup, out string[] defines) => - defines = ConvertScriptingDefineStringToArray(GetScriptingDefineSymbolsForGroup(targetGroup)); + defines = ScriptingDefinesHelper.ConvertScriptingDefineStringToArray(GetScriptingDefineSymbolsForGroup(targetGroup)); [Obsolete("Use SetScriptingDefineSymbols(NamedBuildTarget buildTarget, string defines) instead")] public static void SetScriptingDefineSymbolsForGroup(BuildTargetGroup targetGroup, string defines) => @@ -1037,13 +997,13 @@ public static void SetNormalMapEncoding(BuildTargetGroup platform, NormalMapEnco public static string GetScriptingDefineSymbols(NamedBuildTarget buildTarget) => GetScriptingDefineSymbolsInternal(buildTarget.TargetName); public static void GetScriptingDefineSymbols(NamedBuildTarget buildTarget, out string[] defines) => - defines = ConvertScriptingDefineStringToArray(GetScriptingDefineSymbols(buildTarget)); + defines = ScriptingDefinesHelper.ConvertScriptingDefineStringToArray(GetScriptingDefineSymbols(buildTarget)); // Set user-specified symbols for script compilation for the given build target group. public static void SetScriptingDefineSymbols(NamedBuildTarget buildTarget, string defines) { if (!string.IsNullOrEmpty(defines)) - defines = string.Join(";", ConvertScriptingDefineStringToArray(defines)); + defines = string.Join(";", ScriptingDefinesHelper.ConvertScriptingDefineStringToArray(defines)); SetScriptingDefineSymbolsInternal(buildTarget.TargetName, defines); } @@ -1053,7 +1013,7 @@ public static void SetScriptingDefineSymbols(NamedBuildTarget buildTarget, strin if (defines == null) throw new ArgumentNullException(nameof(defines)); - SetScriptingDefineSymbols(buildTarget, ConvertScriptingDefineArrayToString(defines)); + SetScriptingDefineSymbols(buildTarget, ScriptingDefinesHelper.ConvertScriptingDefineArrayToString(defines)); } [NativeThrows] diff --git a/Editor/Mono/PreferencesWindow/AssetPipelinePreferences.cs b/Editor/Mono/PreferencesWindow/AssetPipelinePreferences.cs index 907b7e5d7b..1d5aedfbc8 100644 --- a/Editor/Mono/PreferencesWindow/AssetPipelinePreferences.cs +++ b/Editor/Mono/PreferencesWindow/AssetPipelinePreferences.cs @@ -5,7 +5,6 @@ using UnityEngine; using System; using System.Collections.Generic; -using UnityEditor.Collaboration; using UnityEngine.UIElements; namespace UnityEditor @@ -22,7 +21,6 @@ internal class AssetPipelinePreferences : PreferencesProvider class Properties { public static readonly GUIContent autoRefresh = EditorGUIUtility.TrTextContent("Auto Refresh", "Automatically import changed assets."); - public static readonly GUIContent autoRefreshHelpBox = EditorGUIUtility.TrTextContent("Auto Refresh must be set when using Collaboration feature.", EditorGUIUtility.GetHelpIcon(MessageType.Warning)); public static readonly GUIContent desiredImportWorkerCountPctOfLogicalCPUs = EditorGUIUtility.TrTextContent("Import Worker Count %", "Desired asset import worker count for new projects in percentage of available logical CPU cores."); public static readonly GUIContent desiredImportWorkerCountPctOfLogicalCPUsLearnMore = new GUIContent("Learn more...", "Go to import worker documentation."); public static readonly GUIContent directoryMonitoring = EditorGUIUtility.TrTextContent("Directory Monitoring", "Monitor directories instead of scanning all project files to detect asset changes."); diff --git a/Editor/Mono/ProjectBrowser/SearchFilter.cs b/Editor/Mono/ProjectBrowser/SearchFilter.cs index d715e9c30e..73d52e5281 100644 --- a/Editor/Mono/ProjectBrowser/SearchFilter.cs +++ b/Editor/Mono/ProjectBrowser/SearchFilter.cs @@ -127,8 +127,6 @@ public State GetState() !IsNullOrEmpty(m_ReferencingInstanceIDs) || m_ImportLogFlags != ImportLogFlags.None; - - bool foldersActive = !IsNullOrEmpty(m_Folders); if (isSearchActive) @@ -188,6 +186,7 @@ public bool SetNewFilter(SearchFilter newFilter) m_Folders = newFilter.m_Folders; changed = true; } + if (newFilter.m_AssetLabels != m_AssetLabels) { m_AssetLabels = newFilter.m_AssetLabels; @@ -272,7 +271,6 @@ public override string ToString() if (m_AssetLabels != null && m_AssetLabels.Length > 0) result += "[Labels: " + m_AssetLabels[0] + "]"; - if (m_AssetBundleNames != null && m_AssetBundleNames.Length > 0) result += "[AssetBundleNames: " + m_AssetBundleNames[0] + "]"; diff --git a/Editor/Mono/SceneView/SceneViewMotion.cs b/Editor/Mono/SceneView/SceneViewMotion.cs index 895d016d6e..4210374fbe 100644 --- a/Editor/Mono/SceneView/SceneViewMotion.cs +++ b/Editor/Mono/SceneView/SceneViewMotion.cs @@ -77,7 +77,7 @@ static void RegisterShortcutContexts() => EditorApplication.delayCall += () => ShortcutIntegration.instance.contextManager.RegisterToolContext(s_CameraFlyModeContext); }; - internal abstract class SceneViewContext : IShortcutToolContext + internal abstract class SceneViewContext : IShortcutContext { public SceneView window => EditorWindow.focusedWindow as SceneView; public virtual bool active => ViewHasFocus; @@ -639,13 +639,16 @@ private void HandleKeyDown() void HandleScrollWheel(SceneView view, bool zoomTowardsCenter) { - var evt = Event.current; - float scrollDelta = evt.delta.magnitude * Mathf.Sign(Mathf.Min(evt.delta.x, evt.delta.y)); - + var evt = Event. current; + var scrollDelta = Event.current.delta.y; if (Tools.s_LockedViewTool == ViewTool.FPS) { - // On some OSs, macOS for example, holding Shift while scrolling is interpreted as horizontal scroll at the system level - // and that would cause the scroll delta to be set on the x coord instead of y. Therefore here we're taking the magnitude instead of specific component's value. + // On MacOS, scrolling with Shift down is interpreted as a horizontal scroll at the 0S level. + // On Window, due to UUM-43552 a change was done at the editor's win platform layer to mimic macOS behaviour and swap x/y deltas. + if ((evt.modifiers & EventModifiers.Shift) != 0 && + (Application.platform == RuntimePlatform.OSXEditor || Application.platform == RuntimePlatform.WindowsEditor)) + scrollDelta = Event.current.delta.x; + float scrollWheelDelta = scrollDelta * m_FPSScrollWheelMultiplier; view.cameraSettings.speedNormalized -= scrollWheelDelta; float cameraSettingsSpeed = view.cameraSettings.speed; diff --git a/Editor/Mono/ScriptingDefinesHelper.cs b/Editor/Mono/ScriptingDefinesHelper.cs new file mode 100644 index 0000000000..d7ebb6f29f --- /dev/null +++ b/Editor/Mono/ScriptingDefinesHelper.cs @@ -0,0 +1,52 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; +using System.Collections.Generic; + +namespace UnityEditor; + +internal static class ScriptingDefinesHelper +{ + private static readonly char[] DefineSeparators = { ';', ',', ' ' }; + + internal static string ConvertScriptingDefineArrayToString(string[] defines) + { + if (defines == null) + { + throw new ArgumentNullException(nameof(defines)); + } + + var flattenedDefines = new List(); + foreach (var define in defines) + { + flattenedDefines.AddRange(define.Split(DefineSeparators, StringSplitOptions.RemoveEmptyEntries)); + } + + var distinctDefines = new HashSet(); + foreach (var define in flattenedDefines) + { + distinctDefines.Add(define); + } + + return string.Join(";", distinctDefines); + } + + internal static string[] ConvertScriptingDefineStringToArray(string defines) + { + var splitDefines = string.IsNullOrEmpty(defines) + ? Array.Empty() + : defines.Split(DefineSeparators, StringSplitOptions.RemoveEmptyEntries); + + var distinctDefines = new HashSet(); + foreach (var define in splitDefines) + { + distinctDefines.Add(define); + } + + var distinctDefinesArray = new string[distinctDefines.Count]; + distinctDefines.CopyTo(distinctDefinesArray); + return distinctDefinesArray; + } +} diff --git a/Editor/Mono/SerializedObject.bindings.cs b/Editor/Mono/SerializedObject.bindings.cs index b396b134e0..45a53cae98 100644 --- a/Editor/Mono/SerializedObject.bindings.cs +++ b/Editor/Mono/SerializedObject.bindings.cs @@ -227,11 +227,9 @@ public extern int maxArraySizeForMultiEditing set; } - internal extern bool isValid - { - [NativeMethod("IsValid")] - get; - } + internal extern bool IsValid(); + + internal bool isValid => m_NativeObjectPtr != IntPtr.Zero && IsValid(); internal extern uint objectVersion { diff --git a/Editor/Mono/Tools/EditorToolCache.cs b/Editor/Mono/Tools/EditorToolCache.cs index a455381dd8..80d0d98f28 100644 --- a/Editor/Mono/Tools/EditorToolCache.cs +++ b/Editor/Mono/Tools/EditorToolCache.cs @@ -121,9 +121,12 @@ public UnityObject[] targets { if (additionalEditors == null) return inspector.targets; + List objects = new List(inspector.targets); - foreach (var insp in additionalEditors) - objects.AddRange(insp.targets); + foreach (var additionalInspector in additionalEditors) + foreach (var additionalTarget in additionalInspector.targets) + if (!objects.Contains(additionalTarget)) + objects.Add(additionalTarget); return objects.ToArray(); } } diff --git a/Editor/Mono/UIElements/Controls/CurveField.cs b/Editor/Mono/UIElements/Controls/CurveField.cs index 23513b7ec5..e656fe79ed 100644 --- a/Editor/Mono/UIElements/Controls/CurveField.cs +++ b/Editor/Mono/UIElements/Controls/CurveField.cs @@ -651,7 +651,7 @@ void DrawMesh() finalColor *= playModeTintColor; // Send the view zoom factor so that the antialias width do not grow when zooming in. - m_Mat.SetFloat("_ZoomFactor", scale * realWidth / CurveField.k_EdgeWidth * EditorGUIUtility.pixelsPerPoint); + m_Mat.SetFloat("_ZoomFactor", scale * realWidth / CurveField.k_EdgeWidth * scaledPixelsPerPoint); // Send the view zoom correction so that the vertex shader can scale the edge triangles when below m_MinWidth. m_Mat.SetFloat("_ZoomCorrection", realWidth / CurveField.k_EdgeWidth); diff --git a/Editor/Mono/UIElements/Inspector/EditorElement.cs b/Editor/Mono/UIElements/Inspector/EditorElement.cs index f5274d81f0..963d915c9d 100644 --- a/Editor/Mono/UIElements/Inspector/EditorElement.cs +++ b/Editor/Mono/UIElements/Inspector/EditorElement.cs @@ -214,6 +214,7 @@ public void ReinitCulled(int editorIndex, Editor[] editors) m_Header = m_Footer = null; m_EditorUsedInDecorators = null; m_DecoratorsElement = null; + m_IsCulled = true; Clear(); InitCulled(editors); return; @@ -228,6 +229,7 @@ public void Reinit(int editorIndex, Editor[] editors) { m_EditorIndex = editorIndex; m_EditorUsedInDecorators = null; + m_IsCulled = false; Clear(); Init(editors); return; diff --git a/Editor/Mono/UIElements/Inspector/InspectorElement.cs b/Editor/Mono/UIElements/Inspector/InspectorElement.cs index 0052bda663..9521c11472 100644 --- a/Editor/Mono/UIElements/Inspector/InspectorElement.cs +++ b/Editor/Mono/UIElements/Inspector/InspectorElement.cs @@ -331,7 +331,7 @@ internal InspectorElement(Editor editor, DefaultInspectorFramework defaultInspec void OnAttachToPanel(AttachToPanelEvent evt) { - if (boundObject != null && m_Editor == null) + if (boundObject != null && boundObject.isValid && m_Editor == null) { m_Rebind = true; this.Bind(boundObject); @@ -378,7 +378,7 @@ protected override void HandleEventBubbleUp(EventBase evt) } // Determine if we need to rebuild. This should only be done when our serialized object target changes or something forces us to rebuild (i.e. backend changing). - var shouldRebuildElements = m_Rebind || m_BoundObject != bindEvent.bindObject; + var shouldRebuildElements = bindEvent.bindObject != null && bindEvent.bindObject.isValid && (m_Rebind || m_BoundObject != bindEvent.bindObject); if (shouldRebuildElements) { diff --git a/Editor/Mono/WindowBackendManager.cs b/Editor/Mono/WindowBackendManager.cs index f828bd88e7..96de5a8463 100644 --- a/Editor/Mono/WindowBackendManager.cs +++ b/Editor/Mono/WindowBackendManager.cs @@ -51,6 +51,7 @@ internal interface IWindowBackend object visualTree { get; } void SizeChanged(); + void OnBackingScaleFactorChanged(); void EventInterestsChanged(); void ResetPanelRenderingOnAssetChangeChanged(); } diff --git a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs index 4213e626d7..7752668e10 100644 --- a/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs +++ b/Modules/AssetPipelineEditor/ImportSettings/ModelImporterRigEditor.cs @@ -5,6 +5,7 @@ using System; using UnityEngine; using System.Collections.Generic; +using System.IO; using Object = UnityEngine.Object; using UnityEditor.AssetImporters; using System.Linq; @@ -66,6 +67,8 @@ internal class ModelImporterRigEditor : BaseAssetImporterTabUI private ExposeTransformEditor m_ExposeTransformEditor; private SerializedObject m_AvatarSourceSerializedObject; + string[] m_ReferencedClips; + SerializedObject avatarSourceSerializedObject { get @@ -144,7 +147,7 @@ static class Styles public static GUIContent MinBoneWeight = EditorGUIUtility.TrTextContent("Min Bone Weight", "Bone weights smaller than this value are rejected. The remaining weights are scaled to add up to 1.0."); public static GUIContent OptimizeBones = EditorGUIUtility.TrTextContent("Strip Bones", "Only adds bones to SkinnedMeshRenderers that have skin weights assigned to them."); - public static GUIContent UpdateReferenceClips = EditorGUIUtility.TrTextContent("Update reference clips", "Click on this button to update all the @convention files referencing this file. Should set all these files to Copy From Other Avatar, set the source Avatar to this one and reimport all these files."); + public static GUIContent UpdateReferenceClips = EditorGUIUtility.TrTextContent("Update referenced clips", "Click on this button to update all the referenced clips matching this model. This will set all these clips to Copy From Other Avatar, set the source Avatar to this one and reimport all these files. See the documentation for EditorSettings.referenceClipsExactNaming for more details about how models are matched to referenced clips."); public static GUIContent ImportMessages = EditorGUIUtility.TrTextContent("Import Messages"); public static GUIContent ExtraExposedTransform = EditorGUIUtility.TrTextContent("Extra Transforms to Expose", "Select the list of transforms to expose in the optimized GameObject hierarchy."); @@ -177,14 +180,42 @@ internal override void OnEnable() UpdateBipedMappingReport(); - if (m_AnimationType.intValue == (int)ModelImporterAnimationType.Human && m_Avatar == null) + if (m_AnimationType.intValue == (int)ModelImporterAnimationType.Human) { - ResetAvatar(); + if (m_Avatar == null) + { + ResetAvatar(); + } + UpdateReferencedClips(); + ReferencedClipsPostProcessor.ReferencedClipsChanged += ReferencedClipsChanged; + } + } + + void ReferencedClipsChanged(List referencedClips) + { + if (referencedClips.Count == 0) + return; + + // If any of the passed referenced clip is located in the same folder as this model, + // then refresh our list of referenced clips + var modelImporter = target as ModelImporter; + if (modelImporter) + { + var modelDirectory = Path.GetDirectoryName(modelImporter.assetPath); + foreach (var referencedClip in referencedClips) + { + if (modelDirectory == Path.GetDirectoryName(referencedClip)) + { + UpdateReferencedClips(); + return; + } + } } } internal override void OnDisable() { + ReferencedClipsPostProcessor.ReferencedClipsChanged -= ReferencedClipsChanged; if (m_AvatarSourceSerializedObject != null) m_AvatarSourceSerializedObject.Dispose(); } @@ -521,19 +552,59 @@ Object ValidateAvatarSource(Object[] references, Type objType, SerializedPropert return references[0]; } - void ShowUpdateReferenceClip() + // We only populate the model's referenced clips for models using the Legacy animation type. + // Models using the Human animation type still need to be able to fetch their matching referenced clips + // and the editor needs to react when referenced clips are imported. This is done through this asset + // post-processor + class ReferencedClipsPostProcessor : AssetPostprocessor { - if (targets.Length > 1 || m_AvatarSetup.intValue == (int)ModelImporterAvatarSetup.CopyFromOther || !m_Avatar || !m_Avatar.isValid) - return; + public static event Action> ReferencedClipsChanged; + + static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths, bool didDomainReload) + { + if (ReferencedClipsChanged == null) + return; + + List referencedClips = new(); + foreach (var asset in importedAssets) + if (asset.Contains('@')) + referencedClips.Add(asset); + foreach (var asset in deletedAssets) + if (asset.Contains('@')) + referencedClips.Add(asset); + foreach (var asset in movedAssets) + if (asset.Contains('@')) + referencedClips.Add(asset); + foreach (var asset in movedFromAssetPaths) + if (asset.Contains('@')) + referencedClips.Add(asset); + + ReferencedClipsChanged(referencedClips); + } + } - string[] paths = new string[0]; + void UpdateReferencedClips() + { ModelImporter importer = target as ModelImporter; - if (importer.referencedClips.Length > 0) + if (importer != null) + m_ReferencedClips = ModelImporter.GetReferencedClipsForModelPath(importer.assetPath); + } + void ShowUpdateReferenceClip() + { + if (targets.Length > 1 + || m_AvatarSetup.intValue == (int)ModelImporterAvatarSetup.CopyFromOther + || !m_Avatar + || !m_Avatar.isValid + || animationType != ModelImporterAnimationType.Human + ) { - foreach (string clipGUID in importer.referencedClips) - ArrayUtility.Add(ref paths, AssetDatabase.GUIDToAssetPath(clipGUID)); + return; } + string[] paths = new string[m_ReferencedClips.Length]; + for (var i = 0; i < m_ReferencedClips.Length; i++) + paths[i] = AssetDatabase.GUIDToAssetPath(m_ReferencedClips[i]); + // Show only button if some clip reference this avatar. if (paths.Length > 0 && GUILayout.Button(Styles.UpdateReferenceClips, GUILayout.Width(150))) { @@ -649,7 +720,7 @@ public override void OnInspectorGUI() } } } - + if (importRigErrors.Length > 0 || importRigWarnings.Length > 0) { EditorGUILayout.Space(); diff --git a/Modules/AssetPipelineEditor/Public/ModelImporting/ModelImporter.bindings.cs b/Modules/AssetPipelineEditor/Public/ModelImporting/ModelImporter.bindings.cs index 81a3322ea2..9d667f3126 100644 --- a/Modules/AssetPipelineEditor/Public/ModelImporting/ModelImporter.bindings.cs +++ b/Modules/AssetPipelineEditor/Public/ModelImporting/ModelImporter.bindings.cs @@ -667,6 +667,13 @@ public string[] referencedClips [FreeFunction("ModelImporterBindings::GetReferencedClips")] private extern static string[] INTERNAL_GetReferencedClips(ModelImporter self); + public static string[] GetReferencedClipsForModelPath(string modelPath) + { + return INTERNAL_GetReferencedClipsForModelPath(modelPath); + } + [FreeFunction("ModelImporterBindings::GetReferencedClipsForModelPath")] + private extern static string[] INTERNAL_GetReferencedClipsForModelPath(string modelPath); + public extern bool isReadable { get; diff --git a/Modules/BuildProfileEditor/BuildProfileWindow.cs b/Modules/BuildProfileEditor/BuildProfileWindow.cs index 880ce89c1d..af1dd4c799 100644 --- a/Modules/BuildProfileEditor/BuildProfileWindow.cs +++ b/Modules/BuildProfileEditor/BuildProfileWindow.cs @@ -337,7 +337,7 @@ void RepaintAdditionActionsDropdown() if (action.state != ActionState.Enabled) continue; - if(firstEnabledIndex < 0) + if (firstEnabledIndex < 0) firstEnabledIndex = i; else menu.AddItem(new GUIContent(action.displayName), action.isOn, () => action.callback()); @@ -382,7 +382,7 @@ void OnBuildProfileOrClassicPlatformSelected(IEnumerable selectedItems) // Rebuild the BuildProfile inspector, targeting the newly selected BuildProfile. DestroyImmediate(buildProfileEditor); - buildProfileEditor = (BuildProfileEditor) Editor.CreateEditor(profile, typeof(BuildProfileEditor)); + buildProfileEditor = (BuildProfileEditor)Editor.CreateEditor(profile, typeof(BuildProfileEditor)); buildProfileEditor.parentState = m_WindowState; buildProfileEditor.parent = this; m_BuildProfileInspectorElement.Clear(); @@ -500,8 +500,7 @@ void UpdateFormButtonState(BuildProfile profile) } else { - m_WindowState.activateAction = (profile.platformBuildProfile != null) - ? ActionState.Enabled : ActionState.Hidden; + m_WindowState.activateAction = profile.CanBuildLocally() ? ActionState.Enabled : ActionState.Hidden; m_WindowState.buildAction = ActionState.Hidden; m_WindowState.buildAndRunAction = ActionState.Hidden; m_WindowState.Refresh(); @@ -580,7 +579,7 @@ void CreateBuildProfileListView(ListView target, IList itemSource, if (!BuildProfileContext.IsClassicPlatformProfile(profile)) { - editableBuildProfileLabel.tooltip = AssetDatabase.GetAssetPath(profile); + editableBuildProfileLabel.tooltip = AssetDatabase.GetAssetPath(profile); } }; diff --git a/Modules/HierarchyCore/Managed/HierarchyNodeTypeHandlerBase.cs b/Modules/HierarchyCore/Managed/HierarchyNodeTypeHandlerBase.cs index 3c6e8a3ca4..cb8b6158ba 100644 --- a/Modules/HierarchyCore/Managed/HierarchyNodeTypeHandlerBase.cs +++ b/Modules/HierarchyCore/Managed/HierarchyNodeTypeHandlerBase.cs @@ -99,19 +99,6 @@ public virtual HierarchyNodeFlags GetDefaultNodeFlags(in HierarchyNode node, Hie return defaultFlags; } - /// - /// Callback that determines if pending changes from a registered node type handler need to be applied to the hierarchy. When the hierarchy is updated, `ChangesPending` is called on all registered node ype handlers. If they return true, then `IntegrateChanges` is called on them. If they return false, then `IntegrateChanges` is not called on them. - /// - /// if changes are pending, otherwise. - protected virtual bool ChangesPending() => false; - - /// - /// Callback that determines if changes from an update need to be integrated into the hierarchy. `IntegrateChanges` is called after returns . When the hierarchy is updated, `ChangesPending` is called on all registered node ype handlers. If they return true, then `IntegrateChanges` is called on them. If they return false, then `IntegrateChanges` is not called on them. - /// - /// A hierarchy command list that can modify the hierarchy. - /// if more invocations are needed to complete integrating changes, and if the handler is done integrating changes. - protected virtual bool IntegrateChanges(HierarchyCommandList cmdList) => false; - /// /// Called when a new search query begins. /// @@ -187,11 +174,13 @@ static bool InvokeTryGetNodeType(Type type, out int nodeType) [UsedByNativeCode, RequiredMember] static HierarchyNodeFlags InvokeGetDefaultNodeFlags(IntPtr ptr, in HierarchyNode node, HierarchyNodeFlags defaultFlags) => GetHandlerFromPtr(ptr).GetDefaultNodeFlags(in node, defaultFlags); +#pragma warning disable 618 // Remove this pragma once the corresponding public APIs below are removed [UsedByNativeCode, RequiredMember] static bool InvokeChangesPending(IntPtr ptr) => GetHandlerFromPtr(ptr).ChangesPending(); [UsedByNativeCode, RequiredMember] static bool InvokeIntegrateChanges(IntPtr ptr, HierarchyCommandList cmdList) => GetHandlerFromPtr(ptr).IntegrateChanges(cmdList); +#pragma warning restore 618 [UsedByNativeCode, RequiredMember] static bool InvokeSearchMatch(IntPtr ptr, in HierarchyNode node) => GetHandlerFromPtr(ptr).SearchMatch(in node); @@ -199,5 +188,22 @@ static bool InvokeTryGetNodeType(Type type, out int nodeType) [UsedByNativeCode, RequiredMember] static void InvokeSearchEnd(IntPtr ptr) => GetHandlerFromPtr(ptr).SearchEnd(); #endregion + + #region Obsolete public APIs to remove in 2024 + /// + /// Callback that determines if pending changes from a registered node type handler need to be applied to the hierarchy. When the hierarchy is updated, `ChangesPending` is called on all registered node ype handlers. If they return true, then `IntegrateChanges` is called on them. If they return false, then `IntegrateChanges` is not called on them. + /// + /// if changes are pending, otherwise. + [Obsolete("ChangesPending is obsolete, it is replaced by adding commands into the hierarchy node type handler's CommandList.", false)] + protected virtual bool ChangesPending() => false; + + /// + /// Callback that determines if changes from an update need to be integrated into the hierarchy. `IntegrateChanges` is called after returns . When the hierarchy is updated, `ChangesPending` is called on all registered node ype handlers. If they return true, then `IntegrateChanges` is called on them. If they return false, then `IntegrateChanges` is not called on them. + /// + /// A hierarchy command list that can modify the hierarchy. + /// if more invocations are needed to complete integrating changes, and if the handler is done integrating changes. + [Obsolete("IntegrateChanges is obsolete, it is replaced by adding commands into the hierarchy node type handler's CommandList.", false)] + protected virtual bool IntegrateChanges(HierarchyCommandList cmdList) => false; + #endregion } } diff --git a/Modules/HierarchyCore/ScriptBindings/HierarchyViewModel.bindings.cs b/Modules/HierarchyCore/ScriptBindings/HierarchyViewModel.bindings.cs index ac8592e38e..f7f38ea4ce 100644 --- a/Modules/HierarchyCore/ScriptBindings/HierarchyViewModel.bindings.cs +++ b/Modules/HierarchyCore/ScriptBindings/HierarchyViewModel.bindings.cs @@ -848,7 +848,7 @@ internal void SearchBegin() [FreeFunction("HierarchyViewModelBindings::GetIndicesWithoutAnyFlagsSpan", HasExplicitThis = true, IsThreadSafe = true, ThrowsException = true)] extern int GetIndicesWithoutAnyFlagsSpan(HierarchyNodeFlags flags, Span outIndices); - #region Obsolete public APIs to remove in 2024 / Unity 7 + #region Obsolete public APIs to remove in 2024 [Obsolete("HasFlags is obsolete, please use HasAllFlags or HasAnyFlags instead", false)] [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public bool HasFlags(HierarchyNodeFlags flags) => HasAllFlagsAny(flags); diff --git a/Modules/IMGUI/GUIUtility.bindings.cs b/Modules/IMGUI/GUIUtility.bindings.cs index 969c9cdc84..ccb2839340 100644 --- a/Modules/IMGUI/GUIUtility.bindings.cs +++ b/Modules/IMGUI/GUIUtility.bindings.cs @@ -24,6 +24,9 @@ internal static extern float pixelsPerPoint [VisibleToOtherModules("UnityEngine.UIElementsModule")] get; + + [VisibleToOtherModules("UnityEngine.UIElementsModule")] + set; } [NativeProperty("GetGUIState().m_OnGUIDepth", true, TargetType.Field)] diff --git a/Modules/PackageManagerUI/Editor/External/EditorGameServiceExtension.cs b/Modules/PackageManagerUI/Editor/External/EditorGameServiceExtension.cs index 8de4b1e3a1..80022c2a61 100644 --- a/Modules/PackageManagerUI/Editor/External/EditorGameServiceExtension.cs +++ b/Modules/PackageManagerUI/Editor/External/EditorGameServiceExtension.cs @@ -51,15 +51,16 @@ internal static bool FilterServicesPackage(IPackage package) internal static string GetServicesPackageGroupName(IPackage package) { - var packageGameServiceField = GetLatestEditorGameServiceField(package); - var hasServiceGroupingId = HasDynamicServiceGroupId(packageGameServiceField); - if (hasServiceGroupingId) - { - return GetDynamicServiceGroupId(packageGameServiceField); - } - + // override order: editor s_GroupMap first, then service package upm groupId field if exist if (s_GroupMap == null || string.IsNullOrWhiteSpace(package.name) || !s_GroupMap.ContainsKey(package.name)) { + var packageGameServiceField = GetLatestEditorGameServiceField(package); + var hasServiceGroupingId = HasDynamicServiceGroupId(packageGameServiceField); + if (hasServiceGroupingId) + { + return GetDynamicServiceGroupId(packageGameServiceField); + } + return string.Empty; } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs b/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs index 30eebfbe77..654b3a9741 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs @@ -177,7 +177,7 @@ internal override void OnHeaderControlsGUI() var previousEnabled = GUI.enabled; PackageManifest manifest = null; - if (m_Package?.state == PackageState.InDevelopment && (m_Version?.isInstalled ?? false)) + if (m_Version?.HasTag(PackageTag.Custom) ?? false) { var packageInfo = m_UpmCache.GetBestMatchPackageInfo(m_Version.name, m_Version.isInstalled, m_Version.versionString); manifest = m_AssetDatabase.LoadAssetAtPath($"{packageInfo.assetPath}/package.json"); diff --git a/Modules/ProfilerEditor/ProfilerWindow/Bottlenecks/Details/Data/BottlenecksDetailsViewModelBuilder.cs b/Modules/ProfilerEditor/ProfilerWindow/Bottlenecks/Details/Data/BottlenecksDetailsViewModelBuilder.cs index da19f7f196..6c6784f9e7 100644 --- a/Modules/ProfilerEditor/ProfilerWindow/Bottlenecks/Details/Data/BottlenecksDetailsViewModelBuilder.cs +++ b/Modules/ProfilerEditor/ProfilerWindow/Bottlenecks/Details/Data/BottlenecksDetailsViewModelBuilder.cs @@ -20,8 +20,8 @@ class BottlenecksDetailsViewModelBuilder static readonly string k_NotBoundTitleFormat = $"The {{0}} within your target frame time in this frame."; static readonly string k_CpuBoundExplanationFormat = $"In this frame the CPU spent the majority of its time executing on the {{0}} thread. Therefore, you should initially focus on this to begin your investigation."; static readonly string k_SuggestionTitle = $"How to inspect further:"; - static readonly string k_CpuBoundSuggestion = $"To optimize your game’s CPU utilization, begin by using the CPU module’s Timeline view to see which systems contributed the most to this time spent executing on the CPU.\n\nYou might also consider using the Profile Analyzer to perform a deeper statistical analysis and/or to compare Profiler captures after you have made some optimizations."; - static readonly string k_GpuBoundSuggestion = $"To optimize your game’s GPU utilization, use the Frame Debugger to step through individual draw calls and see in detail how the scene is constructed from its graphical elements.\n\nYou might also consider using a native GPU profiler for the platform you are targeting. Please see the Unity documentation for more information."; + static readonly string k_CpuBoundSuggestion = $"To optimize your game’s CPU utilization, begin by using the CPU module’s Timeline view to see which systems contributed the most to this time spent executing on the CPU.\n\nYou might also consider using the Profile Analyzer to perform a deeper statistical analysis and/or to compare Profiler captures after you have made some optimizations."; + static readonly string k_GpuBoundSuggestion = $"To optimize your game’s GPU utilization, use the Frame Debugger to step through individual draw calls and see in detail how the scene is constructed from its graphical elements.\n\nYou might also consider using a native GPU profiler for the platform you are targeting. Please see the Unity documentation for more information."; readonly IProfilerCaptureDataService m_DataService; diff --git a/Modules/ProfilerEditor/ProfilerWindow/ProfilerWindow.cs b/Modules/ProfilerEditor/ProfilerWindow/ProfilerWindow.cs index 1eea46191b..4417f5a377 100644 --- a/Modules/ProfilerEditor/ProfilerWindow/ProfilerWindow.cs +++ b/Modules/ProfilerEditor/ProfilerWindow/ProfilerWindow.cs @@ -900,7 +900,7 @@ static void RecordToggle() if (ProfilerDriver.enabled) Debug.LogFormat(LogType.Log, LogOption.NoStacktrace, null, $"Recording {GetRecordingStateName(connectionName)} has started..."); else - Debug.LogFormat(LogType.Log, LogOption.NoStacktrace, null, "Recording has ended.\r\nClick here to open the profiler window."); + Debug.LogFormat(LogType.Log, LogOption.NoStacktrace, null, $"Recording has ended.\r\nClick here to open the profiler window."); } } } diff --git a/Modules/Properties/Runtime/PropertyBags/Internal/PropertyBagStore.cs b/Modules/Properties/Runtime/PropertyBags/Internal/PropertyBagStore.cs index c0f838e435..26868f6d2a 100644 --- a/Modules/Properties/Runtime/PropertyBags/Internal/PropertyBagStore.cs +++ b/Modules/Properties/Runtime/PropertyBags/Internal/PropertyBagStore.cs @@ -27,8 +27,6 @@ interface IPropertyBagRegister /// static class PropertyBagStore { - private static ConcurrentQueue s_Handles = new ConcurrentQueue(); - internal struct TypedStore { public static IPropertyBag PropertyBag; @@ -236,25 +234,5 @@ internal static bool TryGetPropertyBagForValue(ref TValue value, out IPr propertyBag = GetPropertyBag(value.GetType()); return null != propertyBag; } - - internal static void AddJobToWaitQueue(JobHandle handle) - { - var handles = s_Handles ??= new ConcurrentQueue(); - handles.Enqueue(handle); - } - - static void WaitForJobs() - { - if (s_Handles is not {Count: > 0}) - return; - - foreach (var handle in s_Handles) - { - if (!handle.IsCompleted) - handle.Complete(); - } - - s_Handles.Clear(); - } } } diff --git a/Modules/Properties/Runtime/PropertyBags/PropertyBag.cs b/Modules/Properties/Runtime/PropertyBags/PropertyBag.cs index 14d037bf11..c35168bb09 100644 --- a/Modules/Properties/Runtime/PropertyBags/PropertyBag.cs +++ b/Modules/Properties/Runtime/PropertyBags/PropertyBag.cs @@ -79,18 +79,6 @@ public static IEnumerable GetAllTypesWithAPropertyBag() { return PropertyBagStore.AllTypes; } - - /// - /// Allows for to be registered on a background thread while ensuring that the jobs will be completed before - /// the next call to . - /// - /// The job handle to wait on. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [VisibleToOtherModules("UnityEditor.PropertiesModule")] - internal static void AddJobToWaitQueue(JobHandle handle) - { - PropertyBagStore.AddJobToWaitQueue(handle); - } } /// diff --git a/Modules/PropertiesEditor/Module/PropertiesEditorInitialization.cs b/Modules/PropertiesEditor/Module/PropertiesEditorInitialization.cs index 46a6e1b3f9..6c4db7d8cf 100644 --- a/Modules/PropertiesEditor/Module/PropertiesEditorInitialization.cs +++ b/Modules/PropertiesEditor/Module/PropertiesEditorInitialization.cs @@ -24,7 +24,7 @@ public static void InitializePropertiesEditor() if (s_Initialized) return; s_InitializeJobHandle = new InitializePropertiesJob().Schedule(); - PropertyBag.AddJobToWaitQueue(s_InitializeJobHandle); + JobHandle.ScheduleBatchedJobs(); s_Initialized = true; } diff --git a/Modules/ShortcutManagerEditor/IShortcutContext.cs b/Modules/ShortcutManagerEditor/IShortcutContext.cs index 566dbcf384..d636774bab 100644 --- a/Modules/ShortcutManagerEditor/IShortcutContext.cs +++ b/Modules/ShortcutManagerEditor/IShortcutContext.cs @@ -6,9 +6,6 @@ namespace UnityEditor.ShortcutManagement { - // shim for packages who access this through internal bridge - interface IShortcutToolContext : IShortcutContext { } - abstract class ClutchShortcutContext : IShortcutContext { public bool active { get; internal set; } diff --git a/Modules/Terrain/Public/TerrainData.GPUCopy.cs b/Modules/Terrain/Public/TerrainData.GPUCopy.cs index 9e9dee65d4..9e84d85001 100644 --- a/Modules/Terrain/Public/TerrainData.GPUCopy.cs +++ b/Modules/Terrain/Public/TerrainData.GPUCopy.cs @@ -141,10 +141,7 @@ public void CopyActiveRenderTextureToTexture(string textureName, int textureInde } else { - if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Metal || !SystemInfo.graphicsUVStartsAtTop) - dstTexture.ReadPixels(new Rect(sourceRect.x, sourceRect.y, sourceRect.width, sourceRect.height), dest.x, dest.y); - else - dstTexture.ReadPixels(new Rect(sourceRect.x, source.height - sourceRect.yMax, sourceRect.width, sourceRect.height), dest.x, dest.y); + dstTexture.ReadPixels(new Rect(sourceRect.x, sourceRect.y, sourceRect.width, sourceRect.height), dest.x, dest.y); dstTexture.Apply(true); // TODO: Check if the texture is previously marked dirty? diff --git a/Modules/TextCoreTextEngine/Managed/TextHandle.cs b/Modules/TextCoreTextEngine/Managed/TextHandle.cs index e922379f49..1a7e91e0fc 100644 --- a/Modules/TextCoreTextEngine/Managed/TextHandle.cs +++ b/Modules/TextCoreTextEngine/Managed/TextHandle.cs @@ -828,9 +828,15 @@ internal TextInfo Update() if (!IsDirty(settings)) return textInfo; + if (settings.fontAsset == null || settings.fontAsset.characterLookupTable == null) + { + Debug.LogWarning("Can't Generate Mesh, No Font Asset has been assigned."); + return textInfo; + } + generator.GenerateText(settings, textInfo); - m_IsEllided = generator.isTextTruncated; - return textInfo; + m_IsEllided = generator.isTextTruncated; + return textInfo; } [VisibleToOtherModules("UnityEngine.IMGUIModule", "UnityEngine.UIElementsModule")] diff --git a/Modules/TextCoreTextEngineEditor/Managed/FontAssetCreatorWindow.cs b/Modules/TextCoreTextEngineEditor/Managed/FontAssetCreatorWindow.cs index 6cb9332d0d..9a39cd7e8f 100644 --- a/Modules/TextCoreTextEngineEditor/Managed/FontAssetCreatorWindow.cs +++ b/Modules/TextCoreTextEngineEditor/Managed/FontAssetCreatorWindow.cs @@ -737,7 +737,12 @@ void DrawControls() // Get list of characters that need to be packed and rendered to the atlas texture. if (m_CharacterSetSelectionMode == 7 || m_CharacterSetSelectionMode == 8) { - List char_List = new List(); + // Ensure these characters are always added + List char_List = new List() + { + 9, // Space + 95 // Underline + }; for (int i = 0; i < m_CharacterSequence.Length; i++) { diff --git a/Modules/UIBuilder/Editor/Builder/BuilderSelection.cs b/Modules/UIBuilder/Editor/Builder/BuilderSelection.cs index 87e3be9604..254a6af7b1 100644 --- a/Modules/UIBuilder/Editor/Builder/BuilderSelection.cs +++ b/Modules/UIBuilder/Editor/Builder/BuilderSelection.cs @@ -87,7 +87,8 @@ public BuilderSelectionType selectionType if (selectedElement.GetVisualElementAsset() == null) { if (selectedElement.HasProperty(VisualTreeAsset.LinkedVEAInTemplatePropertyName) - && BuilderAssetUtilities.GetVisualElementRootTemplate(selectedElement) != null) + && BuilderAssetUtilities.GetVisualElementRootTemplate(selectedElement) != null + && !BuilderAssetUtilities.HasDynamicallyCreatedTemplateAncestor(selectedElement)) { return BuilderSelectionType.ElementInTemplateInstance; } diff --git a/Modules/UIBuilder/Editor/Builder/Utilities/BuilderAssetUtilities.cs b/Modules/UIBuilder/Editor/Builder/Utilities/BuilderAssetUtilities.cs index ec021bbd9c..6bfaf6802f 100644 --- a/Modules/UIBuilder/Editor/Builder/Utilities/BuilderAssetUtilities.cs +++ b/Modules/UIBuilder/Editor/Builder/Utilities/BuilderAssetUtilities.cs @@ -576,13 +576,14 @@ public static TemplateContainer GetVisualElementRootTemplate(VisualElement visua while (parent != null) { - if (parent is TemplateContainer templateContainer) + if (parent is TemplateContainer templateContainer && templateContainer.GetVisualElementAsset() != null) { - if (templateContainer.GetVisualElementAsset() != null) - { - templateContainerParent = templateContainer; - } + templateContainerParent = templateContainer; + break; + } + if (BuilderSharedStyles.IsDocumentElement(parent)) + { break; } @@ -592,6 +593,29 @@ public static TemplateContainer GetVisualElementRootTemplate(VisualElement visua return templateContainerParent; } + public static bool HasDynamicallyCreatedTemplateAncestor(VisualElement visualElement) + { + var parent = visualElement.parent; + while (parent != null) + { + if (BuilderSharedStyles.IsDocumentElement(parent)) + { + return false; + } + + if (parent is TemplateContainer + && !parent.HasProperty(VisualTreeAsset.LinkedVEAInTemplatePropertyName) + && parent.GetVisualElementAsset() == null) + { + return true; + } + + parent = parent.parent; + } + + return false; + } + public static bool HasAttributeOverrideInRootTemplate(VisualElement visualElement, string attributeName) { var templateContainer = GetVisualElementRootTemplate(visualElement); diff --git a/Modules/UIBuilder/Editor/Builder/Viewport/BuilderViewport.cs b/Modules/UIBuilder/Editor/Builder/Viewport/BuilderViewport.cs index f2791a870b..6a3dc1a2ca 100644 --- a/Modules/UIBuilder/Editor/Builder/Viewport/BuilderViewport.cs +++ b/Modules/UIBuilder/Editor/Builder/Viewport/BuilderViewport.cs @@ -387,6 +387,9 @@ public void FitViewport(VisualElement target = null) var targetOffset = target == null ? Vector2.zero : m_Canvas.worldBound.min - target.worldBound.min; + // Adjust the offset in case the canvas is not at the origin. + targetOffset -= m_Canvas.localBound.position; + // Scale the target zoom targetOffset /= zoomScale / targetZoom; diff --git a/Modules/UIElements/Core/Collections/Controllers/BaseTreeViewController.cs b/Modules/UIElements/Core/Collections/Controllers/BaseTreeViewController.cs index 109f9c6de1..6f49b5244e 100644 --- a/Modules/UIElements/Core/Collections/Controllers/BaseTreeViewController.cs +++ b/Modules/UIElements/Core/Collections/Controllers/BaseTreeViewController.cs @@ -85,6 +85,8 @@ public abstract class BaseTreeViewController : CollectionViewController /// protected BaseTreeView baseTreeView => view as BaseTreeView; + internal event Action itemExpandedChanged; + /// /// Constructor for a BaseTreeViewController /// @@ -379,10 +381,21 @@ private void OnItemPointerUp(PointerUpEvent evt) UpdateHierarchy(); baseTreeView.RefreshItems(); + RaiseItemExpandedChanged(GetIdForIndex(index), !wasExpanded, true); evt.StopPropagation(); } + private void RaiseItemExpandedChanged(int id, bool isExpanded, bool isAppliedToAllChildren) + { + itemExpandedChanged?.Invoke(new TreeViewExpansionChangedArgs + { + id = id, + isExpanded = isExpanded, + isAppliedToAllChildren = isAppliedToAllChildren + }); + } + private void OnToggleValueChanged(ChangeEvent evt) { var toggle = evt.target as Toggle; @@ -664,6 +677,7 @@ public void ExpandAll() } baseTreeView.RefreshItems(); + RaiseItemExpandedChanged(-1, true, true); } /// @@ -681,6 +695,7 @@ public void CollapseAll() } baseTreeView.RefreshItems(); + RaiseItemExpandedChanged(-1, false, true); } // Once we update the TreeView to be 100% Hierarchy, we can replace ExpandItemByIndex with this method. Or, we @@ -718,6 +733,8 @@ void ExpandItemByNode(in HierarchyNode node, bool expandAllChildren, bool refres if (refresh) baseTreeView.RefreshItems(); + + RaiseItemExpandedChanged(id, true, expandAllChildren); } // Once we update the TreeView to be 100% Hierarchy, we can replace CollapseItemByIndex with this method. Or, we @@ -747,6 +764,8 @@ void CollapseItemByNode(in HierarchyNode node, bool collapseAllChildren, bool re if (refresh) baseTreeView.RefreshItems(); + + RaiseItemExpandedChanged(id, false, collapseAllChildren); } // Helps to determine which expandedItemsIds set to use (the serialized or the view model one). diff --git a/Modules/UIElements/Core/Collections/Virtualization/DynamicHeightVirtualizationController.cs b/Modules/UIElements/Core/Collections/Virtualization/DynamicHeightVirtualizationController.cs index 26912b2a62..73187a0709 100644 --- a/Modules/UIElements/Core/Collections/Virtualization/DynamicHeightVirtualizationController.cs +++ b/Modules/UIElements/Core/Collections/Virtualization/DynamicHeightVirtualizationController.cs @@ -540,7 +540,7 @@ void Fill() { if (contentOffset >= viewportMaxOffset) break; - + contentOffset += GetExpectedItemHeight(i); var item = m_ActiveItems[activeIndex++]; @@ -580,7 +580,7 @@ void Fill() if (firstVisiblePadding < serializedData.scrollOffset.y) break; } - + m_ActiveItems.InsertRange(0, inserting); m_ScrollInsertionList.Clear(); } @@ -635,7 +635,7 @@ void ApplyScrollViewUpdate(bool dimensionsOnly = false) CycleItems(anchoredIndex); ScheduleFill(); } - + firstVisibleIndex = anchoredIndex; itemOffset = anchorOffset; } @@ -749,7 +749,7 @@ void ScheduleFill() m_ScheduledItem.Pause(); m_ScheduledItem.Resume(); } - + void ScheduleScroll() { if (m_ScrollScheduledItem == null) @@ -832,19 +832,39 @@ float GetContentHeightForIndex(int lastIndex) if (lastIndex < 0) return 0; - if (m_ContentHeightCache.TryGetValue(lastIndex, out var height)) + var draggedIndex = GetDraggedIndex(); + + float GetContentHeightFromCachedHeight(int index, in ContentHeightCacheInfo heightInfo) { // Make sure we don't include the dragged item height. - var draggedIndex = GetDraggedIndex(); - if (draggedIndex >= 0 && lastIndex >= draggedIndex) + if (draggedIndex >= 0 && index >= draggedIndex) + { + return heightInfo.sum + (index - heightInfo.count + 1) * defaultExpectedHeight - m_DraggedItem.rootElement.layout.height; + } + + return heightInfo.sum + (index - heightInfo.count + 1) * defaultExpectedHeight; + } + + // We can skip a lot of work when there is a big jump past the last known cached index. We can use the default + // expected height for anything past that, without the need to iterate through the indices. + if (m_HighestCachedIndex <= lastIndex && m_ContentHeightCache.TryGetValue(m_HighestCachedIndex, out var highestHeightInfo)) + { + return GetContentHeightFromCachedHeight(lastIndex, highestHeightInfo); + } + + // Accumulate height down the indices until we find a node that has been cached. + var totalHeight = 0f; + for (var i = lastIndex; i >= 0; i--) + { + if (m_ContentHeightCache.TryGetValue(i, out var heightInfo)) { - return height.sum + (lastIndex - height.count + 1) * defaultExpectedHeight - m_DraggedItem.rootElement.layout.height; + return totalHeight + GetContentHeightFromCachedHeight(i, heightInfo); } - return height.sum + (lastIndex - height.count + 1) * defaultExpectedHeight; + totalHeight += draggedIndex == i ? 0 : defaultExpectedHeight; } - return GetContentHeightForIndex(lastIndex - 1) + GetExpectedItemHeight(lastIndex); + return totalHeight; } ContentHeightCacheInfo GetCachedContentHeight(int index) diff --git a/Modules/UIElements/Core/Controls/BaseListView.cs b/Modules/UIElements/Core/Controls/BaseListView.cs index 6226e07e83..7fa276379a 100644 --- a/Modules/UIElements/Core/Controls/BaseListView.cs +++ b/Modules/UIElements/Core/Controls/BaseListView.cs @@ -1217,5 +1217,28 @@ private protected override void PostRefresh() UpdateListViewLabel(); base.PostRefresh(); } + + private protected override bool HandleItemNavigation(bool moveIn, bool altPressed) + { + var hasChanges = false; + + foreach (var index in selectedIndices) + { + foreach (var reusableCollectionItem in activeItems) + { + if (reusableCollectionItem.index == index && GetProperty(internalBindingKey) != null) + { + var foldout = reusableCollectionItem.bindableElement.Q(); + if (foldout != null) + { + foldout.value = moveIn; + hasChanges = true; + } + } + } + } + + return hasChanges; + } } } diff --git a/Modules/UIElements/Core/Controls/BaseTreeView.cs b/Modules/UIElements/Core/Controls/BaseTreeView.cs index 07bf1b169c..c9ed845bac 100644 --- a/Modules/UIElements/Core/Controls/BaseTreeView.cs +++ b/Modules/UIElements/Core/Controls/BaseTreeView.cs @@ -13,6 +13,27 @@ namespace UnityEngine.UIElements { + /// + /// A data structure for the tree view item expansion event. + /// + public class TreeViewExpansionChangedArgs + { + /// + /// The id of the item being expanded or collapsed. Returns -1 when expandAll() or collapseAll() is being called. + /// + public int id { get; set; } + + /// + /// Indicates whether the item is expanded (true) or collapsed (false). + /// + public bool isExpanded { get; set; } + + /// + /// Indicates whether the expandAllChildren or collapsedAllChildren is applied when expanding the item. + /// + public bool isAppliedToAllChildren { get; set; } + } + /// /// Base class for a tree view, a vertically scrollable area that links to, and displays, a list of items organized in a tree. /// @@ -130,6 +151,14 @@ public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext internal set => GetOrCreateViewController().itemsSource = value; } + /// + /// Raised when an item is expanded or collapsed. + /// + /// + /// The will contain the expanded state of the item being modified. + /// + public event Action itemExpandedChanged; + /// /// Sets the root items to use with the default tree view controller. /// @@ -183,6 +212,7 @@ public override void SetViewController(CollectionViewController controller) if (viewController != null) { viewController.itemIndexChanged -= OnItemIndexChanged; + viewController.itemExpandedChanged -= OnItemExpandedChanged; } base.SetViewController(controller); @@ -190,6 +220,7 @@ public override void SetViewController(CollectionViewController controller) if (viewController != null) { viewController.itemIndexChanged += OnItemIndexChanged; + viewController.itemExpandedChanged += OnItemExpandedChanged; } } @@ -198,6 +229,11 @@ void OnItemIndexChanged(int srcIndex, int dstIndex) RefreshItems(); } + void OnItemExpandedChanged(TreeViewExpansionChangedArgs arg) + { + itemExpandedChanged?.Invoke(arg); + } + internal override ICollectionDragAndDropController CreateDragAndDropController() => new TreeViewReorderableDragAndDropController(this); bool m_AutoExpand; @@ -341,10 +377,11 @@ public void AddItem(TreeViewItemData item, int parentId = -1, int childInd /// Removes an item of the tree if it can find it. /// /// The item id. + /// Whether we need to rebuild tree data. Set to false when doing multiple additions to save a few rebuilds. /// If the item was removed from the tree. - public bool TryRemoveItem(int id) + public bool TryRemoveItem(int id, bool rebuildTree = true) { - if (viewController.TryRemoveItem(id)) + if (viewController.TryRemoveItem(id, rebuildTree)) { RefreshItems(); return true; @@ -365,29 +402,36 @@ internal override void OnViewDataReady() private protected override bool HandleItemNavigation(bool moveIn, bool altPressed) { - var index = selectedIndex; - var hasChildren = viewController.HasChildrenByIndex(index); - var selectionIncrement = 1; - if (moveIn) + var hasChanges = false; + + foreach (var selectedId in selectedIds) { - if (hasChildren && !IsExpandedByIndex(index)) + var id = viewController.GetIndexForId(selectedId); + + if (!viewController.HasChildrenByIndex(id)) + break; + + if (moveIn && !IsExpandedByIndex(id)) { - ExpandItemByIndex(index, altPressed); - return true; + ExpandItemByIndex(id, altPressed); + hasChanges = true; } - } - else - { - if (hasChildren && IsExpandedByIndex(index)) + else if (!moveIn && IsExpandedByIndex(id)) { - CollapseItemByIndex(index, altPressed); - return true; + CollapseItemByIndex(id, altPressed); + hasChanges = true; } + } + + if (hasChanges) + return true; + if (!moveIn) + { // Find the nearest ancestor with children in the tree and select it. // If no ancestor is found, find the closest item with children before the current one. - var id = viewController.GetIdForIndex(index); + var id = viewController.GetIdForIndex(selectedIndex); var ancestorId = viewController.GetParentId(id); if (ancestorId != ReusableCollectionItem.UndefinedIndex) { @@ -399,8 +443,9 @@ private protected override bool HandleItemNavigation(bool moveIn, bool altPresse selectionIncrement = -1; } + bool hasChildren; // Find the next item with children in the tree and select it. - var selectionIndex = index; + var selectionIndex = selectedIndex; do { selectionIndex += selectionIncrement; diff --git a/Modules/UIElements/Core/Controls/BaseVerticalCollectionView.cs b/Modules/UIElements/Core/Controls/BaseVerticalCollectionView.cs index 3717fd53bc..4890175a78 100644 --- a/Modules/UIElements/Core/Controls/BaseVerticalCollectionView.cs +++ b/Modules/UIElements/Core/Controls/BaseVerticalCollectionView.cs @@ -1326,6 +1326,8 @@ private void Apply(KeyboardNavigationOperation op, EventBase sourceEvent) { sourceEvent.StopPropagation(); } + + focusController.IgnoreEvent(sourceEvent); } private protected virtual bool HandleItemNavigation(bool moveIn, bool altKey) diff --git a/Modules/UIElements/Core/Controls/Foldout.cs b/Modules/UIElements/Core/Controls/Foldout.cs index 923a41cb62..d24be72e5a 100644 --- a/Modules/UIElements/Core/Controls/Foldout.cs +++ b/Modules/UIElements/Core/Controls/Foldout.cs @@ -249,6 +249,8 @@ public void SetValueWithoutNotify(bool newValue) internal static readonly string ussFoldoutDepthClassName = ussClassName + "--depth-"; internal static readonly int ussFoldoutMaxDepth = 4; + private KeyboardNavigationManipulator m_NavigationManipulator; + internal override void OnViewDataReady() { base.OnViewDataReady(); @@ -259,13 +261,49 @@ internal override void OnViewDataReady() SetValueWithoutNotify(m_Value); } + private void Apply(KeyboardNavigationOperation op, EventBase sourceEvent) + { + if (Apply(op)) + { + sourceEvent.StopPropagation(); + } + + focusController.IgnoreEvent(sourceEvent); + } + + private bool Apply(KeyboardNavigationOperation op) + { + switch (op) + { + case KeyboardNavigationOperation.Previous: + case KeyboardNavigationOperation.Next: + case KeyboardNavigationOperation.SelectAll: + case KeyboardNavigationOperation.Cancel: + case KeyboardNavigationOperation.Submit: + case KeyboardNavigationOperation.Begin: + case KeyboardNavigationOperation.End: + case KeyboardNavigationOperation.PageDown: + case KeyboardNavigationOperation.PageUp: + break; // Allow focus to move outside the Foldout + case KeyboardNavigationOperation.MoveRight: + SetValueWithoutNotify(true); + return true; + case KeyboardNavigationOperation.MoveLeft: + SetValueWithoutNotify(false); + return true; + default: + throw new ArgumentOutOfRangeException(nameof(op), op, null); + } + + return false; + } + /// /// Constructs a Foldout element. /// public Foldout() { AddToClassList(ussClassName); - m_Toggle = new Toggle(); m_Container = new VisualElement() @@ -281,13 +319,13 @@ public Foldout() m_Toggle.AddToClassList(toggleUssClassName); m_Toggle.visualInput.AddToClassList(inputUssClassName); m_Toggle.visualInput.Q(className: Toggle.checkmarkUssClassName).AddToClassList(checkmarkUssClassName); + m_Toggle.AddManipulator(m_NavigationManipulator = new KeyboardNavigationManipulator(Apply)); hierarchy.Add(m_Toggle); m_Container.AddToClassList(contentUssClassName); hierarchy.Add(m_Container); RegisterCallback(OnAttachToPanel); - SetValueWithoutNotify(true); } diff --git a/Modules/UIElements/Core/Controls/ScrollView.cs b/Modules/UIElements/Core/Controls/ScrollView.cs index 5fe74e7b71..56e3ab22ff 100644 --- a/Modules/UIElements/Core/Controls/ScrollView.cs +++ b/Modules/UIElements/Core/Controls/ScrollView.cs @@ -524,6 +524,10 @@ internal float scrollableHeight private bool hasInertia => scrollDecelerationRate > 0f; private static readonly float k_DefaultScrollDecelerationRate = 0.135f; private float m_ScrollDecelerationRate = k_DefaultScrollDecelerationRate; + private float k_ScaledPixelsPerPointMultiplier = 10.0f; + // Equivalent to 240Hz. + private float k_TouchScrollInertiaBaseTimeInterval = 0.004167f; + /// /// Controls the rate at which the scrolling movement slows after a user scrolls using a touch interaction. /// @@ -843,6 +847,12 @@ private float GetDeltaDistance(float viewMin, float viewMax, float childBoundary private VisualElement m_ContentContainer; private VisualElement m_ContentAndVerticalScrollContainer; + private float previousVerticalTouchScrollTimeStamp = 0f; + private float previousHorizontalTouchScrollTimeStamp = 0f; + + private float elapsedTimeSinceLastVerticalTouchScroll = 0f; + private float elapsedTimeSinceLastHorizontalTouchScroll = 0f; + /// /// Contains full content, potentially partially visible. /// @@ -1359,14 +1369,13 @@ private void SpringBack() m_SpringBackVelocity = Vector2.zero; return; } - var newOffset = scrollOffset; if (newOffset.x < m_LowBounds.x) { newOffset.x = Mathf.SmoothDamp(newOffset.x, m_LowBounds.x, ref m_SpringBackVelocity.x, elasticity, - Mathf.Infinity, Time.unscaledDeltaTime); - if (Mathf.Abs(m_SpringBackVelocity.x) < 1) + Mathf.Infinity, elapsedTimeSinceLastHorizontalTouchScroll); + if (Mathf.Abs(m_SpringBackVelocity.x) < scaledPixelsPerPoint) { m_SpringBackVelocity.x = 0; } @@ -1374,8 +1383,8 @@ private void SpringBack() else if (newOffset.x > m_HighBounds.x) { newOffset.x = Mathf.SmoothDamp(newOffset.x, m_HighBounds.x, ref m_SpringBackVelocity.x, elasticity, - Mathf.Infinity, Time.unscaledDeltaTime); - if (Mathf.Abs(m_SpringBackVelocity.x) < 1) + Mathf.Infinity, elapsedTimeSinceLastHorizontalTouchScroll); + if (Mathf.Abs(m_SpringBackVelocity.x) < scaledPixelsPerPoint) { m_SpringBackVelocity.x = 0; } @@ -1388,8 +1397,8 @@ private void SpringBack() if (newOffset.y < m_LowBounds.y) { newOffset.y = Mathf.SmoothDamp(newOffset.y, m_LowBounds.y, ref m_SpringBackVelocity.y, elasticity, - Mathf.Infinity, Time.unscaledDeltaTime); - if (Mathf.Abs(m_SpringBackVelocity.y) < 1) + Mathf.Infinity, elapsedTimeSinceLastVerticalTouchScroll); + if (Mathf.Abs(m_SpringBackVelocity.y) < scaledPixelsPerPoint) { m_SpringBackVelocity.y = 0; } @@ -1397,8 +1406,8 @@ private void SpringBack() else if (newOffset.y > m_HighBounds.y) { newOffset.y = Mathf.SmoothDamp(newOffset.y, m_HighBounds.y, ref m_SpringBackVelocity.y, elasticity, - Mathf.Infinity, Time.unscaledDeltaTime); - if (Mathf.Abs(m_SpringBackVelocity.y) < 1) + Mathf.Infinity, elapsedTimeSinceLastVerticalTouchScroll); + if (Mathf.Abs(m_SpringBackVelocity.y) < scaledPixelsPerPoint) { m_SpringBackVelocity.y = 0; } @@ -1416,21 +1425,37 @@ internal void ApplyScrollInertia() { if (hasInertia && m_Velocity != Vector2.zero) { - m_Velocity *= Mathf.Pow(scrollDecelerationRate, Time.unscaledDeltaTime); + var additionalOffset = Vector2.zero; + var cumulativeDeltaTimeCovered = 0f; + while (cumulativeDeltaTimeCovered < elapsedTimeSinceLastVerticalTouchScroll) + { + m_Velocity *= Mathf.Pow(scrollDecelerationRate, k_TouchScrollInertiaBaseTimeInterval); + cumulativeDeltaTimeCovered += k_TouchScrollInertiaBaseTimeInterval; + additionalOffset += m_Velocity * k_TouchScrollInertiaBaseTimeInterval; + } - if (Mathf.Abs(m_Velocity.x) < 1 || + var remainingTimeDifference = elapsedTimeSinceLastVerticalTouchScroll - cumulativeDeltaTimeCovered; + if (remainingTimeDifference > 0 && remainingTimeDifference < k_TouchScrollInertiaBaseTimeInterval) + { + m_Velocity *= Mathf.Pow(scrollDecelerationRate, remainingTimeDifference); + additionalOffset += m_Velocity * remainingTimeDifference; + } + + var scaledSpeedLimit = scaledPixelsPerPoint * k_ScaledPixelsPerPointMultiplier; + + if (Mathf.Abs(m_Velocity.x) <= scaledSpeedLimit || touchScrollBehavior == TouchScrollBehavior.Elastic && (scrollOffset.x < m_LowBounds.x || scrollOffset.x > m_HighBounds.x)) { m_Velocity.x = 0; } - if (Mathf.Abs(m_Velocity.y) < 1 || + if (Mathf.Abs(m_Velocity.y) <= scaledSpeedLimit || touchScrollBehavior == TouchScrollBehavior.Elastic && (scrollOffset.y < m_LowBounds.y || scrollOffset.y > m_HighBounds.y)) { m_Velocity.y = 0; } - scrollOffset += m_Velocity * Time.unscaledDeltaTime; + scrollOffset += additionalOffset; } else { @@ -1440,6 +1465,11 @@ internal void ApplyScrollInertia() private void PostPointerUpAnimation() { + elapsedTimeSinceLastVerticalTouchScroll = Time.unscaledTime - previousVerticalTouchScrollTimeStamp; + previousVerticalTouchScrollTimeStamp = Time.unscaledTime; + + elapsedTimeSinceLastHorizontalTouchScroll = Time.unscaledTime - previousHorizontalTouchScrollTimeStamp; + previousHorizontalTouchScrollTimeStamp = Time.unscaledTime; ApplyScrollInertia(); SpringBack(); @@ -1447,6 +1477,10 @@ private void PostPointerUpAnimation() if (m_SpringBackVelocity == Vector2.zero && m_Velocity == Vector2.zero) { m_PostPointerUpAnimation.Pause(); + elapsedTimeSinceLastVerticalTouchScroll = 0f; + elapsedTimeSinceLastHorizontalTouchScroll = 0f; + previousVerticalTouchScrollTimeStamp = 0f; + previousHorizontalTouchScrollTimeStamp = 0f; } } @@ -1553,6 +1587,7 @@ internal void InitTouchScrolling(Vector2 position) Mathf.Max(verticalScroller.lowValue, verticalScroller.highValue)); } + // Internal for tests. internal TouchScrollingResult ComputeTouchScrolling(Vector2 position) { @@ -1573,6 +1608,9 @@ internal TouchScrollingResult ComputeTouchScrolling(Vector2 position) newScrollOffset.y = ComputeElasticOffset(deltaPointer.y, m_StartPosition.y, m_LowBounds.y, m_LowBounds.y - contentViewport.resolvedStyle.height, m_HighBounds.y, m_HighBounds.y + contentViewport.resolvedStyle.height); + + previousVerticalTouchScrollTimeStamp = Time.unscaledTime; + previousHorizontalTouchScrollTimeStamp = Time.unscaledTime; } else { @@ -1618,7 +1656,7 @@ bool ApplyTouchScrolling(Vector2 newScrollOffset) m_LastVelocityLerpTime = Time.unscaledTime; - var deltaTime = Time.unscaledDeltaTime; + var deltaTime = (m_ElasticAnimationIntervalMs/1000f); var newVelocity = (newScrollOffset - scrollOffset) / deltaTime; m_Velocity = Vector2.Lerp(m_Velocity, newVelocity, deltaTime * k_VelocityLerpTimeFactor); } @@ -1641,6 +1679,8 @@ bool ReleaseScrolling(int pointerId, IEventHandler target) if (target != contentContainer || !contentContainer.HasPointerCapture(pointerId)) return false; + previousVerticalTouchScrollTimeStamp = Time.unscaledTime; + previousHorizontalTouchScrollTimeStamp = Time.unscaledTime; if (touchScrollBehavior == TouchScrollBehavior.Elastic || hasInertia) { ExecuteElasticSpringAnimation(); diff --git a/Modules/UIElements/Core/GameObjects/RuntimePanel.cs b/Modules/UIElements/Core/GameObjects/RuntimePanel.cs index 679e573cfd..0554bf7321 100644 --- a/Modules/UIElements/Core/GameObjects/RuntimePanel.cs +++ b/Modules/UIElements/Core/GameObjects/RuntimePanel.cs @@ -46,7 +46,7 @@ private RuntimePanel(ScriptableObject ownerObject) TrickleDown.TrickleDown); } - public override void Update() + internal override void Update() { if (m_PanelSettings != null) m_PanelSettings.ApplyPanelSettings(); diff --git a/Modules/UIElements/Core/IMGUIContainer.cs b/Modules/UIElements/Core/IMGUIContainer.cs index 025c0ae2dc..93f95b133f 100644 --- a/Modules/UIElements/Core/IMGUIContainer.cs +++ b/Modules/UIElements/Core/IMGUIContainer.cs @@ -256,6 +256,7 @@ private struct GUIGlobals public bool enabled; public bool changed; public int displayIndex; + public float pixelsPerPoint; } private GUIGlobals m_GUIGlobals; @@ -272,6 +273,7 @@ private void SaveGlobals() { m_GUIGlobals.displayIndex = Event.current.displayIndex; } + m_GUIGlobals.pixelsPerPoint = GUIUtility.pixelsPerPoint; } private void RestoreGlobals() @@ -286,6 +288,7 @@ private void RestoreGlobals() { Event.current.displayIndex = m_GUIGlobals.displayIndex; } + GUIUtility.pixelsPerPoint = m_GUIGlobals.pixelsPerPoint; } static readonly ProfilerMarker k_OnGUIMarker = new ProfilerMarker("OnGUI"); @@ -319,6 +322,10 @@ private void DoOnGUI(Event evt, Matrix4x4 parentTransform, Rect clippingRect, bo // From now on, Event.current is either evt or a copy of evt. // Since Event.current may change while being processed, we do not rely on evt below but use Event.current instead. + + GUIUtility.pixelsPerPoint = scaledPixelsPerPoint; + + if (Event.current.type != EventType.Layout) { if (lostFocus) diff --git a/Modules/UIElements/Core/Layout/LayoutConfig.cs b/Modules/UIElements/Core/Layout/LayoutConfig.cs index b64a062da2..cf68fe642b 100644 --- a/Modules/UIElements/Core/Layout/LayoutConfig.cs +++ b/Modules/UIElements/Core/Layout/LayoutConfig.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; @@ -30,16 +30,6 @@ internal LayoutConfig(LayoutDataAccess access, LayoutHandle handle) /// public LayoutHandle Handle => m_Handle; - /// - /// Gets or sets if configured nodes should use web default settings. - /// - public ref bool UseWebDefaults => ref m_Access.GetConfigData(m_Handle).UseWebDefaults; - - /// - /// Gets or sets if configured nodes should legacy stretching behavior. - /// - public ref bool UseLegacyStretchBehaviour => ref m_Access.GetConfigData(m_Handle).UseLegacyStretchBehaviour; - /// /// Gets or sets the shared point scale factor for configured nodes. /// diff --git a/Modules/UIElements/Core/Layout/LayoutManager.cs b/Modules/UIElements/Core/Layout/LayoutManager.cs index 96b2390bc5..859281c5cf 100644 --- a/Modules/UIElements/Core/Layout/LayoutManager.cs +++ b/Modules/UIElements/Core/Layout/LayoutManager.cs @@ -195,7 +195,8 @@ static void Shutdown() readonly ManagedObjectStore m_ManagedBaselineFunctions = new(); readonly ManagedObjectStore> m_ManagedOwners = new(); - int m_HighMark; + // Last allocated index in the store (0 mean index 0 is valid aka a node was allocated) + int m_HighMark = -1; internal static LayoutManager GetManager(int index) => (uint) index < s_Managers.Count ? s_Managers[index] : null; @@ -233,15 +234,16 @@ public void Dispose() unsafe { + // if m_HighMark == 0, then a single node was allocated and we need to dispose it for (var i = 0; i <= m_HighMark; i++) { - ref var data = ref ((LayoutNodeData*) m_Nodes.GetComponentDataPtr(i, (int)LayoutNodeDataType.Node))[0]; + var data = (LayoutNodeData*) m_Nodes.GetComponentDataPtr(i, (int)LayoutNodeDataType.Node); - if (!data.Children.IsCreated) + if (!data->Children.IsCreated) continue; - data.Children.Dispose(); - data.Children = default; + data->Children.Dispose(); + data->Children = new(); } } @@ -293,7 +295,7 @@ LayoutNode CreateNodeInternal(LayoutHandle configHandle) TryFreeNodes(); var handle = m_Nodes.Allocate( - new LayoutNodeData { Config = configHandle }, + new LayoutNodeData { Config = configHandle , Children= new() }, LayoutStyleData.Default, LayoutComputedData.Default, LayoutCacheData.Default, @@ -306,8 +308,7 @@ LayoutNode CreateNodeInternal(LayoutHandle configHandle) var node = new LayoutNode(GetAccess(), handle); - node.InitializeStyle(); - + Debug.Assert(!GetAccess().GetNodeData(handle).Children.IsCreated, "memory is not initialized" ); return node; } @@ -349,7 +350,7 @@ public void DestroyNode(ref LayoutNode node) if (data.Children.IsCreated) { data.Children.Dispose(); - data.Children = default; + data.Children = new(); } // Defer the shared resource free until later. diff --git a/Modules/UIElements/Core/Layout/LayoutNode+Style.cs b/Modules/UIElements/Core/Layout/LayoutNode+Style.cs index 149a73ce56..4958e977c2 100644 --- a/Modules/UIElements/Core/Layout/LayoutNode+Style.cs +++ b/Modules/UIElements/Core/Layout/LayoutNode+Style.cs @@ -125,11 +125,6 @@ public LayoutWrap Wrap } } - public float Flex - { - set => SetValue(ref Style.Flex, value); - } - public float FlexGrow { get => Style.FlexGrow; diff --git a/Modules/UIElements/Core/Layout/LayoutNode.cs b/Modules/UIElements/Core/Layout/LayoutNode.cs index 136ccb8d4b..aab9e1d54b 100644 --- a/Modules/UIElements/Core/Layout/LayoutNode.cs +++ b/Modules/UIElements/Core/Layout/LayoutNode.cs @@ -61,12 +61,20 @@ internal LayoutNode(LayoutDataAccess access, LayoutHandle handle) /// /// Gets or sets the dirty flag for this node. Used when calculating layout. /// - public ref bool IsDirty => ref m_Access.GetNodeData(m_Handle).IsDirty; + public bool IsDirty + { + get => m_Access.GetNodeData(m_Handle).IsDirty; + set => m_Access.GetNodeData(m_Handle).IsDirty = value; + } /// /// Gets or sets the new layout flag for this node. Used when calculating layout. /// - public ref bool HasNewLayout => ref m_Access.GetNodeData(m_Handle).HasNewLayout; + public bool HasNewLayout + { + get => m_Access.GetNodeData(m_Handle).HasNewLayout; + set => m_Access.GetNodeData(m_Handle).HasNewLayout = value; + } /// /// Returns if a custom measurement method is defined. @@ -147,21 +155,8 @@ public void MarkLayoutSeen() HasNewLayout = false; } - /// - /// Initialize the style based on the config. - /// - public void InitializeStyle() - { - if (!Config.IsUndefined && Config.UseWebDefaults) - { - Style.FlexDirection = LayoutFlexDirection.Row; - Style.AlignContent = LayoutAlign.Stretch; - } - } - public void CopyFromComputedStyle(ComputedStyle style) { - Flex = float.NaN; FlexGrow = style.flexGrow; FlexShrink = style.flexShrink; FlexBasis = style.flexBasis.ToLayoutValue(); @@ -284,8 +279,6 @@ public void Reset() StyleBorders = LayoutStyleBorderData.Default; StyleMargins = LayoutStyleMarginData.Default; StyleDimensions = LayoutStyleDimensionData.Default; - - InitializeStyle(); } public bool Equals(LayoutNode other) diff --git a/Modules/UIElements/Core/Layout/Model/Components/LayoutConfigData.cs b/Modules/UIElements/Core/Layout/Model/Components/LayoutConfigData.cs index 228e03c6be..c7030ba85f 100644 --- a/Modules/UIElements/Core/Layout/Model/Components/LayoutConfigData.cs +++ b/Modules/UIElements/Core/Layout/Model/Components/LayoutConfigData.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,4 @@ struct LayoutConfigData }; public float PointScaleFactor; - [MarshalAs(UnmanagedType.U1)] public bool UseWebDefaults; - [MarshalAs(UnmanagedType.U1)] public bool UseLegacyStretchBehaviour; } diff --git a/Modules/UIElements/Core/Layout/Model/Components/LayoutDataStore.cs b/Modules/UIElements/Core/Layout/Model/Components/LayoutDataStore.cs index 2a59c13a41..d82b9ecaba 100644 --- a/Modules/UIElements/Core/Layout/Model/Components/LayoutDataStore.cs +++ b/Modules/UIElements/Core/Layout/Model/Components/LayoutDataStore.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.CompilerServices; using System.Runtime.InteropServices; using Unity.Collections; @@ -111,6 +111,7 @@ public void EnsureCapacity(int capacity) m_Chunks[i] = new Chunk { Buffer = (byte*)UnsafeUtility.Malloc(k_ChunkSize, 4, Allocator) + // memory is cleared when we call Allocate with some data }; } @@ -218,11 +219,6 @@ public bool Exists(in LayoutHandle handle) return m_Data->Components[componentIndex].GetComponentDataPtr(index); } - public LayoutHandle Allocate() - { - return Allocate(null, 0); - } - LayoutHandle Allocate(byte** data, int count) { // Fetch the next available index. This is the element we are about to initialize. @@ -244,8 +240,11 @@ LayoutHandle Allocate(byte** data, int count) m_Data->NextFreeIndex = nextIndex; + Debug.Assert(m_Data->ComponentCount == count, "All components must be initialized"); + Debug.Assert(data != null); for (var i = 0; i < count; i++) { + Debug.Assert(data[i] != null); var ptr = m_Data->Components[i].GetComponentDataPtr(index); UnsafeUtility.MemCpy(ptr, data[i], m_Data->Components[i].Size); } diff --git a/Modules/UIElements/Core/Layout/Model/Components/LayoutNodeData.cs b/Modules/UIElements/Core/Layout/Model/Components/LayoutNodeData.cs index 88f1ef410a..967540b429 100644 --- a/Modules/UIElements/Core/Layout/Model/Components/LayoutNodeData.cs +++ b/Modules/UIElements/Core/Layout/Model/Components/LayoutNodeData.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; using System.Runtime.InteropServices; namespace UnityEngine.UIElements.Layout; @@ -9,10 +10,27 @@ namespace UnityEngine.UIElements.Layout; [StructLayout(LayoutKind.Sequential)] struct LayoutNodeData { - public FixedBuffer2 ResolvedDimensions; + [Flags] + internal enum FlexStatus + { + // External States + + // Input suggesting the layout may have changed and should be recomputed. + IsDirty = 1 << 0, + + // Output of the layout telling the node has a new layout that needs to be taken into account. + // (generate GCO, dirty visuals) + HasNewLayout = 1 << 2, - public bool IsDirty; - public bool HasNewLayout; + // Internal State + // The Next 3 bits represent the status of the node for the flex algorithm. + Fixed = 1 << 3, + MinViolation = 1 << 4, + MaxViolation = 1 << 5, + } + + public FixedBuffer2 ResolvedDimensions; + float TargetSize; public int ManagedMeasureFunctionIndex; public int ManagedBaselineFunctionIndex; public int ManagedOwnerIndex; @@ -23,4 +41,21 @@ struct LayoutNodeData public LayoutHandle NextChild; public LayoutList Children; + private FlexStatus Status; + + public bool HasNewLayout + { + get => (Status & FlexStatus.HasNewLayout) == FlexStatus.HasNewLayout; + set => Status = value ? Status | FlexStatus.HasNewLayout : Status & ~FlexStatus.HasNewLayout; + } + + public bool IsDirty + { + get => (Status & FlexStatus.IsDirty) == FlexStatus.IsDirty; + set => Status = value ? Status | FlexStatus.IsDirty : Status & ~FlexStatus.IsDirty; + } + + // FlexInternal states are just valid during the flex algorithm, has no meaning outside of it so it is not exposed. } + + diff --git a/Modules/UIElements/Core/Layout/Model/Components/LayoutStyleData.cs b/Modules/UIElements/Core/Layout/Model/Components/LayoutStyleData.cs index bf33b42736..80177ef275 100644 --- a/Modules/UIElements/Core/Layout/Model/Components/LayoutStyleData.cs +++ b/Modules/UIElements/Core/Layout/Model/Components/LayoutStyleData.cs @@ -23,7 +23,6 @@ struct LayoutStyleData FlexWrap = LayoutWrap.NoWrap, Overflow = LayoutOverflow.Visible, Display = LayoutDisplay.Flex, - Flex = float.NaN, FlexGrow = float.NaN, FlexShrink = float.NaN, FlexBasis = LayoutValue.Auto() @@ -41,7 +40,6 @@ struct LayoutStyleData public LayoutWrap FlexWrap; public LayoutOverflow Overflow; public LayoutDisplay Display; - public float Flex; public float FlexGrow; public float FlexShrink; public LayoutValue FlexBasis; diff --git a/Modules/UIElements/Core/Layout/Model/LayoutList.cs b/Modules/UIElements/Core/Layout/Model/LayoutList.cs index 84e65438c5..245787ddfb 100644 --- a/Modules/UIElements/Core/Layout/Model/LayoutList.cs +++ b/Modules/UIElements/Core/Layout/Model/LayoutList.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; using System.Collections.Generic; using System.Runtime.InteropServices; @@ -42,6 +42,12 @@ public ref T this[int index] } } + public LayoutList() + { + m_Data = null; + m_Allocator = Allocator.Invalid; + } + public LayoutList(int initialCapacity, Allocator allocator) { m_Allocator = allocator; diff --git a/Modules/UIElements/Core/Panel.cs b/Modules/UIElements/Core/Panel.cs index a7bbec7d7d..5554f8f073 100644 --- a/Modules/UIElements/Core/Panel.cs +++ b/Modules/UIElements/Core/Panel.cs @@ -424,7 +424,6 @@ protected BaseVisualElementPanel() // m_VisualPanel.SetOwner(this); layoutConfig = LayoutManager.SharedManager.CreateConfig(); - layoutConfig.UseWebDefaults = false; m_UIElementsBridge = new RuntimeUIElementsBridge(); } @@ -698,6 +697,10 @@ protected void InvokeStandardWorldSpaceShaderChanged() internal event Action isFlatChanged; bool m_IsFlat = true; + + // Used only for testing. Can be disabled for setting a manual scale + internal bool UpdateScalingFromEditorWindow; + public bool isFlat { get => m_IsFlat; @@ -758,17 +761,6 @@ internal void UpdateElementUnderPointers() public IPanelDebug panelDebug { get; set; } public ILiveReloadSystem liveReloadSystem { get; set; } - public virtual void Update() - { - scheduler.UpdateScheduledEvents(); - // This call is already on UIElementsUtility.UpdateSchedulers() but it's also necessary here for Runtime UI - UpdateAssetTrackers(); - ValidateFocus(); - ValidateLayout(); - UpdateAnimations(); - UpdateBindings(); - } - Action m_RenderAction; internal void SetRenderAction(Action action) => m_RenderAction = action; public virtual void Render() => m_RenderAction?.Invoke(); @@ -1286,10 +1278,6 @@ public override void Repaint(Event e) { m_RepaintVersion = version; - // in an in-game context, pixelsPerPoint is user driven - if (contextType == ContextType.Editor) - pixelsPerPoint = GUIUtility.pixelsPerPoint; - repaintData.repaintEvent = e; using (m_MarkerBeforeUpdate.Auto()) @@ -1458,6 +1446,17 @@ internal float pixelsPerUnit { internal int screenRenderingWidth => getScreenRenderingWidth(targetDisplay); internal int screenRenderingHeight => getScreenRenderingHeight(targetDisplay); + internal virtual void Update() + { + scheduler.UpdateScheduledEvents(); + // This call is already on UIElementsUtility.UpdateSchedulers() but it's also necessary here for Runtime UI + UpdateAssetTrackers(); + ValidateFocus(); + ValidateLayout(); + UpdateAnimations(); + UpdateBindings(); + } + // 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) @@ -1558,17 +1557,12 @@ private void AssignPanelToComponents(BaseRuntimePanel panel) if (selectableGameObject == null) return; - var components = ObjectListPool.Get(); - try // Going through potential user code + using (Pool.ListPool.Get(out var components)) { selectableGameObject.GetComponents(components); foreach (var component in components) component.panel = panel; } - finally - { - ObjectListPool.Release(components); - } } internal void PointerLeavesPanel(int pointerId, Vector2 position) diff --git a/Modules/UIElements/Core/Text/PanelTextSettings.cs b/Modules/UIElements/Core/Text/PanelTextSettings.cs index 293664d3a3..76e7af2814 100644 --- a/Modules/UIElements/Core/Text/PanelTextSettings.cs +++ b/Modules/UIElements/Core/Text/PanelTextSettings.cs @@ -23,13 +23,17 @@ internal static PanelTextSettings defaultPanelTextSettings { get { - if (s_DefaultPanelTextSettings == null) - { - s_DefaultPanelTextSettings = ScriptableObject.CreateInstance(); - } - + InitializeDefaultPanelTextSettingsIfNull(); return s_DefaultPanelTextSettings; } } + + internal static void InitializeDefaultPanelTextSettingsIfNull() + { + if (s_DefaultPanelTextSettings == null) + { + s_DefaultPanelTextSettings = ScriptableObject.CreateInstance(); + } + } } } diff --git a/Modules/UIElements/Core/Text/UITKTextJobSystem.cs b/Modules/UIElements/Core/Text/UITKTextJobSystem.cs index 953fbc55f9..b119651d26 100644 --- a/Modules/UIElements/Core/Text/UITKTextJobSystem.cs +++ b/Modules/UIElements/Core/Text/UITKTextJobSystem.cs @@ -123,6 +123,7 @@ internal void GenerateText(MeshGenerationContext mgc, TextElement textElement) internal void PrepareTextJobified(MeshGenerationContext mgc, object _) { TextHandle.InitThreadArrays(); + PanelTextSettings.InitializeDefaultPanelTextSettingsIfNull(); TextHandle.currentTime = Time.realtimeSinceStartup; k_PrepareMainThreadMarker.Begin(); @@ -164,15 +165,11 @@ private void GenerateTextJobified(MeshGenerationContext mgc, object _) k_UpdateMainThreadMarker.Begin(); foreach (var textData in textJobDatas) { - if (!textData.prepareSuccess) - { - textData.visualElement.uitkTextHandle.ConvertUssToTextGenerationSettings(); - textData.visualElement.uitkTextHandle.PrepareFontAsset(); - } + if (textData.prepareSuccess) + continue; - var fa = TextUtilities.GetFontAsset(textData.visualElement); - if (fa.m_CharacterLookupDictionary == null) - fa.ReadFontAssetDefinition(); + textData.visualElement.uitkTextHandle.ConvertUssToTextGenerationSettings(); + textData.visualElement.uitkTextHandle.PrepareFontAsset(); } FontAsset.UpdateFontAssetsInUpdateQueue(); diff --git a/Modules/UIElements/Core/TextElement.cs b/Modules/UIElements/Core/TextElement.cs index f2dd284122..1060655e2e 100644 --- a/Modules/UIElements/Core/TextElement.cs +++ b/Modules/UIElements/Core/TextElement.cs @@ -186,11 +186,12 @@ public TextElement() AddToClassList(ussClassName); generateVisualContent += OnGenerateVisualContent; + edition.GetDefaultValueType = GetDefaultValueType; RegisterCallback(OnGeometryChanged); RegisterCallback(OnAttachToPanel); RegisterCallback(OnDetachFromPanel); } - + string GetDefaultValueType() { return ""; } internal UITKTextHandle uitkTextHandle { get; set; } diff --git a/Modules/UIElements/Core/TextElementEdition.cs b/Modules/UIElements/Core/TextElementEdition.cs index b5eee58b14..eda1f58497 100644 --- a/Modules/UIElements/Core/TextElementEdition.cs +++ b/Modules/UIElements/Core/TextElementEdition.cs @@ -390,7 +390,7 @@ string ITextEdition.placeholder //this approach results not showing leading 0s when input fields are updated from the UI Builder if there is a placeholder text //however since this does not occur at run-time and inputfields are generally empty when placeholder text is set this should be ok //if we want to fix this down the line then defaultValue needs to return null so we could differentiate an empty field vs. one with "0" - if (!string.IsNullOrEmpty(value) && text.Equals(edition.GetDefaultValueType())) + if (!string.IsNullOrEmpty(value) && (text == null || text.Equals(edition.GetDefaultValueType()))) text = ""; m_PlaceholderText = value; @@ -513,10 +513,14 @@ internal bool showPlaceholderText { get { - if (edition.hidePlaceholderOnFocus) - return string.IsNullOrEmpty(text) && !hasFocus; + var isPlaceholderVisible = m_PlaceholderText.Length > 0; + var shouldHideOnFocus = edition.hidePlaceholderOnFocus && hasFocus; + var isTextEmpty = string.IsNullOrEmpty(text); - return string.IsNullOrEmpty(text); + if (!isPlaceholderVisible) return false; + if (shouldHideOnFocus) return false; + + return isTextEmpty; } } @@ -553,7 +557,7 @@ internal RenderedText renderedText if (effectiveMaskChar != char.MinValue) { - return new RenderedText(effectiveMaskChar, m_RenderedText.Length, ZeroWidthSpace); + return new RenderedText(effectiveMaskChar, m_RenderedText?.Length ?? 0, ZeroWidthSpace); } return new RenderedText(m_RenderedText, ZeroWidthSpace); diff --git a/Modules/UIElements/Core/UIElementsUtility.cs b/Modules/UIElements/Core/UIElementsUtility.cs index d38f124b46..187a9b7bac 100644 --- a/Modules/UIElements/Core/UIElementsUtility.cs +++ b/Modules/UIElements/Core/UIElementsUtility.cs @@ -569,9 +569,12 @@ internal static string ParseMenuName(string menuName) var displayValue = menuName.TrimEnd(); var separatorPos = displayValue.LastIndexOf(' '); - int modifierPos = Array.IndexOf(s_Modifiers, displayValue[separatorPos + 1]); - if (separatorPos != -1 && displayValue.Length > separatorPos + 1 && modifierPos > -1) - displayValue = displayValue.Substring(0, separatorPos).TrimEnd(); + if (separatorPos > -1) + { + int modifierPos = Array.IndexOf(s_Modifiers, displayValue[separatorPos + 1]); + if (displayValue.Length > separatorPos + 1 && modifierPos > -1) + displayValue = displayValue.Substring(0, separatorPos).TrimEnd(); + } return displayValue; } diff --git a/Modules/UIElements/Core/UXML/VisualTreeAsset.cs b/Modules/UIElements/Core/UXML/VisualTreeAsset.cs index 0bfd185a5d..0cf04e4a8c 100644 --- a/Modules/UIElements/Core/UXML/VisualTreeAsset.cs +++ b/Modules/UIElements/Core/UXML/VisualTreeAsset.cs @@ -212,7 +212,7 @@ public IEnumerable templateDependencies } else if (!string.IsNullOrEmpty(entry.path)) { - var vta = Panel.LoadResource(entry.path, typeof(VisualTreeAsset), GUIUtility.pixelsPerPoint) as + var vta = Panel.LoadResource(entry.path, typeof(VisualTreeAsset),1) as VisualTreeAsset; if (vta != null && !sent.Contains(entry.asset)) { @@ -257,8 +257,7 @@ public IEnumerable stylesheets foreach (var stylesheetPath in vea.stylesheetPaths) { var stylesheet = - Panel.LoadResource(stylesheetPath, typeof(StyleSheet), - GUIUtility.pixelsPerPoint) as StyleSheet; + Panel.LoadResource(stylesheetPath, typeof(StyleSheet), 1) as StyleSheet; if (stylesheet != null && !sent.Contains(stylesheet)) { sent.Add(stylesheet); @@ -1002,7 +1001,7 @@ internal VisualTreeAsset ResolveTemplate(string templateName) return entry.asset; string path = entry.path; - return Panel.LoadResource(path, typeof(VisualTreeAsset), GUIUtility.pixelsPerPoint) as VisualTreeAsset; + return Panel.LoadResource(path, typeof(VisualTreeAsset),1) as VisualTreeAsset; } [VisibleToOtherModules("UnityEditor.UIBuilderModule")] diff --git a/Modules/UIElementsEditor/EditorMonitor.cs b/Modules/UIElementsEditor/EditorMonitor.cs index 29faeca9cc..24ad26a269 100644 --- a/Modules/UIElementsEditor/EditorMonitor.cs +++ b/Modules/UIElementsEditor/EditorMonitor.cs @@ -74,15 +74,13 @@ bool CheckForRenderTexturesTrashed() } } - namespace Experimental + /// Utility that manages asset monitoring features of UI Toolkit panels. + public static class AssetMonitoringUtilities { - static class AssetMonitoringExtensions - { - /// Gets the state that controls if the panel of the EditorWindow should reset its rendering data when an asset changes. - public static bool GetResetPanelRenderingOnAssetChange(EditorWindow window) => window.resetPanelRenderingOnAssetChange; + /// Gets the state that controls if the panel of the EditorWindow should reset its rendering data when an asset changes. + public static bool GetResetPanelRenderingOnAssetChange(EditorWindow window) => window.resetPanelRenderingOnAssetChange; - /// Sets the state that controls if the panel of the EditorWindow should reset its rendering data when an asset changes. - public static void SetResetPanelRenderingOnAssetChange(EditorWindow window, bool reset) => window.resetPanelRenderingOnAssetChange = reset; - } + /// Sets the state that controls if the panel of the EditorWindow should reset its rendering data when an asset changes. + public static void SetResetPanelRenderingOnAssetChange(EditorWindow window, bool reset) => window.resetPanelRenderingOnAssetChange = reset; } } diff --git a/Modules/UIElementsEditor/EditorPanel.cs b/Modules/UIElementsEditor/EditorPanel.cs index f5aedb26a7..c85eec17aa 100644 --- a/Modules/UIElementsEditor/EditorPanel.cs +++ b/Modules/UIElementsEditor/EditorPanel.cs @@ -46,6 +46,7 @@ public static Panel FindOrCreate(ScriptableObject ownerObject) standardShader = EditorShader; updateMaterial += OnUpdateMaterial; uiElementsBridge = new EditorUIElementsBridge(); + UpdateScalingFromEditorWindow = true; } static void OnUpdateMaterial(Material mat) @@ -61,5 +62,61 @@ public static void InitEditorUpdater(BaseVisualElementPanel panel, VisualTreeUpd var assetTracker = editorUpdater.GetUpdater(VisualTreeEditorUpdatePhase.AssetChange) as ILiveReloadSystem; panel.liveReloadSystem = assetTracker; } + + internal float? GetBackingScaleFactor() + { + return GetBackingScaleFactor(ownerObject); + } + + float? GetBackingScaleFactor(object obj) + { + return obj switch + { + GUIView view => view.GetBackingScaleFactor(), + View view => GetBackingScaleFactor(view.parent), //MainView and SplitView are not GUIView + EditorWindow editorWindow => GetBackingScaleFactor(editorWindow?.m_Parent), + IEditorWindowModel ewm => GetBackingScaleFactor(ewm.window), + _ => null, + } ; + } + + private void CheckPanelScaling() + { + // Can be disabled for setting a manual scale for testing + if (UpdateScalingFromEditorWindow) + { + + //check that the scaling is up to date + var windowScaling = GetBackingScaleFactor(); + if (windowScaling == null || windowScaling.Value == -1) + { + Debug.Assert(windowScaling != null, "got -1 here!!" ); + // if we have -1, we were able to get to a GuiView, but the native call returned -1 because there is no containerWindow + // if the windowScaling == null we were simply not able to get to a GuiView + // in both cases, we want to update the scaling like the old behavior. + pixelsPerPoint = GUIUtility.pixelsPerPoint; + } + else + { + Debug.Assert(pixelsPerPoint == windowScaling.Value, $"Scaling mismatch between the EditorWindow ({windowScaling.Value}) and the Editor Panel {name} ({pixelsPerPoint}). OnBackingScaleFactorChangedInternal was probably not call upon scaling change"); + pixelsPerPoint = windowScaling.Value;// AKA silence the assert after the first occurence + } + } + } + public override void ValidateLayout() + { + CheckPanelScaling(); + base.ValidateLayout(); + } + public override void Repaint(Event e) + { + CheckPanelScaling(); + base.Repaint(e); + } + public override void Render() + { + CheckPanelScaling(); + base.Render(); + } } } diff --git a/Modules/UIElementsEditor/UIElementsEditorInitialization.cs b/Modules/UIElementsEditor/UIElementsEditorInitialization.cs index 67d3c54727..cebe018e05 100644 --- a/Modules/UIElementsEditor/UIElementsEditorInitialization.cs +++ b/Modules/UIElementsEditor/UIElementsEditorInitialization.cs @@ -16,7 +16,7 @@ public static void InitializeUIElementsEditorManaged() { var jobHandle = PropertiesEditorInitialization.GetInitializationJobHandle(); var handle = new InitializeUIElementsJob().Schedule(jobHandle); - PropertyBag.AddJobToWaitQueue(handle); + JobHandle.ScheduleBatchedJobs(); } struct InitializeUIElementsJob : IJob diff --git a/Modules/UIElementsEditor/VisualTreeAssetEditor.cs b/Modules/UIElementsEditor/VisualTreeAssetEditor.cs index 69d6ef5f75..2a7740779a 100644 --- a/Modules/UIElementsEditor/VisualTreeAssetEditor.cs +++ b/Modules/UIElementsEditor/VisualTreeAssetEditor.cs @@ -93,6 +93,8 @@ private void RenderStaticPreview(int width, int height, ref RenderTexture tex) var r = new Rect(0, 0, width, height); var viewportRect = GUIClip.UnclipToWindow(r); // Still in points, not pixels + m_Panel.pixelsPerPoint = 1; + m_Panel.UpdateScalingFromEditorWindow = false; m_Panel.visualTree.SetSize(viewportRect.size); // We will draw relative to a viewport covering the preview area, so draw at 0,0 m_Panel.visualTree.IncrementVersion(VersionChangeType.Repaint); diff --git a/Modules/UIElementsEditor/WindowBackends/DefaultWindowBackend.cs b/Modules/UIElementsEditor/WindowBackends/DefaultWindowBackend.cs index aa15df6d9b..d45c190917 100644 --- a/Modules/UIElementsEditor/WindowBackends/DefaultWindowBackend.cs +++ b/Modules/UIElementsEditor/WindowBackends/DefaultWindowBackend.cs @@ -39,11 +39,13 @@ public virtual void OnCreate(IWindowModel model) m_Panel.rootIMGUIContainer = imguiContainer; } - void IWindowBackend.SizeChanged() + public virtual void SizeChanged() { // The window backend isn't aware of the panel scaling, so the size only considers the native // pixels-per-point value. So for example, if a panel scaling of 2 is used, we must have twice // less points displayed, hence the division by 2. + + OnBackingScaleFactorChanged(); m_Panel.visualTree.SetSize(m_Model.size / m_Panel.scale); } @@ -102,5 +104,11 @@ public bool GetTooltip(Vector2 windowMouseCoordinates, out string tooltip, out R } return false; } + + public virtual void OnBackingScaleFactorChanged() + { + if (panel.UpdateScalingFromEditorWindow) + panel.pixelsPerPoint = (panel as EditorPanel).GetBackingScaleFactor() ?? 1; + } } } diff --git a/Modules/UnityWebRequest/Public/CertificateHandler/CertificateHandler.bindings.cs b/Modules/UnityWebRequest/Public/CertificateHandler/CertificateHandler.bindings.cs index d255bf6868..ce898a64e2 100644 --- a/Modules/UnityWebRequest/Public/CertificateHandler/CertificateHandler.bindings.cs +++ b/Modules/UnityWebRequest/Public/CertificateHandler/CertificateHandler.bindings.cs @@ -19,7 +19,7 @@ public class CertificateHandler : IDisposable extern private static IntPtr Create([Unmarshalled] CertificateHandler obj); [NativeMethod(IsThreadSafe = true)] - extern private void Release(); + extern private void ReleaseFromScripting(); protected CertificateHandler() { @@ -46,7 +46,7 @@ public void Dispose() { if (m_Ptr != IntPtr.Zero) { - Release(); + ReleaseFromScripting(); m_Ptr = IntPtr.Zero; } } diff --git a/Modules/UnityWebRequest/Public/DownloadHandler/DownloadHandler.bindings.cs b/Modules/UnityWebRequest/Public/DownloadHandler/DownloadHandler.bindings.cs index 3f3b457172..a524a9649b 100644 --- a/Modules/UnityWebRequest/Public/DownloadHandler/DownloadHandler.bindings.cs +++ b/Modules/UnityWebRequest/Public/DownloadHandler/DownloadHandler.bindings.cs @@ -25,7 +25,7 @@ public class DownloadHandler : IDisposable internal IntPtr m_Ptr; [NativeMethod(IsThreadSafe = true)] - private extern void Release(); + private extern void ReleaseFromScripting(); [VisibleToOtherModules] internal DownloadHandler() @@ -40,7 +40,7 @@ public virtual void Dispose() { if (m_Ptr != IntPtr.Zero) { - Release(); + ReleaseFromScripting(); m_Ptr = IntPtr.Zero; } } diff --git a/Modules/UnityWebRequest/Public/UploadHandler/UploadHandler.bindings.cs b/Modules/UnityWebRequest/Public/UploadHandler/UploadHandler.bindings.cs index 532ac20137..e9b1607af8 100644 --- a/Modules/UnityWebRequest/Public/UploadHandler/UploadHandler.bindings.cs +++ b/Modules/UnityWebRequest/Public/UploadHandler/UploadHandler.bindings.cs @@ -21,7 +21,7 @@ public class UploadHandler : IDisposable internal IntPtr m_Ptr; [NativeMethod(IsThreadSafe = true)] - private extern void Release(); + private extern void ReleaseFromScripting(); internal UploadHandler() {} @@ -34,7 +34,7 @@ public virtual void Dispose() { if (m_Ptr != IntPtr.Zero) { - Release(); + ReleaseFromScripting(); m_Ptr = IntPtr.Zero; } } diff --git a/Modules/VFXEditor/Public/ScriptBindings/VisualEffectResource.bindings.cs b/Modules/VFXEditor/Public/ScriptBindings/VisualEffectResource.bindings.cs index 074f866002..fe54b3713c 100644 --- a/Modules/VFXEditor/Public/ScriptBindings/VisualEffectResource.bindings.cs +++ b/Modules/VFXEditor/Public/ScriptBindings/VisualEffectResource.bindings.cs @@ -73,9 +73,10 @@ internal struct VFXGPUBufferDesc { public VFXLayoutElementDesc[] layout; public uint capacity; - public ComputeBufferType type; + public GraphicsBuffer.Target target; public uint size; public uint stride; + public ComputeBufferMode mode; } internal struct VFXTemporaryGPUBufferDesc diff --git a/Projects/CSharp/UnityEditor.csproj b/Projects/CSharp/UnityEditor.csproj index f2d8ef8f3f..cca75a3565 100644 --- a/Projects/CSharp/UnityEditor.csproj +++ b/Projects/CSharp/UnityEditor.csproj @@ -7,7 +7,7 @@ false true false - $(DefineConstants);ALLOW_IMPLICIT_INTERNAL_VISIBILITY;COMBINED_ASSEMBLIES;DEBUGGER_LISTENS_FIXED_PORT;DEBUGMODE=1;DISABLE_SKETCHUP_IMPORTER=1;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;ENABLE_ALTERNATIVE_LISTEN_PORT;ENABLE_AMD;ENABLE_AR;ENABLE_AUDIO;ENABLE_AUDIO_MANAGER_BASED_SCHEDULING;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_CLOUD_LICENSE;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_SERVICES_COLLAB_TESTING;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLUSTERINPUT;ENABLE_CLUSTER_SYNC;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_EDITOR_GAME_SERVICES;ENABLE_EDITOR_HUB_LICENSE;ENABLE_ETC_COMPRESSION;ENABLE_EVENT_QUEUE;ENABLE_GAMECENTER_API;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_HOLOLENS_MODULE_API;ENABLE_LZMA;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_UNITYTLS;ENABLE_MARSHALLING_TESTS;ENABLE_MICROPHONE;ENABLE_MOVIES;ENABLE_MULTIPLE_DISPLAYS;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_NETWORK;ENABLE_NVIDIA;ENABLE_PHYSICS;ENABLE_RUNTIME_GI;ENABLE_SCRIPTING_GC_WBARRIERS;ENABLE_TEXTURE_STREAMING;ENABLE_UNITYEVENTS;ENABLE_UNITYWEBREQUEST;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_VERSION_CONTROL_INTEGRATION;ENABLE_VIDEO;ENABLE_VIRTUALTEXTURING;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WEBSOCKET_CLIENT;ENABLE_WEBSOCKET_HOST;ENABLE_WWW;INCLUDE_DYNAMIC_GI;PLATFORM_SUPPORTS_GAMEPAD_AUDIO;PLATFORM_SUPPORTS_MONO;PLAYERCONNECTION_LISTENS_FIXED_PORT;RENDER_SOFTWARE_CURSOR;TEXTCORE_1_0_OR_NEWER;TRACE;UNITY_ANDROID_API;UNITY_ASSEMBLIES_API;UNITY_ASSERTIONS;UNITY_CAN_SHOW_SPLASH_SCREEN;UNITY_EDITOR;UNITY_EDITOR_API;UNITY_EDITOR_LINUX;UNITY_IPHONE_API;UNITY_METRO_API;UNITY_PS4_API;UNITY_PS5_API;UNITY_STANDALONE_LINUX_API;UNITY_STANDALONE_OSX_API;UNITY_STANDALONE_WIN_API;UNITY_TINYPROFILING_INTERNAL;UNITY_TVOS_API;UNITY_UNITYADS_API;UNITY_WEBGL_API;USE_PROPERTY_DATABASE;USE_QUERY_BUILDER;USE_SEARCH_ENGINE_API;USE_SEARCH_MODULE + $(DefineConstants);ALLOW_IMPLICIT_INTERNAL_VISIBILITY;COMBINED_ASSEMBLIES;DEBUGGER_LISTENS_FIXED_PORT;DEBUGMODE=1;DISABLE_SKETCHUP_IMPORTER=1;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;ENABLE_ALTERNATIVE_LISTEN_PORT;ENABLE_AMD;ENABLE_AR;ENABLE_AUDIO;ENABLE_AUDIO_MANAGER_BASED_SCHEDULING;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_CLOUD_LICENSE;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLUSTERINPUT;ENABLE_CLUSTER_SYNC;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_EDITOR_GAME_SERVICES;ENABLE_EDITOR_HUB_LICENSE;ENABLE_ETC_COMPRESSION;ENABLE_EVENT_QUEUE;ENABLE_GAMECENTER_API;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_HOLOLENS_MODULE_API;ENABLE_LZMA;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_UNITYTLS;ENABLE_MARSHALLING_TESTS;ENABLE_MICROPHONE;ENABLE_MOVIES;ENABLE_MULTIPLE_DISPLAYS;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_NETWORK;ENABLE_NVIDIA;ENABLE_PHYSICS;ENABLE_RUNTIME_GI;ENABLE_SCRIPTING_GC_WBARRIERS;ENABLE_TEXTURE_STREAMING;ENABLE_UNITYEVENTS;ENABLE_UNITYWEBREQUEST;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_VERSION_CONTROL_INTEGRATION;ENABLE_VIDEO;ENABLE_VIRTUALTEXTURING;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WEBSOCKET_CLIENT;ENABLE_WEBSOCKET_HOST;ENABLE_WWW;INCLUDE_DYNAMIC_GI;PLATFORM_SUPPORTS_GAMEPAD_AUDIO;PLATFORM_SUPPORTS_MONO;PLAYERCONNECTION_LISTENS_FIXED_PORT;RENDER_SOFTWARE_CURSOR;TEXTCORE_1_0_OR_NEWER;TRACE;UNITY_ANDROID_API;UNITY_ASSEMBLIES_API;UNITY_ASSERTIONS;UNITY_CAN_SHOW_SPLASH_SCREEN;UNITY_EDITOR;UNITY_EDITOR_API;UNITY_EDITOR_LINUX;UNITY_IPHONE_API;UNITY_METRO_API;UNITY_PS4_API;UNITY_PS5_API;UNITY_STANDALONE_LINUX_API;UNITY_STANDALONE_OSX_API;UNITY_STANDALONE_WIN_API;UNITY_TINYPROFILING_INTERNAL;UNITY_TVOS_API;UNITY_UNITYADS_API;UNITY_WEBGL_API;USE_PROPERTY_DATABASE;USE_QUERY_BUILDER;USE_SEARCH_ENGINE_API;USE_SEARCH_MODULE latest 1701;0169;0649;0626 @@ -735,6 +735,9 @@ Editor\Mono\BuildProfile\BuildProfile.cs + + Editor\Mono\BuildProfile\BuildProfileAPI.cs + Editor\Mono\BuildProfile\BuildProfileCLI.cs @@ -855,9 +858,6 @@ Editor\Mono\Collab\AssetAccess.cs - - Editor\Mono\Collab\CollabChangeItem.cs - Editor\Mono\Collab\CollabTesting.cs @@ -3267,6 +3267,9 @@ Editor\Mono\ScriptableWizard.cs + + Editor\Mono\ScriptingDefinesHelper.cs + Editor\Mono\Scripting\APIUpdater\APIUpdaterAssemblyHelper.cs diff --git a/Projects/CSharp/UnityEngine.csproj b/Projects/CSharp/UnityEngine.csproj index 8f5934adff..4dae442502 100644 --- a/Projects/CSharp/UnityEngine.csproj +++ b/Projects/CSharp/UnityEngine.csproj @@ -7,7 +7,7 @@ false true false - $(DefineConstants);ALLOW_IMPLICIT_INTERNAL_VISIBILITY;COMBINED_ASSEMBLIES;DEBUGGER_LISTENS_FIXED_PORT;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;ENABLE_ALTERNATIVE_LISTEN_PORT;ENABLE_AR;ENABLE_AUDIO;ENABLE_AUDIO_MANAGER_BASED_SCHEDULING;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_CLOUD_LICENSE;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_SERVICES_COLLAB_TESTING;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_DUMMYTLS=1;ENABLE_EDITOR_GAME_SERVICES;ENABLE_EDITOR_HUB_LICENSE;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_HOLOLENS_MODULE_API;ENABLE_LZMA;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_UNITYTLS;ENABLE_MARSHALLING_TESTS;ENABLE_MBEDTLS=1;ENABLE_MICROPHONE;ENABLE_MOVIES;ENABLE_MULTIPLE_DISPLAYS;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_NETWORK;ENABLE_PHYSICS;ENABLE_SCRIPTING_GC_WBARRIERS;ENABLE_TEXTURE_STREAMING;ENABLE_UNITYEVENTS;ENABLE_UNITYWEBREQUEST;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_VERSION_CONTROL_INTEGRATION;ENABLE_VIDEO;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WEBSOCKET_CLIENT;ENABLE_WWW;GRAPHINE_BUILD_STATIC=1;GRAPHINE_BUILD_UNITY=1;HAVE_FREETYPE;ICU_NO_USER_DATA_OVERRIDE;INCLUDE_DYNAMIC_GI;MBEDTLS_PSK_MAX_LEN=64;MBEDTLS_USER_CONFIG=1;NV_CLOTH_IMPORT=;PLATFORM_SUPPORTS_MONO;PLAYERCONNECTION_LISTENS_FIXED_PORT;RENDER_SOFTWARE_CURSOR;TEXTCORE_1_0_OR_NEWER;TRACE;UCONFIG_NO_COLLATION;UCONFIG_NO_CONVERSION;UCONFIG_NO_FILE_IO;UCONFIG_NO_FORMATTING;UCONFIG_NO_IDNA;UCONFIG_NO_REGULAR_EXPRESSIONS;UCONFIG_NO_SERVICE;UCONFIG_NO_TRANSLITERATION;UMBRA_IS_TARGET=0;UMBRA_OS=UMBRA_LINUX;UNITY_ANDROID_API;UNITY_ASSEMBLIES_API;UNITY_ASSERTIONS;UNITY_CURL_BUILT_IN;UNITY_EDITOR;UNITY_EDITOR_API;UNITY_IPHONE_API;UNITY_METRO_API;UNITY_PS4_API;UNITY_PS5_API;UNITY_STANDALONE_LINUX_API;UNITY_STANDALONE_OSX_API;UNITY_STANDALONE_WIN_API;UNITY_TLS_INTERFACE_UNITY=1;UNITY_TVOS_API;UNITY_WEBGL_API;USE_PROPERTIES_MODULE;U_COMMON_IMPLEMENTATION;U_ENABLE_DYLOAD=0;U_STATIC_IMPLEMENTATION=1;VPX_MULTITHREAD;VPX_X86;VPX_X86_64;_HAS_EXCEPTIONS=0 + $(DefineConstants);ALLOW_IMPLICIT_INTERNAL_VISIBILITY;COMBINED_ASSEMBLIES;DEBUGGER_LISTENS_FIXED_PORT;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;ENABLE_ALTERNATIVE_LISTEN_PORT;ENABLE_AR;ENABLE_AUDIO;ENABLE_AUDIO_MANAGER_BASED_SCHEDULING;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_CLOUD_LICENSE;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_DUMMYTLS=1;ENABLE_EDITOR_GAME_SERVICES;ENABLE_EDITOR_HUB_LICENSE;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_HOLOLENS_MODULE_API;ENABLE_LZMA;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_UNITYTLS;ENABLE_MARSHALLING_TESTS;ENABLE_MBEDTLS=1;ENABLE_MICROPHONE;ENABLE_MOVIES;ENABLE_MULTIPLE_DISPLAYS;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_NETWORK;ENABLE_PHYSICS;ENABLE_SCRIPTING_GC_WBARRIERS;ENABLE_TEXTURE_STREAMING;ENABLE_UNITYEVENTS;ENABLE_UNITYWEBREQUEST;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_VERSION_CONTROL_INTEGRATION;ENABLE_VIDEO;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WEBSOCKET_CLIENT;ENABLE_WWW;GRAPHINE_BUILD_STATIC=1;GRAPHINE_BUILD_UNITY=1;HAVE_FREETYPE;ICU_NO_USER_DATA_OVERRIDE;INCLUDE_DYNAMIC_GI;MBEDTLS_PSK_MAX_LEN=64;MBEDTLS_USER_CONFIG=1;NV_CLOTH_IMPORT=;PLATFORM_SUPPORTS_MONO;PLAYERCONNECTION_LISTENS_FIXED_PORT;RENDER_SOFTWARE_CURSOR;TEXTCORE_1_0_OR_NEWER;TRACE;UCONFIG_NO_COLLATION;UCONFIG_NO_CONVERSION;UCONFIG_NO_FILE_IO;UCONFIG_NO_FORMATTING;UCONFIG_NO_IDNA;UCONFIG_NO_REGULAR_EXPRESSIONS;UCONFIG_NO_SERVICE;UCONFIG_NO_TRANSLITERATION;UMBRA_IS_TARGET=0;UMBRA_OS=UMBRA_LINUX;UNITY_ANDROID_API;UNITY_ASSEMBLIES_API;UNITY_ASSERTIONS;UNITY_CURL_BUILT_IN;UNITY_EDITOR;UNITY_EDITOR_API;UNITY_IPHONE_API;UNITY_METRO_API;UNITY_PS4_API;UNITY_PS5_API;UNITY_STANDALONE_LINUX_API;UNITY_STANDALONE_OSX_API;UNITY_STANDALONE_WIN_API;UNITY_TLS_INTERFACE_UNITY=1;UNITY_TVOS_API;UNITY_WEBGL_API;USE_PROPERTIES_MODULE;U_COMMON_IMPLEMENTATION;U_ENABLE_DYLOAD=0;U_STATIC_IMPLEMENTATION=1;VPX_MULTITHREAD;VPX_X86;VPX_X86_64;_HAS_EXCEPTIONS=0 latest 1701;0626 diff --git a/README.md b/README.md index e35eaaddc0..2fd1237d67 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Unity 2023.3.0b10 C# reference source code +## Unity 6000.0.0b11 C# reference source code The C# part of the Unity engine and editor source code. May be used for reference purposes only. diff --git a/Runtime/Export/Rendering/GPUDrivenRendering.bindings.cs b/Runtime/Export/Rendering/GPUDrivenRendering.bindings.cs index b0ef2dcc76..1034df54df 100644 --- a/Runtime/Export/Rendering/GPUDrivenRendering.bindings.cs +++ b/Runtime/Export/Rendering/GPUDrivenRendering.bindings.cs @@ -105,6 +105,7 @@ private void Destroy() var materialsCount = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(nativeData.materialsCount, nativeData.rendererGroupCount, Allocator.Invalid); var instancesOffset = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(null, 0, Allocator.Invalid); var instancesCount = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(null, 0, Allocator.Invalid); + var editorData = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(nativeData.editorData, nativeData.rendererGroupCount, Allocator.Invalid); var invalidRendererGroupID = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(nativeData.invalidRendererGroupID, nativeData.invalidRendererGroupIDCount, Allocator.Invalid); @@ -139,6 +140,7 @@ private void Destroy() NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref materialsCount, AtomicSafetyHandle.Create()); NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref instancesOffset, AtomicSafetyHandle.Create()); NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref instancesCount, AtomicSafetyHandle.Create()); + NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref editorData, AtomicSafetyHandle.Create()); NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref invalidRendererGroupID, AtomicSafetyHandle.Create()); NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref localToWorldMatrix, AtomicSafetyHandle.Create()); NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref prevLocalToWorldMatrix, AtomicSafetyHandle.Create()); @@ -168,6 +170,7 @@ private void Destroy() materialsCount = materialsCount, instancesOffset = instancesOffset, instancesCount = instancesCount, + editorData = editorData, invalidRendererGroupID = invalidRendererGroupID, localToWorldMatrix = localToWorldMatrix, prevLocalToWorldMatrix = prevLocalToWorldMatrix, @@ -199,6 +202,7 @@ private void Destroy() AtomicSafetyHandle.Release(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(materialsCount)); AtomicSafetyHandle.Release(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(instancesOffset)); AtomicSafetyHandle.Release(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(instancesCount)); + AtomicSafetyHandle.Release(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(editorData)); AtomicSafetyHandle.Release(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(invalidRendererGroupID)); AtomicSafetyHandle.Release(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(localToWorldMatrix)); AtomicSafetyHandle.Release(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(prevLocalToWorldMatrix)); @@ -301,6 +305,13 @@ internal static class BindingsMarshaller } } + [UsedByNativeCode] + [StructLayout(LayoutKind.Sequential)] + internal struct GPUDrivenRendererEditorData + { + public ulong sceneCullingMask; + } + [UsedByNativeCode] [StructLayout(LayoutKind.Sequential)] internal unsafe struct GPUDrivenRendererGroupDataNative @@ -320,6 +331,7 @@ internal unsafe struct GPUDrivenRendererGroupDataNative public short* materialsCount; public int* instancesOffset; public int* instancesCount; + public GPUDrivenRendererEditorData* editorData; public int rendererGroupCount; public int* invalidRendererGroupID; @@ -476,6 +488,7 @@ internal struct GPUDrivenRendererGroupData // Used for indexing multiple instances per a renderer group. public NativeArray instancesOffset; public NativeArray instancesCount; + public NativeArray editorData; /// /// Invalid or disabled Render Group IDs. diff --git a/Runtime/Export/Scripting/Awaitable.DelayedCall.cs b/Runtime/Export/Scripting/Awaitable.DelayedCall.cs index 3a8da3eb83..4879365071 100644 --- a/Runtime/Export/Scripting/Awaitable.DelayedCall.cs +++ b/Runtime/Export/Scripting/Awaitable.DelayedCall.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; -using UnityEditor; using UnityEngine.Bindings; using UnityEngine.Scripting; @@ -22,7 +21,7 @@ public static Awaitable NextFrameAsync(CancellationToken cancellationToken = def EnsureDelayedCallWiredUp(); var awaitable = Awaitable.NewManagedAwaitable(); - _nextFrameAwaitables.Add(awaitable); + _nextFrameAwaitables.Add(awaitable, Time.frameCount + 1); if (cancellationToken.CanBeCanceled) { WireupCancellation(awaitable, cancellationToken); @@ -53,7 +52,7 @@ public static Awaitable EndOfFrameAsync(CancellationToken cancellationToken = de EnsureDelayedCallWiredUp(); var awaitable = Awaitable.NewManagedAwaitable(); - _endOfFrameAwaitables.Add(awaitable); + _endOfFrameAwaitables.Add(awaitable, -1); if (cancellationToken.CanBeCanceled) { WireupCancellation(awaitable, cancellationToken); @@ -86,10 +85,22 @@ static void OnDelayedCallManagerCleared() private static readonly DoubleBufferedAwaitableList _nextFrameAwaitables = new(); private static readonly DoubleBufferedAwaitableList _endOfFrameAwaitables = new(); + private struct AwaitableAndFrameIndex + { + public Awaitable Awaitable { get; } + public int FrameIndex { get; } + + public AwaitableAndFrameIndex(Awaitable awaitable, int frameIndex) + { + Awaitable = awaitable; + FrameIndex = frameIndex; + } + } + class DoubleBufferedAwaitableList { - private List _awaitables = new(); - private List _scratch = new(); + private List _awaitables = new(); + private List _scratch = new(); public void SwapAndComplete() { var oldScratch = _scratch; @@ -100,8 +111,17 @@ public void SwapAndComplete() { foreach (var item in toIterate) { - if (!item.IsDettachedOrCompleted) // might already have been completed - item.RaiseManagedCompletion(); + if (!item.Awaitable.IsDettachedOrCompleted) + { + if (Time.frameCount >= item.FrameIndex || item.FrameIndex == -1) + { + item.Awaitable.RaiseManagedCompletion(); + } + else + { + oldScratch.Add(item); + } + } } } finally @@ -110,9 +130,9 @@ public void SwapAndComplete() } } - public void Add(Awaitable item) + public void Add(Awaitable item, int frameIndex) { - _awaitables.Add(item); + _awaitables.Add(new AwaitableAndFrameIndex(item, frameIndex)); } public void Clear() { diff --git a/Runtime/Export/iOS/iOSReplayKit.bindings.cs b/Runtime/Export/iOS/iOSReplayKit.bindings.cs index 932359a715..ba3902a60f 100644 --- a/Runtime/Export/iOS/iOSReplayKit.bindings.cs +++ b/Runtime/Export/iOS/iOSReplayKit.bindings.cs @@ -2,11 +2,13 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License +using System; using UnityEngine.Bindings; using uei = UnityEngine.Internal; namespace UnityEngine.Apple.ReplayKit { + [Obsolete("ReplayKit will be removed in future version of Unity")] [NativeHeader("PlatformDependent/iPhonePlayer/IOSScriptBindings.h")] public static partial class ReplayKit { From 78110bed21e5cf5423b157986d33d8ff71293569 Mon Sep 17 00:00:00 2001 From: Unity Technologies Date: Tue, 19 Mar 2024 19:32:02 +0000 Subject: [PATCH 02/89] Unity 6000.0.0b12 C# reference source code --- Editor/Mono/AssemblyInfo/AssemblyInfo.cs | 4 + Editor/Mono/BuildPlayerWindow.cs | 2 +- .../Mono/BuildProfile/BuildProfileContext.cs | 7 + .../BuildProfile/SharedPlatformSettings.cs | 41 +- Editor/Mono/ConsoleWindow.cs | 5 + Editor/Mono/Delayer.cs | 50 +- Editor/Mono/EditorApplication.bindings.cs | 7 + .../Mono/EditorUserBuildSettings.bindings.cs | 4 +- .../EditorPluginImporterExtension.cs | 65 +- Editor/Mono/Inspector/Core/PreviewWindow.cs | 6 +- Editor/Mono/Inspector/Core/PropertyEditor.cs | 68 +- .../Modules/DefaultBuildProfileExtension.cs | 2 +- Editor/Mono/PlayerSettingsSwitch.bindings.cs | 1 - ...layerSettingsSwitch.deprecated.bindings.cs | 340 ++++++++++ Editor/Mono/Prefabs/PrefabImporterEditor.cs | 3 + Editor/Mono/Prefabs/PrefabUtility.cs | 2 +- .../PreferencesSettingsProviders.cs | 2 +- .../Mono/UIElements/UIBuildAnalyticsEvent.cs | 138 +++++ .../AndroidJNI/AndroidAssetPacks.bindings.cs | 19 +- Modules/AndroidJNI/AndroidGame.bindings.cs | 19 + Modules/AndroidJNI/AndroidGame.cs | 2 +- .../Public/ScriptBindings/Audio.bindings.cs | 2 + .../BuildProfileEditor/BuildProfileWindow.cs | 9 +- .../ToolbarElements/PlayModeButtons.cs | 2 +- Modules/IMGUI/RuntimeTextSettings.cs | 17 + .../UI/Data/Events/Base/NotificationType.cs | 1 + .../Events/BorrowFeatureStatusNotification.cs | 26 + .../Events/LicenseNotificationDispatcher.cs | 13 + .../Editor/Extensions/ExtensionManager.cs | 14 +- .../Editor/Extensions/PackageSelectionArgs.cs | 4 +- .../Editor/Services/Interfaces/IPage.cs | 6 +- .../Services/Packages/Actions/AddAction.cs | 7 +- .../Packages/Actions/CancelDownloadAction.cs | 6 +- .../Packages/Actions/DeselectAction.cs | 9 +- .../Packages/Actions/DownloadActionBase.cs | 6 +- .../Packages/Actions/PackageAction.cs | 6 +- .../Services/Packages/Actions/RemoveAction.cs | 16 +- .../Packages/Actions/RemoveImportedAction.cs | 6 +- .../Services/Packages/Actions/UnlockAction.cs | 7 +- .../Services/Packages/Actions/UpdateAction.cs | 6 +- .../Packages/PackageAndVersionIdPair.cs | 21 - .../Services/Packages/PackageDatabase.cs | 31 +- .../Packages/PackageOperationDispatcher.cs | 8 +- .../Editor/Services/Pages/BasePage.cs | 36 +- .../Editor/Services/Pages/PageManager.cs | 16 +- .../Editor/Services/Pages/PageSelection.cs | 69 +-- .../Services/Pages/PageTypes/MyAssetsPage.cs | 4 +- .../Editor/UI/AddPackageByNameDropdown.cs | 2 +- .../UI/Common/InspectorSelectionHandler.cs | 33 +- .../Editor/UI/InProgressDropdown.cs | 2 +- .../UI/MultiSelect/CheckUpdateFoldout.cs | 6 +- .../MultiSelect/IMultiSelectFoldoutElement.cs | 4 +- .../UI/MultiSelect/InstallFoldoutGroup.cs | 10 +- .../UI/MultiSelect/MultiSelectDetails.cs | 28 +- .../UI/MultiSelect/MultiSelectFoldout.cs | 22 +- .../UI/MultiSelect/MultiSelectFoldoutGroup.cs | 14 +- .../Editor/UI/MultiSelect/MultiSelectItem.cs | 19 +- .../UI/MultiSelect/RemoveFoldoutGroup.cs | 8 +- .../MultiSelect/RemoveImportedFoldoutGroup.cs | 4 +- .../Editor/UI/MultiSelect/UnlockFoldout.cs | 6 +- .../Editor/UI/MultiSelect/UpdateFoldout.cs | 6 +- .../UI/MultiSelect/UpdateFoldoutGroup.cs | 6 +- .../Editor/UI/PackageDetails.cs | 25 +- .../Editor/UI/PackageDetailsBody.cs | 4 +- .../Editor/UI/PackageDetailsHeader.cs | 6 +- .../PackageDetailsVersionsTab.cs | 17 +- .../PackageManagerUI/Editor/UI/PackageItem.cs | 18 +- .../PackageManagerUI/Editor/UI/PackageList.cs | 8 +- .../Editor/UI/PackageListScrollView.cs | 23 +- .../Editor/UI/PackageListView.cs | 8 +- .../Editor/UI/PackageManagerWindowRoot.cs | 14 +- .../Editor/UI/PackageSelectionEditor.cs | 10 +- .../Editor/UI/PackageSelectionObject.cs | 3 - .../UI/ToolBar/LegacyFormatDropdownButton.cs | 2 +- .../Editor/UI/ToolBar/PackageToolBar.cs | 6 +- .../Editor/UI/ToolBar/PackageToolBarButton.cs | 9 +- Modules/Properties/Runtime/AssemblyInfo.cs | 1 + .../Properties/ReflectedMemberProperty.cs | 12 +- .../PropertyBags/Internal/PropertyBagStore.cs | 10 +- .../Internal/ReflectionUtilities.cs | 20 + .../PropertyDatabase/PropertyDatabase.cs | 2 +- .../Editor/UITK/SearchBaseCollectionView.cs | 2 +- .../QuickSearch/Editor/UITK/SearchGridView.cs | 2 +- .../Managed/FontEngine.bindings.cs | 13 - .../Managed/TextAssets/FontAsset.cs | 106 +++- .../FontAsset/FontAssetAtlasPopulation.cs | 8 +- .../TextAssets/FontAsset/NativeFontAsset.cs | 11 +- .../Managed/TextAssets/FontAssetUtilities.cs | 25 +- .../Managed/TextAssets/TextSettings.cs | 38 +- .../TextGenerator/TextGeneratorPrepare.cs | 51 +- .../TextRendering/TextRendering.bindings.cs | 2 + .../Editor/Builder/BuilderSelection.cs | 22 + .../Document/BuilderDocumentOpenUXML.cs | 15 + .../Builder/Explorer/BuilderExplorerItem.cs | 6 +- .../Builder/Explorer/BuilderHierarchy.cs | 6 +- .../Builder/Explorer/BuilderStyleSheets.cs | 2 +- .../BuilderBindingUxmlAtttributesView.cs | 4 +- .../Inspector/Binding/BuilderBindingWindow.cs | 4 + .../Binding/BuilderDataSourceAndPathView.cs | 27 +- .../Binding/BuilderDataSourcePathCompleter.cs | 25 +- .../Builder/Inspector/BuilderInspector.cs | 13 + .../Inspector/BuilderInspectorHeader.cs | 1 + .../Inspector/BuilderInspectorPreview.cs | 16 +- .../Editor/Builder/Library/BuilderLibrary.cs | 1 - .../BuilderUxmlAttributesView.cs | 2 +- .../Builder/Viewport/BuilderViewport.cs | 2 +- .../ElementHierarchyView.cs | 2 +- .../UIElements/Core/Bindings/DataBinding.cs | 2 +- .../Core/Controls/InputField/BaseField.cs | 8 +- .../Core/Controls/MultiColumn/Column.cs | 17 +- .../Core/Controls/MultiColumn/ColumnLayout.cs | 585 +++++++++++------- .../MultiColumnCollectionHeader.cs | 4 +- .../UIElements/Core/Controls/ScrollView.cs | 39 +- .../ToggleButtonGroup/ToggleButtonGroup.cs | 6 + Modules/UIElements/Core/EventDispatcher.cs | 6 +- Modules/UIElements/Core/FocusController.cs | 1 + .../Native/Renderer/UIPainter2D.bindings.cs | 6 +- .../UIElements/Core/Renderer/UIRPainter2D.cs | 16 +- .../Core/StyleSheets/StyleVariable.cs | 32 +- .../Core/VisualElementDataBinding.cs | 2 +- .../Bindings/SerializedDefaultEnumBinding.cs | 14 +- .../Bindings/SerializedIsExpandedBinding.cs | 11 +- .../Bindings/SerializedManagedEnumBinding.cs | 2 +- .../Bindings/SerializedObjectBinding.cs | 14 +- .../Bindings/SerializedObjectBindingBase.cs | 30 +- .../SerializedObjectBindingToBaseField.cs | 16 + ...SerializedObjectStringConversionBinding.cs | 14 - .../UIElementsEditorInitialization.cs | 2 +- .../UIElementsViewImporter.cs | 68 +- .../UIElementsSamples.cs | 62 +- .../Public/DownloadHandlerTexture.bindings.cs | 67 +- .../UnityWebRequestTexture.cs | 10 + Projects/CSharp/UnityEditor.csproj | 12 +- Projects/CSharp/UnityEngine.csproj | 5 +- README.md | 2 +- 135 files changed, 2064 insertions(+), 898 deletions(-) create mode 100644 Editor/Mono/PlayerSettingsSwitch.deprecated.bindings.cs create mode 100644 Editor/Mono/UIElements/UIBuildAnalyticsEvent.cs create mode 100644 Modules/Licensing/UI/Data/Events/BorrowFeatureStatusNotification.cs delete mode 100644 Modules/PackageManagerUI/Editor/Services/Packages/PackageAndVersionIdPair.cs create mode 100644 Modules/Properties/Runtime/Reflection/Internal/ReflectionUtilities.cs diff --git a/Editor/Mono/AssemblyInfo/AssemblyInfo.cs b/Editor/Mono/AssemblyInfo/AssemblyInfo.cs index 52cfe0e7b3..8a0bc40e87 100644 --- a/Editor/Mono/AssemblyInfo/AssemblyInfo.cs +++ b/Editor/Mono/AssemblyInfo/AssemblyInfo.cs @@ -54,6 +54,7 @@ [assembly: InternalsVisibleTo("UnityEditor.PS5.Extensions")] [assembly: InternalsVisibleTo("UnityEditor.Switch.Extensions")] [assembly: InternalsVisibleTo("UnityEditor.WebGL.Extensions")] +[assembly: InternalsVisibleTo("Unity.Automation.Players.WebGL")] [assembly: InternalsVisibleTo("Unity.WebGL.Extensions")] [assembly: InternalsVisibleTo("UnityEditor.LinuxStandalone.Extensions")] [assembly: InternalsVisibleTo("UnityEditor.CloudRendering.Extensions")] @@ -149,6 +150,9 @@ [assembly: InternalsVisibleTo("Unity.Entities.Build")] +[assembly: InternalsVisibleTo("Unity.Muse.Common.Bridge")] +[assembly: InternalsVisibleTo("Unity.Muse.Chat.Bridge")] + [assembly: InternalsVisibleTo("Unity.Scenes")] // This should move with the AnimationWindow to a module at some point diff --git a/Editor/Mono/BuildPlayerWindow.cs b/Editor/Mono/BuildPlayerWindow.cs index 9924e77b6c..8ec3a359db 100644 --- a/Editor/Mono/BuildPlayerWindow.cs +++ b/Editor/Mono/BuildPlayerWindow.cs @@ -70,7 +70,7 @@ public GUIContent GetDownloadErrorForTarget(BuildTarget target) public GUIContent autoconnectProfiler = EditorGUIUtility.TrTextContent("Autoconnect Profiler", "When the build is started, an open Profiler Window will automatically connect to the Player and start profiling. The \"Build And Run\" option will also automatically open the Profiler Window."); public GUIContent autoconnectProfilerDisabled = EditorGUIUtility.TrTextContent("Autoconnect Profiler", "Profiling is only enabled in a Development Player."); public GUIContent buildWithDeepProfiler = EditorGUIUtility.TrTextContent("Deep Profiling Support", "Build Player with Deep Profiling Support. This might affect Player performance."); - public GUIContent buildWithDeepProfilerDisabled = EditorGUIUtility.TrTextContent("Deep Profiling", "Profiling is only enabled in a Development Player."); + public GUIContent buildWithDeepProfilerDisabled = EditorGUIUtility.TrTextContent("Deep Profiling Support", "Profiling is only enabled in a Development Player."); public GUIContent allowDebugging = EditorGUIUtility.TrTextContent("Script Debugging", "Enable this setting to allow your script code to be debugged."); public GUIContent waitForManagedDebugger = EditorGUIUtility.TrTextContent("Wait For Managed Debugger", "Show a dialog where you can attach a managed debugger before any script execution. Can also use volume Up or Down button to confirm on Android."); public GUIContent managedDebuggerFixedPort = EditorGUIUtility.TrTextContent("Managed Debugger Fixed Port", "Use the specified port to attach to the managed debugger. If 0, the port will be automatically selected."); diff --git a/Editor/Mono/BuildProfile/BuildProfileContext.cs b/Editor/Mono/BuildProfile/BuildProfileContext.cs index 6fe9260060..2576550357 100644 --- a/Editor/Mono/BuildProfile/BuildProfileContext.cs +++ b/Editor/Mono/BuildProfile/BuildProfileContext.cs @@ -400,6 +400,13 @@ BuildProfile GetOrCreateClassicPlatformBuildProfile(BuildTarget target, Standalo // can access the classic profiles when copying the settings EditorUserBuildSettings.CopyToBuildProfile(buildProfile); + // Classic profile's shared settings should be populated by the existing shared profile + if (sharedProfile != null) + { + var sharedSettings = sharedProfile.platformBuildProfile as SharedPlatformSettings; + sharedSettings?.CopySharedSettingsToBuildProfile(buildProfile); + } + // Created profile can also be populated by settings on the managed side string module = BuildTargetDiscovery.GetModuleNameForBuildTarget(buildProfile.buildTarget); var extension = ModuleManager.GetBuildProfileExtension(module); diff --git a/Editor/Mono/BuildProfile/SharedPlatformSettings.cs b/Editor/Mono/BuildProfile/SharedPlatformSettings.cs index d31cc41f38..6885061a80 100644 --- a/Editor/Mono/BuildProfile/SharedPlatformSettings.cs +++ b/Editor/Mono/BuildProfile/SharedPlatformSettings.cs @@ -401,7 +401,7 @@ void SyncSharedSettings(string name) break; case k_SettingCompressionType: { - var isStandalone = BuildTargetDiscovery.PlatformHasFlag(profile.buildTarget, TargetAttributes.IsStandalonePlatform); + var isStandalone = BuildProfileModuleUtil.IsStandalonePlatform(profile.buildTarget); if (isStandalone) { platformSettingsBase.compressionType = compressionType; @@ -453,5 +453,44 @@ void SyncSharedSettings(string name) } } } + + // + // Copy shared settings to a build profile. + // + public void CopySharedSettingsToBuildProfile(BuildProfile profile) + { + if (profile == null) + return; + + var platformSettings = profile.platformBuildProfile; + if (platformSettings == null) + return; + + platformSettings.development = development; + platformSettings.connectProfiler = connectProfiler; + platformSettings.buildWithDeepProfilingSupport = buildWithDeepProfilingSupport; + platformSettings.allowDebugging = allowDebugging; + platformSettings.waitForManagedDebugger = waitForManagedDebugger; + platformSettings.managedDebuggerFixedPort = managedDebuggerFixedPort; + platformSettings.explicitNullChecks = explicitNullChecks; + platformSettings.explicitDivideByZeroChecks = explicitDivideByZeroChecks; + platformSettings.explicitArrayBoundsChecks = explicitArrayBoundsChecks; + if (BuildProfileModuleUtil.IsStandalonePlatform(profile.buildTarget)) + platformSettings.compressionType = compressionType; + platformSettings.installInBuildFolder = installInBuildFolder; + platformSettings.SetSharedSetting(k_SettingWindowsDevicePortalAddress, windowsDevicePortalAddress); + platformSettings.SetSharedSetting(k_SettingWindowsDevicePortalUsername, windowsDevicePortalUsername); + platformSettings.SetSharedSetting(k_SettingWindowsDevicePortalPassword, windowsDevicePortalPassword); + platformSettings.SetSharedSetting(k_SettingForceInstallation, forceInstallation.ToString().ToLower()); + platformSettings.SetSharedSetting(k_SettingiOSXcodeBuildConfig, iOSXcodeBuildConfig.ToString()); + platformSettings.SetSharedSetting(k_SettingSymlinkSources, symlinkSources.ToString().ToLower()); + platformSettings.SetSharedSetting(k_SettingPreferredXcode, preferredXcode); + platformSettings.SetSharedSetting(k_SettingSymlinkTrampoline, symlinkTrampoline.ToString().ToLower()); + platformSettings.SetSharedSetting(k_SettingRemoteDeviceInfo, remoteDeviceInfo.ToString().ToLower()); + platformSettings.SetSharedSetting(k_SettingRemoteDeviceAddress, remoteDeviceAddress); + platformSettings.SetSharedSetting(k_SettingRemoteDeviceUsername, remoteDeviceUsername); + platformSettings.SetSharedSetting(k_SettingRemoteDeviceExports, remoteDeviceExports); + platformSettings.SetSharedSetting(k_SettingPathOnRemoteDevice, pathOnRemoteDevice); + } } } diff --git a/Editor/Mono/ConsoleWindow.cs b/Editor/Mono/ConsoleWindow.cs index 4086585822..18c00d4e43 100644 --- a/Editor/Mono/ConsoleWindow.cs +++ b/Editor/Mono/ConsoleWindow.cs @@ -745,6 +745,7 @@ const bool { SetActiveEntry(entry); m_LastActiveEntryIndex = entry.globalLineIndex; + activeEntryChanged?.Invoke(); } @@ -1090,6 +1091,8 @@ public void AddItemsToMenu(GenericMenu menu) AddStackTraceLoggingMenu(menu); } + internal ListViewState GetListViewState() { return m_ListView; } + private static void OnFontButtonValueChange() { m_UseMonospaceFont = !m_UseMonospaceFont; @@ -1258,6 +1261,8 @@ void DestroyLatestRestoreEntry() internal static event EntryDoubleClickedDelegate entryWithManagedCallbackDoubleClicked; + internal static event Action activeEntryChanged; + [UsedImplicitly, RequiredByNativeCode] private static void SendEntryDoubleClicked(LogEntry entry) { diff --git a/Editor/Mono/Delayer.cs b/Editor/Mono/Delayer.cs index 777c232310..59799aa769 100644 --- a/Editor/Mono/Delayer.cs +++ b/Editor/Mono/Delayer.cs @@ -16,26 +16,60 @@ class Delayer private readonly bool m_FirstExecuteImmediate; private bool m_DelayInProgress; - public static Delayer Throttle(Action action, double delay = 0.2) + internal static readonly TimeSpan DefaultDelay = TimeSpan.FromMilliseconds(200); + + /// + /// Throttle the action to be executed at most once every delay. + /// If no delay is specified default delay is + /// + /// action to be executed + /// delay of the action, if not specified will be used + /// a new instance of a + public static Delayer Throttle(Action action, TimeSpan? delay = null) { - return new Delayer(action, delay, true, false); + return new Delayer(action, delay ?? DefaultDelay, true, false); } - public static Delayer Throttle(Action action, double delay, bool firstExecuteImmediate) + /// + /// Throttle the action to be executed at most once every delay. + /// + /// action to be executed + /// delay of the action + /// if true, the action will be executed immediately + /// a new instance of a + public static Delayer Throttle(Action action, TimeSpan delay, bool firstExecuteImmediate) { return new Delayer(action, delay, true, firstExecuteImmediate); } - public static Delayer Debounce(Action action, double delay = 0.2) + /// + /// Debounce the action to be executed after the delay has passed. + /// If no delay is specified default delay is + /// + /// action to be executed + /// delay of the action, if not specified will be used + /// a new instance of a + public static Delayer Debounce(Action action, TimeSpan? delay = null) { - return new Delayer(action, delay, false, false); + return new Delayer(action, delay ?? DefaultDelay, false, false); } - public static Delayer Debounce(Action action, double delay, bool firstExecuteImmediate) + /// + /// Debounce the action to be executed after the delay has passed. + /// + /// action to be executed + /// delay for the action + /// if true, the action will be executed immediately + /// a new instance of a + public static Delayer Debounce(Action action, TimeSpan delay, bool firstExecuteImmediate) { return new Delayer(action, delay, false, firstExecuteImmediate); } + /// + /// Try to execute the action + /// + /// Context object to pass to the configured action public void Execute(object context = null) { m_Context = context; @@ -60,10 +94,10 @@ public void Execute(object context = null) } } - private Delayer(Action action, double delay, bool isThrottle, bool firstExecuteImmediate) + private Delayer(Action action, TimeSpan delay, bool isThrottle, bool firstExecuteImmediate) { m_Action = action; - m_DebounceDelay = TimeSpan.FromSeconds(delay).Ticks; + m_DebounceDelay = delay.Ticks; m_IsThrottle = isThrottle; m_FirstExecuteImmediate = firstExecuteImmediate; } diff --git a/Editor/Mono/EditorApplication.bindings.cs b/Editor/Mono/EditorApplication.bindings.cs index a0fd5d4834..05baf43e08 100644 --- a/Editor/Mono/EditorApplication.bindings.cs +++ b/Editor/Mono/EditorApplication.bindings.cs @@ -20,6 +20,7 @@ namespace UnityEditor [NativeHeader("Runtime/Camera/RenderSettings.h")] [NativeHeader("Runtime/Input/TimeManager.h")] [NativeHeader("Editor/Src/ProjectVersion.h")] + [NativeHeader("Runtime/Misc/BuildSettings.h")] [StaticAccessor("EditorApplicationBindings", StaticAccessorType.DoubleColon)] public sealed partial class EditorApplication { @@ -360,5 +361,11 @@ internal static void RestartEditorAndRecompileScripts() [FreeFunction("GetProjectVersion().Write")] internal static extern void WriteVersion(); + + internal static extern GUID buildSessionGUID + { + [FreeFunction("GetBuildSettings().GetBuildSessionGUID")] + get; + } } } diff --git a/Editor/Mono/EditorUserBuildSettings.bindings.cs b/Editor/Mono/EditorUserBuildSettings.bindings.cs index 87cd22e516..28d2efa79b 100644 --- a/Editor/Mono/EditorUserBuildSettings.bindings.cs +++ b/Editor/Mono/EditorUserBuildSettings.bindings.cs @@ -199,7 +199,7 @@ public enum WebGLClientBrowserType // Client browser type [NativeType(Header = "Runtime/Serialize/BuildTarget.h")] - public enum WebGLClientPlatform + internal enum WebGLClientPlatform { Desktop = 0, Android = 1, @@ -551,7 +551,7 @@ public static extern WebGLClientBrowserType webGLClientBrowserType [NativeMethod("SetWebGLClientBrowserType")] set; } - public static extern WebGLClientPlatform webGLClientPlatform + internal static extern WebGLClientPlatform webGLClientPlatform { [NativeMethod("GetWebGLClientPlatform")] get; diff --git a/Editor/Mono/ImportSettings/EditorPluginImporterExtension.cs b/Editor/Mono/ImportSettings/EditorPluginImporterExtension.cs index 96fe811615..1e8f659e11 100644 --- a/Editor/Mono/ImportSettings/EditorPluginImporterExtension.cs +++ b/Editor/Mono/ImportSettings/EditorPluginImporterExtension.cs @@ -16,10 +16,8 @@ internal class EditorPluginImporterExtension : DefaultPluginImporterExtension { internal enum EditorPluginCPUArchitecture { - AnyCPU, - [InspectorName("Intel 64-bit")] + AnyCPU = 0, x86_64, - [InspectorName("Apple silicon / Arm64")] ARM64 } @@ -54,11 +52,20 @@ internal override void Apply(PluginImporterInspector inspector) internal class CPUProperty : Property { private readonly Func validArch; + private EditorPluginOSArchitecture currentOS; + private readonly GUIContent[] m_ArchitectureNames; public CPUProperty(GUIContent name, string key, EditorPluginCPUArchitecture defaultValue, Func validArch) : base(name, key, defaultValue, BuildPipeline.GetEditorTargetName()) { this.validArch = validArch; + this.currentOS = EditorPluginOSArchitecture.AnyOS; + int enumLength = Enum.GetNames(typeof(EditorPluginCPUArchitecture)).Length; + m_ArchitectureNames = new GUIContent[enumLength]; + for (int i = 0; i < enumLength; i++) + { + m_ArchitectureNames[i] = EditorGUIUtility.TrTextContent(GetArchitectureName(currentOS, (EditorPluginCPUArchitecture)i)); + } } internal override void Reset(PluginImporterInspector inspector) @@ -74,7 +81,56 @@ internal override void Apply(PluginImporterInspector inspector) internal override void OnGUI(PluginImporterInspector inspector) { - value = EditorGUILayout.EnumPopup(name, (Enum)value, validArch, false); + EditorGUILayout.BeginHorizontal(); + EditorGUI.BeginChangeCheck(); + int selectedIndex = (int)GetCurrentArchitecture(inspector); + selectedIndex = EditorGUILayout.Popup(name, selectedIndex, m_ArchitectureNames); + if (EditorGUI.EndChangeCheck()) + { + value = (EditorPluginCPUArchitecture)selectedIndex; + } + EditorGUILayout.EndHorizontal(); + } + + private EditorPluginCPUArchitecture GetCurrentArchitecture(PluginImporterInspector inspector) + { + var arch = value as EditorPluginCPUArchitecture?; + if (arch == null) + { + return EditorPluginCPUArchitecture.AnyCPU; + } + return arch.Value; + } + + public void UpdateArchitectureNames(EditorPluginOSArchitecture osValue) + { + if (currentOS != osValue) + { + int enumLength = Enum.GetNames(typeof(EditorPluginCPUArchitecture)).Length; + for (int i = 0; i < enumLength; i++) + { + m_ArchitectureNames[i] = EditorGUIUtility.TrTextContent(GetArchitectureName(osValue, (EditorPluginCPUArchitecture)i)); + } + currentOS = osValue; + } + } + + static string GetArchitectureName(EditorPluginOSArchitecture os, EditorPluginCPUArchitecture architecture) + { + switch (architecture) + { + case EditorPluginCPUArchitecture.x86_64: + return os == EditorPluginOSArchitecture.OSX ? "Intel 64-bit" : "x64"; + + case EditorPluginCPUArchitecture.ARM64: + return os == EditorPluginOSArchitecture.OSX ? "Apple silicon" : "Arm64"; + + case EditorPluginCPUArchitecture.AnyCPU: + return "Any CPU"; + + default: + throw new NotSupportedException("Unknown EditorPluginCPUArchitecture value: " + architecture); + } } } @@ -94,6 +150,7 @@ public override void OnPlatformSettingsGUI(PluginImporterInspector inspector) EditorGUI.BeginChangeCheck(); editorOSProperty.OnGUI(inspector); + editorCPUProperty.UpdateArchitectureNames((EditorPluginOSArchitecture)editorOSProperty.value); editorCPUProperty.OnGUI(inspector); if (EditorGUI.EndChangeCheck()) diff --git a/Editor/Mono/Inspector/Core/PreviewWindow.cs b/Editor/Mono/Inspector/Core/PreviewWindow.cs index c01a32ebf5..bda789d59d 100644 --- a/Editor/Mono/Inspector/Core/PreviewWindow.cs +++ b/Editor/Mono/Inspector/Core/PreviewWindow.cs @@ -86,8 +86,7 @@ internal override void RebuildContentsContainers() CreatePreviewables(); previewWindow = new InspectorPreviewWindow(); - IPreviewable[] editorsWithPreviews = GetEditorsWithPreviews(tracker.activeEditors); - IPreviewable editor = GetEditorThatControlsPreview(editorsWithPreviews); + IPreviewable editor = GetEditorThatControlsPreview(tracker.activeEditors); previewWindow = editor?.CreatePreview(previewWindow) as InspectorPreviewWindow; if (m_ParentInspectorWindow != null && previewWindow != null) @@ -132,8 +131,7 @@ IMGUIContainer DrawPreview(bool drawToolbar = false) { return new IMGUIContainer(() => { - IPreviewable[] editorsWithPreviews = GetEditorsWithPreviews(tracker.activeEditors); - IPreviewable editor = GetEditorThatControlsPreview(editorsWithPreviews); + IPreviewable editor = GetEditorThatControlsPreview(tracker.activeEditors); if (drawToolbar) { diff --git a/Editor/Mono/Inspector/Core/PropertyEditor.cs b/Editor/Mono/Inspector/Core/PropertyEditor.cs index 30d7b6c1d0..8aa9d0185e 100644 --- a/Editor/Mono/Inspector/Core/PropertyEditor.cs +++ b/Editor/Mono/Inspector/Core/PropertyEditor.cs @@ -23,6 +23,7 @@ using JetBrains.Annotations; using Unity.Profiling; using UnityEditor.UIElements; +using UnityEngine.Pool; namespace UnityEditor { @@ -149,6 +150,7 @@ class PropertyEditor : EditorWindow, IPropertyView, IHasCustomMenu EditorElementUpdater m_EditorElementUpdater; IPreviewable m_cachedPreviewEditor; + Delayer m_HasPreviewPeriodicCheckDelayer; public InspectorMode inspectorMode { @@ -360,11 +362,31 @@ protected virtual void OnEnable() EditorApplication.CallDelayed(UpdateSupportedDataModesList); if (!m_AllPropertyEditors.Contains(this)) m_AllPropertyEditors.Add(this); + + m_HasPreviewPeriodicCheckDelayer?.Dispose(); + m_HasPreviewPeriodicCheckDelayer = Delayer.Throttle(HasPreviewPeriodicCheck, TimeSpan.FromMilliseconds(200)); + EditorApplication.update += OnEditorUpdate; + } + + void HasPreviewPeriodicCheck(object _) + { + var previewEditor = GetEditorThatControlsPreview(tracker.activeEditors); + + // Do we have a preview? + var hasPreview = previewEditor != null && previewEditor.HasPreviewGUI(); + if (hasPreview != m_HasPreview) + { + m_HasPreview = hasPreview; + RebuildContentsContainers(); + } } + void OnEditorUpdate() => m_HasPreviewPeriodicCheckDelayer?.Execute(null); + [UsedImplicitly] protected virtual void OnDisable() { + m_HasPreviewPeriodicCheckDelayer?.Dispose(); hasFloatingPreviewWindow = false; ClearPreviewables(); @@ -388,6 +410,7 @@ protected virtual void OnDisable() EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; m_AllPropertyEditors.Remove(this); + EditorApplication.update -= OnEditorUpdate; } private void OnMouseEnter(MouseEnterEvent e) => HoveredPropertyEditor = this; @@ -1146,8 +1169,7 @@ internal virtual void RebuildContentsContainers() { VisualElement previewItem = null; CreatePreviewables(); - IPreviewable[] editorsWithPreviews = GetEditorsWithPreviews(tracker.activeEditors); - m_cachedPreviewEditor = GetEditorThatControlsPreview(editorsWithPreviews); + m_cachedPreviewEditor = GetEditorThatControlsPreview(tracker.activeEditors); if (m_cachedPreviewEditor != null && m_cachedPreviewEditor.HasPreviewGUI()) { @@ -1278,8 +1300,7 @@ private void OnDraglineGeometryChange(VisualElement window, VisualElement dragli internal void PrepareToolbar(InspectorPreviewWindow toolbar, bool isFloatingPreviewWindow = false) { - IPreviewable[] editorsWithPreviews = GetEditorsWithPreviews(tracker.activeEditors); - IPreviewable previewEditor = GetEditorThatControlsPreview(editorsWithPreviews); + IPreviewable previewEditor = GetEditorThatControlsPreview(tracker.activeEditors); if(!isFloatingPreviewWindow) CreatePreviewEllipsisMenu(toolbar, this); @@ -1287,8 +1308,7 @@ internal void PrepareToolbar(InspectorPreviewWindow toolbar, bool isFloatingPrev internal void UpdateLabel(InspectorPreviewWindow toolbar) { - IPreviewable[] editorsWithPreviews = GetEditorsWithPreviews(tracker.activeEditors); - IPreviewable previewEditor = GetEditorThatControlsPreview(editorsWithPreviews); + IPreviewable previewEditor = GetEditorThatControlsPreview(tracker.activeEditors); string label; if (previewEditor != null && previewEditor.HasPreviewGUI()) @@ -1424,9 +1444,16 @@ internal virtual Editor GetLastInteractedEditor() return lastInteractedEditor; } - protected IPreviewable GetEditorThatControlsPreview(IPreviewable[] editors) + protected IPreviewable GetEditorThatControlsPreview(Editor[] activeEditors) { - if (editors.Length == 0) + using var _ = ListPool.Get(out var editorsWithPreviews); + GetEditorsWithPreviews(activeEditors, editorsWithPreviews); + return GetEditorThatControlsPreview(editorsWithPreviews); + } + + protected IPreviewable GetEditorThatControlsPreview(List editors) + { + if (editors.Count == 0) return null; if (m_SelectedPreview != null) @@ -1482,9 +1509,10 @@ protected IPreviewable GetEditorThatControlsPreview(IPreviewable[] editors) return null; } - protected IPreviewable[] GetEditorsWithPreviews(Editor[] editors) + protected void GetEditorsWithPreviews(Editor[] editors, List outEditorsWithPreview) { - IList editorsWithPreview = new List(); + outEditorsWithPreview.Clear(); + if (m_Previews == null) return; int i = -1; foreach (Editor e in editors) @@ -1513,19 +1541,15 @@ protected IPreviewable[] GetEditorsWithPreviews(Editor[] editors) if (e.HasPreviewGUI()) { - editorsWithPreview.Add(e); + outEditorsWithPreview.Add(e); } } - if (m_Previews == null) return new IPreviewable[] {}; - foreach (var previewable in m_Previews) { if (previewable.HasPreviewGUI()) - editorsWithPreview.Add(previewable); + outEditorsWithPreview.Add(previewable); } - - return editorsWithPreview.ToArray(); } internal virtual Object GetInspectedObject() @@ -1581,7 +1605,8 @@ private void DrawPreviewAndLabels() CreatePreviewables(); var hasPreview = BeginDrawPreviewAndLabels(); - IPreviewable[] editorsWithPreviews = GetEditorsWithPreviews(tracker.activeEditors); + using var _ = ListPool.Get(out var editorsWithPreviews); + GetEditorsWithPreviews(tracker.activeEditors, editorsWithPreviews); IPreviewable previewEditor = GetEditorThatControlsPreview(editorsWithPreviews); // Do we have a preview? @@ -1625,7 +1650,7 @@ private void DrawPreviewAndLabels() dragIconRect.height = Styles.dragHandle.fixedHeight; //If we have more than one component with Previews, show a DropDown menu. - if (editorsWithPreviews.Length > 1) + if (editorsWithPreviews.Count > 1) { Vector2 foldoutSize = Styles.preDropDown.CalcSize(title); float maxFoldoutWidth = (dragIconRect.xMax - dragRect.xMin) - dragPadding - minDragWidth; @@ -1634,9 +1659,9 @@ private void DrawPreviewAndLabels() dragRect.xMin += foldoutWidth; dragIconRect.xMin += foldoutWidth; - GUIContent[] panelOptions = new GUIContent[editorsWithPreviews.Length]; + GUIContent[] panelOptions = new GUIContent[editorsWithPreviews.Count]; int selectedPreview = -1; - for (int index = 0; index < editorsWithPreviews.Length; index++) + for (int index = 0; index < editorsWithPreviews.Count; index++) { IPreviewable currentEditor = editorsWithPreviews[index]; GUIContent previewTitle = currentEditor.GetPreviewTitle() ?? Styles.preTitle; @@ -1762,8 +1787,7 @@ private void DrawFooter() bool hasLabels = assets.Length > 0; bool hasBundleName = assets.Any(a => !(a is MonoScript) && AssetDatabase.IsMainAsset(a)); - IPreviewable[] editorsWithPreviews = GetEditorsWithPreviews(tracker.activeEditors); - IPreviewable previewEditor = GetEditorThatControlsPreview(editorsWithPreviews); + IPreviewable previewEditor = GetEditorThatControlsPreview(tracker.activeEditors); if (previewEditor == null || !previewEditor.HasPreviewGUI()) { diff --git a/Editor/Mono/Modules/DefaultBuildProfileExtension.cs b/Editor/Mono/Modules/DefaultBuildProfileExtension.cs index ac53748eaf..9b74e3232d 100644 --- a/Editor/Mono/Modules/DefaultBuildProfileExtension.cs +++ b/Editor/Mono/Modules/DefaultBuildProfileExtension.cs @@ -18,7 +18,7 @@ internal abstract class DefaultBuildProfileExtension : IBuildProfileExtension static readonly GUIContent k_AutoconnectProfiler = EditorGUIUtility.TrTextContent("Autoconnect Profiler", "When the build is started, an open Profiler Window will automatically connect to the Player and start profiling. The \"Build And Run\" option will also automatically open the Profiler Window."); static readonly GUIContent k_AutoconnectProfilerDisabled = EditorGUIUtility.TrTextContent("Autoconnect Profiler", "Profiling is only enabled in a Development Player."); static readonly GUIContent k_BuildWithDeepProfiler = EditorGUIUtility.TrTextContent("Deep Profiling Support", "Build Player with Deep Profiling Support. This might affect Player performance."); - static readonly GUIContent k_BuildWithDeepProfilerDisabled = EditorGUIUtility.TrTextContent("Deep Profiling", "Profiling is only enabled in a Development Player."); + static readonly GUIContent k_BuildWithDeepProfilerDisabled = EditorGUIUtility.TrTextContent("Deep Profiling Support", "Profiling is only enabled in a Development Player."); static readonly GUIContent k_AllowDebugging = EditorGUIUtility.TrTextContent("Script Debugging", "Enable this setting to allow your script code to be debugged."); static readonly GUIContent k_WaitForManagedDebugger = EditorGUIUtility.TrTextContent("Wait For Managed Debugger", "Show a dialog where you can attach a managed debugger before any script execution. Can also use volume Up or Down button to confirm on Android."); static readonly GUIContent k_ManagedDebuggerFixedPort = EditorGUIUtility.TrTextContent("Managed Debugger Fixed Port", "Use the specified port to attach to the managed debugger. If 0, the port will be automatically selected."); diff --git a/Editor/Mono/PlayerSettingsSwitch.bindings.cs b/Editor/Mono/PlayerSettingsSwitch.bindings.cs index cc43a7a171..9762ad9414 100644 --- a/Editor/Mono/PlayerSettingsSwitch.bindings.cs +++ b/Editor/Mono/PlayerSettingsSwitch.bindings.cs @@ -261,7 +261,6 @@ public static string[] compilerFlags [NativeProperty("switchCompilerFlags", TargetType.Function)] extern private static string compilerFlagsInternal { get; set; } - //Additional NSO Dependencies [NativeProperty("switchNSODependencies", TargetType.Function)] extern public static string nsoDependencies { get; set; } diff --git a/Editor/Mono/PlayerSettingsSwitch.deprecated.bindings.cs b/Editor/Mono/PlayerSettingsSwitch.deprecated.bindings.cs new file mode 100644 index 0000000000..4983bde15e --- /dev/null +++ b/Editor/Mono/PlayerSettingsSwitch.deprecated.bindings.cs @@ -0,0 +1,340 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; +using System.IO; +using UnityEngine; +using UnityEngine.Bindings; + +namespace UnityEditor; + +//==== OBSOLETE PLAYER SETTINGS ===// +//These are used ONLY to upgrade a NMETA Player Settings to an NMETA file// + +public sealed partial class PlayerSettings +{ + [NativeHeader("Editor/Mono/PlayerSettingsSwitch.bindings.h")] + public sealed partial class Switch + { + const string kPlayerSettingsAreObsoletedWarning = "NMETA Player Settings are obsolete"; + + [NativeProperty("switchUpgradedPlayerSettingsToNMETA", TargetType.Field)] + extern internal static bool HasUpgradedPlayerSettingsToNMETA { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + internal enum Languages + { + AmericanEnglish = 0, + BritishEnglish = 1, + Japanese = 2, + French = 3, + German = 4, + LatinAmericanSpanish = 5, + Spanish = 6, + Italian = 7, + Dutch = 8, + CanadianFrench = 9, + Portuguese = 10, + Russian = 11, + SimplifiedChinese = 12, + TraditionalChinese = 13, + Korean = 14, + BrazilianPortuguese = 15, + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + internal enum StartupUserAccount + { + None = 0, + Required = 1, + RequiredWithNetworkServiceAccountAvailable = 2 + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + internal enum LogoHandling + { + Auto = 0, + Manual = 1 + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + internal enum LogoType + { + LicensedByNintendo = 0, + [Obsolete("This attribute is no longer available as of NintendoSDK 4.3.", true)] + DistributedByNintendo = 1, + Nintendo = 2 + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + internal enum ApplicationAttribute + { + None = 0, + Demo = 1 + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + internal enum RatingCategories + { + CERO = 0, + GRACGCRB = 1, + GSRMR = 2, + ESRB = 3, + ClassInd = 4, + USK = 5, + PEGI = 6, + PEGIPortugal = 7, + PEGIBBFC = 8, + Russian = 9, + ACB = 10, + OFLC = 11, + IARCGeneric = 12, + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchApplicationID", TargetType.Function)] + extern internal static string applicationID { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + extern internal static string[] titleNames + { + [NativeMethod("GetSwitchTitleNames")] + get; + [NativeMethod("SetSwitchTitleNames")] + set; + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + extern internal static string[] publisherNames + { + [NativeMethod("GetSwitchPublisherNames")] + get; + [NativeMethod("SetSwitchPublisherNames")] + set; + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + extern internal static Texture2D[] icons + { + [NativeMethod("GetSwitchIcons")] + get; + [NativeMethod("SetSwitchIcons")] + set; + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + extern internal static Texture2D[] smallIcons + { + [NativeMethod("GetSwitchSmallIcons")] + get; + [NativeMethod("SetSwitchSmallIcons")] + set; + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchAllowsVideoCapturing", TargetType.Field)] + extern internal static bool isVideoCapturingEnabled { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchAllowsRuntimeAddOnContentInstall", TargetType.Field)] + extern internal static bool isRuntimeAddOnContentInstallEnabled { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchDataLossConfirmation", TargetType.Field)] + extern internal static bool isDataLossConfirmationEnabled { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchUserAccountLockEnabled", TargetType.Field)] + extern internal static bool isUserAccountLockEnabled { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchRatingsMask", TargetType.Field)] + extern internal static int ratingsMask { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + extern internal static string[] localCommunicationIds + { + [NativeMethod("GetSwitchLocalCommunicationIds")] + get; + [NativeMethod("SetSwitchLocalCommunicationIds")] + set; + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchParentalControl", TargetType.Field)] + extern internal static bool isUnderParentalControl { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchAllowsScreenshot", TargetType.Field)] + extern internal static bool isScreenshotEnabled { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + internal static int cardSpecClock + { + get { return cardSpecClockInternal; } + set { cardSpecClockInternal = (value > 0) ? value : -1; } + } + + [NativeProperty("switchCardSpecClock", TargetType.Field)] + extern static int cardSpecClockInternal { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + internal static string manualHTMLPath + { + get + { + string path = manualHTMLPathInternal; + + if (string.IsNullOrEmpty(path)) + return ""; + + string fullPath = path; + + if (!Path.IsPathRooted(fullPath)) + fullPath = Path.GetFullPath(fullPath); + + if (!Directory.Exists(fullPath)) + return ""; + + return fullPath; + } + set { manualHTMLPathInternal = string.IsNullOrEmpty(value) ? "" : value; } + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + internal static string accessibleURLPath + { + get + { + string path = accessibleURLPathInternal; + + if (string.IsNullOrEmpty(path)) + return ""; + + string fullPath = path; + + if (!Path.IsPathRooted(fullPath)) + fullPath = Path.GetFullPath(fullPath); + + return fullPath; + } + set { accessibleURLPathInternal = string.IsNullOrEmpty(value) ? "" : value; } + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + internal static string legalInformationPath + { + get + { + string path = legalInformationPathInternal; + + if (string.IsNullOrEmpty(path)) + return ""; + + if (!Path.IsPathRooted(path)) + path = Path.GetFullPath(path); + + return path; + } + set { legalInformationPathInternal = string.IsNullOrEmpty(value) ? "" : value; } + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchManualHTML", TargetType.Function)] + extern static string manualHTMLPathInternal { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchAccessibleURLs", TargetType.Function)] + extern static string accessibleURLPathInternal { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchLegalInformation", TargetType.Function)] + extern static string legalInformationPathInternal { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchMainThreadStackSize", TargetType.Field)] + extern internal static int mainThreadStackSize { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchPresenceGroupId", TargetType.Function)] + extern internal static string presenceGroupId { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchLogoHandling", TargetType.Field)] + extern internal static LogoHandling logoHandling { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + extern internal static string releaseVersion + { + [NativeMethod("GetSwitchReleaseVersion")] + get; + [NativeMethod("SetSwitchReleaseVersion")] + set; + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchDisplayVersion", TargetType.Function)] + extern internal static string displayVersion { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchStartupUserAccount", TargetType.Field)] + extern internal static StartupUserAccount startupUserAccount { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchSupportedLanguagesMask", TargetType.Field)] + extern internal static int supportedLanguages { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchLogoType", TargetType.Field)] + extern internal static LogoType logoType { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchApplicationErrorCodeCategory", TargetType.Function)] + extern internal static string applicationErrorCodeCategory { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchUserAccountSaveDataSize", TargetType.Field)] + extern internal static int userAccountSaveDataSize { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchUserAccountSaveDataJournalSize", TargetType.Field)] + extern internal static int userAccountSaveDataJournalSize { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchApplicationAttribute", TargetType.Field)] + extern internal static ApplicationAttribute applicationAttribute { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + internal static int cardSpecSize + { + get { return cardSpecSizeInternal; } + set { cardSpecSizeInternal = (value > 0) ? value : -1; } + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchCardSpecSize", TargetType.Field)] + extern private static int cardSpecSizeInternal { get; set; } + + // System Memory (used for virtual memory mapping). + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + [NativeProperty("switchSystemResourceMemory", TargetType.Field)] + extern internal static int systemResourceMemory { get; set; } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + internal static int GetRatingAge(RatingCategories category) + { + return ratingAgeArray[(int)category]; + } + + [Obsolete(kPlayerSettingsAreObsoletedWarning)] + extern internal static int[] ratingAgeArray + { + [NativeMethod("GetSwitchRatingAges")] + get; + [NativeMethod("SetSwitchRatingAges")] + set; + } + + } +} diff --git a/Editor/Mono/Prefabs/PrefabImporterEditor.cs b/Editor/Mono/Prefabs/PrefabImporterEditor.cs index 8d78721584..4ad91d03bc 100644 --- a/Editor/Mono/Prefabs/PrefabImporterEditor.cs +++ b/Editor/Mono/Prefabs/PrefabImporterEditor.cs @@ -241,6 +241,9 @@ internal void SaveDirtyPrefabAssets(bool reloadInspectors) bool IsTargetAsset(Object obj) { + if (assetTargets == null) + return false; + if (obj is Component component) obj = component.gameObject; diff --git a/Editor/Mono/Prefabs/PrefabUtility.cs b/Editor/Mono/Prefabs/PrefabUtility.cs index d43bbfde67..7819e1ab34 100644 --- a/Editor/Mono/Prefabs/PrefabUtility.cs +++ b/Editor/Mono/Prefabs/PrefabUtility.cs @@ -1099,7 +1099,7 @@ internal static bool IsPropertyBeingDrivenByPrefabStage(SerializedProperty prope var prefabStage = SceneManagement.PrefabStageUtility.GetCurrentPrefabStage(); if (prefabStage != null && prefabStage.mode == SceneManagement.PrefabStage.Mode.InContext) { - var propertyPath = property.propertyPath; + var propertyPath = (property.isReferencingAManagedReferenceField ? property.managedReferencePropertyPath : property.propertyPath); ScriptableObject driver = prefabStage; if ( (DrivenPropertyManagerInternal.IsDriving(driver, target, propertyPath)) diff --git a/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs b/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs index 053ddaaba3..8c735b1e3b 100644 --- a/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs +++ b/Editor/Mono/PreferencesWindow/PreferencesSettingsProviders.cs @@ -61,7 +61,7 @@ class GeneralProperties public static readonly GUIContent applicationFrameThrottling = EditorGUIUtility.TrTextContent("Frame Throttling (milliseconds)", "The number of milliseconds the Editor can idle between frames."); public static readonly GUIContent inputMaxProcessTime = EditorGUIUtility.TrTextContent("Input Throttling (milliseconds)", "The maximum number of milliseconds the Editor will take to process user inputs."); public static readonly GUIContent interactionMode = EditorGUIUtility.TrTextContent("Interaction Mode", "Specifies how long the Editor can idle before it updates."); - public static readonly GUIContent enterPlayModeSettingsFocusGameView = EditorGUIUtility.TrTextContent("Create Game View On Play", "If enabled, a Game View window will be created when entering play mode if none exists"); + public static readonly GUIContent enterPlayModeSettingsFocusGameView = EditorGUIUtility.TrTextContent("Open Game View On Play", "Open a Game view window when you enter Play mode."); public static readonly GUIContent enableExtendedDynamicHints = EditorGUIUtility.TrTextContent("Enable extended Dynamic Hints", "Check this to enable extended Dynamic Hints. If available, extended Dynamic Hints will display more information when a property, object or tool is hovered for enough time, or when a Dynamic Hint is displayed"); public static readonly GUIContent[] interactionModes = { diff --git a/Editor/Mono/UIElements/UIBuildAnalyticsEvent.cs b/Editor/Mono/UIElements/UIBuildAnalyticsEvent.cs new file mode 100644 index 0000000000..e59b2bc152 --- /dev/null +++ b/Editor/Mono/UIElements/UIBuildAnalyticsEvent.cs @@ -0,0 +1,138 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; +using System.Collections.Generic; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using UnityEngine; +using UnityEngine.Analytics; +using UnityEngine.Serialization; +using UnityEngine.UIElements; + +namespace UnityEditor.Audio.Analytics; + +class UIBuildAnalyticsEvent : IPostprocessBuildWithReport +{ + + [AnalyticInfo("uiBuild", "unity.ui", 2, 60)] + internal class UIBuildEvent : IAnalytic + { + [Serializable] + public struct UIAssetCounters + { + public int PanelSettings; + public int VisualTreeAsset; + public int StyleSheet; + public int ThemeStyleSheet; + } + + [Serializable] + struct Payload : IAnalytic.IData + { + public string build_guid; + public string build_session_guid; + public int build_type; + public UIAssetCounters counters; + } + + public string buildGuid; + public string buildSessionGuid; + public BuildType buildType; + public UIAssetCounters counters; + + public UIBuildEvent(string buildGuid, string buildSessionGuid, BuildType buildType, UIAssetCounters counters) + { + this.buildGuid = buildGuid; + this.buildSessionGuid = buildSessionGuid; + this.buildType = buildType; + this.counters = counters; + } + + public bool TryGatherData(out IAnalytic.IData data, out Exception error) + { + error = null; + data = new Payload + { + build_guid = buildGuid, + build_session_guid = buildSessionGuid, + build_type = (int)buildType, + counters = counters, + }; + return data != null; + } + } + + public int callbackOrder { get; } + + public void OnPostprocessBuild(BuildReport report) + { + SendEvent(report); + } + + static void SendEvent(BuildReport report) + { + if (!EditorAnalytics.enabled + || report == null + || report.packedAssets.Length == 0) + { + return; + } + + UIBuildEvent.UIAssetCounters counters = default; + + var registeredVTAs = new HashSet(); + + for (var i = 0; i < report.packedAssets.Length; ++i) + { + var infos = report.packedAssets[i].GetContents(); + + for (var j = 0; j < infos.Length; ++j) + { + PackedAssetInfo info = infos[j]; + + // Skip any default/builtin resource + if (info.sourceAssetGUID == default) + continue; + + if (info.type == typeof(MonoBehaviour)) + { + // We want the actual user type, which is not given by PackedAssetInfo.type + Type type = AssetDatabase.GetMainAssetTypeFromGUID(info.sourceAssetGUID); + + if (type == null) + continue; + + if (type == typeof(VisualTreeAsset)) + { + // The same VisualTreeAsset may appear multiple times because it contains a StyleSheet subasset + // Which seems to cause it to appear twice in the BuildReport content list + // So make sure we only count unique GUIDs to avoid counting them twice + if (registeredVTAs.Add(info.sourceAssetGUID)) + { + counters.VisualTreeAsset++; + } + } + else if (type == typeof(StyleSheet)) + { + counters.StyleSheet++; + } + else if (type == typeof(ThemeStyleSheet)) + { + counters.ThemeStyleSheet++; + } + else if (type == typeof(PanelSettings)) + { + counters.PanelSettings++; + } + } + } + } + + string buildSessionGuid = EditorApplication.buildSessionGUID.ToString(); + + var buildEvent = new UIBuildEvent(report.summary.guid.ToString(), buildSessionGuid, report.summary.buildType, counters); + EditorAnalytics.SendAnalytic(buildEvent); + } +} diff --git a/Modules/AndroidJNI/AndroidAssetPacks.bindings.cs b/Modules/AndroidJNI/AndroidAssetPacks.bindings.cs index 1459f521fa..8be73bfb7b 100644 --- a/Modules/AndroidJNI/AndroidAssetPacks.bindings.cs +++ b/Modules/AndroidJNI/AndroidAssetPacks.bindings.cs @@ -65,6 +65,15 @@ internal AndroidAssetPackInfo(string name, AndroidAssetPackStatus status, ulong public ulong bytesDownloaded { get; } public float transferProgress { get; } public AndroidAssetPackError error { get; } + + internal bool downloadInProgress => DownloadInProgress(status); + internal static bool DownloadInProgress(AndroidAssetPackStatus status) + { + return status != AndroidAssetPackStatus.Canceled + && status != AndroidAssetPackStatus.Completed + && status != AndroidAssetPackStatus.Failed + && status != AndroidAssetPackStatus.Unknown; + } } public class AndroidAssetPackState @@ -108,10 +117,7 @@ public override bool keepWaiting if (info == null) return true; - if (info.status != AndroidAssetPackStatus.Canceled - && info.status != AndroidAssetPackStatus.Completed - && info.status != AndroidAssetPackStatus.Failed - && info.status != AndroidAssetPackStatus.Unknown) + if (info.downloadInProgress) { return true; } @@ -137,10 +143,7 @@ public float progress { if (info == null) continue; - if (info.status == AndroidAssetPackStatus.Canceled - || info.status == AndroidAssetPackStatus.Completed - || info.status == AndroidAssetPackStatus.Failed - || info.status == AndroidAssetPackStatus.Unknown) + if (!info.downloadInProgress) { // We are counting the whole operation progress, so a failed subtask is "done" subtask in this case downloadProgress += 1f; diff --git a/Modules/AndroidJNI/AndroidGame.bindings.cs b/Modules/AndroidJNI/AndroidGame.bindings.cs index 441a8cf8db..83eb80b34b 100644 --- a/Modules/AndroidJNI/AndroidGame.bindings.cs +++ b/Modules/AndroidJNI/AndroidGame.bindings.cs @@ -44,4 +44,23 @@ public enum AndroidGameState /// Content = 0x00000004 } + + [NativeType(Header = "Modules/AndroidJNI/Public/GameStateHelper.h")] + internal enum GameStateLabel + { + Default = -1, + InitialLoading = -2, + AssetPacksLoading = -3, + WebRequest = -4 + } + + [NativeHeader("Modules/AndroidJNI/Public/GameStateHelper.h")] + [StaticAccessor("GameStateHelper::Get()", StaticAccessorType.Dot)] + public static partial class AndroidGame + { + // Required for automated SetGameState calls, indicates to the operating system when the application is in loading state, level is the type of loading + internal static extern void StartLoading(int label); + // Required for automated SetGameState calls, indicates to the operating system when loading state is ended, level is the type of loading + internal static extern void StopLoading(int label); + } } diff --git a/Modules/AndroidJNI/AndroidGame.cs b/Modules/AndroidJNI/AndroidGame.cs index 77c99840c4..c95d5bead3 100644 --- a/Modules/AndroidJNI/AndroidGame.cs +++ b/Modules/AndroidJNI/AndroidGame.cs @@ -36,7 +36,7 @@ public enum AndroidGameMode Battery = 0x00000003 } - public static class AndroidGame + public static partial class AndroidGame { private static AndroidJavaObject m_UnityGameManager; private static AndroidJavaObject m_UnityGameState; diff --git a/Modules/Audio/Public/ScriptBindings/Audio.bindings.cs b/Modules/Audio/Public/ScriptBindings/Audio.bindings.cs index 67972ab811..f5b1c217bc 100644 --- a/Modules/Audio/Public/ScriptBindings/Audio.bindings.cs +++ b/Modules/Audio/Public/ScriptBindings/Audio.bindings.cs @@ -385,6 +385,8 @@ extern static internal bool unityAudioDisabled { [NativeName("IsAudioDisabled")] get; + [NativeName("DisableAudio")] + set; } [NativeMethod(Name = "AudioSettings::GetCurrentAmbisonicDefinitionName", IsFreeFunction = true)] diff --git a/Modules/BuildProfileEditor/BuildProfileWindow.cs b/Modules/BuildProfileEditor/BuildProfileWindow.cs index af1dd4c799..8e195308ec 100644 --- a/Modules/BuildProfileEditor/BuildProfileWindow.cs +++ b/Modules/BuildProfileEditor/BuildProfileWindow.cs @@ -230,15 +230,18 @@ void CreateMissingClassicPlatformListView() public void OnDisable() { - m_BuildProfileDataSource.Dispose(); + m_BuildProfileDataSource?.Dispose(); BuildProfileContext.instance.activeProfileChanged -= OnActiveProfileChanged; if (m_AssetImportWindow != null) m_AssetImportWindow.Close(); // Set list view's items source to null, so the items' unbind gets called - m_BuildProfilesListView.itemsSource = null; - m_BuildProfileClassicPlatformListView.itemsSource = null; + if (m_BuildProfilesListView != null) + m_BuildProfilesListView.itemsSource = null; + + if (m_BuildProfileClassicPlatformListView != null) + m_BuildProfileClassicPlatformListView.itemsSource = null; } /// diff --git a/Modules/EditorToolbar/ToolbarElements/PlayModeButtons.cs b/Modules/EditorToolbar/ToolbarElements/PlayModeButtons.cs index 90adb4991a..1d50f389a4 100644 --- a/Modules/EditorToolbar/ToolbarElements/PlayModeButtons.cs +++ b/Modules/EditorToolbar/ToolbarElements/PlayModeButtons.cs @@ -19,7 +19,7 @@ sealed class PlayModeButtons : VisualElement readonly VisualElement m_UIElementsRoot; readonly IMGUIContainer m_ImguiOverride; - static readonly GUIContent s_PlayButtonContextMenuItem = EditorGUIUtility.TrTextContent("Create Game View On Play"); + static readonly GUIContent s_PlayButtonContextMenuItem = EditorGUIUtility.TrTextContent("Open Game View On Play"); internal static event Action onPlayModeButtonsCreated; diff --git a/Modules/IMGUI/RuntimeTextSettings.cs b/Modules/IMGUI/RuntimeTextSettings.cs index 27d378e897..51ebfe2271 100644 --- a/Modules/IMGUI/RuntimeTextSettings.cs +++ b/Modules/IMGUI/RuntimeTextSettings.cs @@ -27,5 +27,22 @@ internal static RuntimeTextSettings defaultTextSettings return s_DefaultTextSettings; } } + + private static List s_FallbackOSFontAssetIMGUIInternal; + + internal override Shader GetFontShader() + { + return TextShaderUtilities.ShaderRef_MobileSDF_IMGUI; + } + + internal override List GetStaticFallbackOSFontAsset() + { + return s_FallbackOSFontAssetIMGUIInternal; + } + + internal override void SetStaticFallbackOSFontAsset(List fontAssets) + { + s_FallbackOSFontAssetIMGUIInternal = fontAssets; + } } } diff --git a/Modules/Licensing/UI/Data/Events/Base/NotificationType.cs b/Modules/Licensing/UI/Data/Events/Base/NotificationType.cs index dcf2fbe5d3..0b5983e6a5 100644 --- a/Modules/Licensing/UI/Data/Events/Base/NotificationType.cs +++ b/Modules/Licensing/UI/Data/Events/Base/NotificationType.cs @@ -10,4 +10,5 @@ enum NotificationType LicenseUpdate, LicenseExpired, LicenseOfflineValidityEnding, + BorrowFeatureStatus, } diff --git a/Modules/Licensing/UI/Data/Events/BorrowFeatureStatusNotification.cs b/Modules/Licensing/UI/Data/Events/BorrowFeatureStatusNotification.cs new file mode 100644 index 0000000000..e5548eeb56 --- /dev/null +++ b/Modules/Licensing/UI/Data/Events/BorrowFeatureStatusNotification.cs @@ -0,0 +1,26 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; +using UnityEditor.Licensing.UI.Data.Events.Base; + +namespace UnityEditor.Licensing.UI.Data.Events; + +[Serializable] +class BorrowFeatureStatusNotification : NotificationWithDetails { } + +[Serializable] +class BorrowFeatureStatusNotificationDetails +{ + public BorrowFeatureStatus status; + public int maxBorrowDurationDays; +} + +enum BorrowFeatureStatus +{ + Unknown = 0, + Allowed = 200, + NotAllowed = 403, + NotSupported = 501, +} diff --git a/Modules/Licensing/UI/Events/LicenseNotificationDispatcher.cs b/Modules/Licensing/UI/Events/LicenseNotificationDispatcher.cs index 2cd27ac52e..8862cf635d 100644 --- a/Modules/Licensing/UI/Events/LicenseNotificationDispatcher.cs +++ b/Modules/Licensing/UI/Events/LicenseNotificationDispatcher.cs @@ -3,6 +3,8 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using System.Collections.Generic; +using UnityEditor.Licensing.UI.Data.Events; using UnityEditor.Licensing.UI.Data.Events.Base; using UnityEditor.Licensing.UI.Helper; using UnityEngine; @@ -14,6 +16,10 @@ class LicenseNotificationDispatcher : INotificationDispatcher ILicenseNotificationHandlerFactory m_NotificationHandlerFactory; ILicenseLogger m_LicenseLogger; readonly INativeApiWrapper m_NativeApiWrapper; + List m_IgnorableNotifications = new () + { + NotificationType.BorrowFeatureStatus + }; public LicenseNotificationDispatcher(ILicenseNotificationHandlerFactory notificationHandlerFactory, ILicenseLogger licenseLogger, INativeApiWrapper nativeApiWrapper) @@ -35,6 +41,13 @@ public void Dispatch(string jsonNotification) try { + var notificationType = notificationBase.NotificationTypeAsEnum; + + if (m_IgnorableNotifications.Contains(notificationType)) + { + return; + } + var notificationHandler = m_NotificationHandlerFactory.GetHandler(notificationBase.NotificationTypeAsEnum, jsonNotification); notificationHandler.Handle(m_NativeApiWrapper.IsHumanControllingUs()); } diff --git a/Modules/PackageManagerUI/Editor/Extensions/ExtensionManager.cs b/Modules/PackageManagerUI/Editor/Extensions/ExtensionManager.cs index bbf0715eec..c903eff584 100644 --- a/Modules/PackageManagerUI/Editor/Extensions/ExtensionManager.cs +++ b/Modules/PackageManagerUI/Editor/Extensions/ExtensionManager.cs @@ -15,7 +15,7 @@ internal interface IExtensionManager : IService DetailsExtension CreateDetailsExtension(); PackageExtensionAction CreatePackageActionButton(); PackageExtensionAction CreatePackageActionMenu(); - void SendPackageSelectionChangedEvent(IPackage package, IPackageVersion version); + void SendPackageSelectionChangedEvent(IPackage package); void OnWindowCreated(IWindow window, VisualElement detailsExtensionContainer, VisualElement toolbarExtensionsContainer); void OnWindowDestroy(); } @@ -29,7 +29,7 @@ class EventDispatcher private IWindow m_Window = null; // This is to keep track of the selection that happens during the initialization process - private Tuple m_DelayedPackageSelection = null; + private IPackage m_DelayedPackageSelection = null; // We keep a dictionary of objects so that we only create one instance for one type // and if a developer implements multiple interfaces with one class we won't create multiple instances @@ -95,7 +95,7 @@ public void SendWindowCreatedEvent(IWindow window) // This is the delayed `OnPackageSelectionChanged` call during initialization. Check `OnPackageSelectionChanged` for more details. if (m_DelayedPackageSelection != null) { - SendPackageSelectionChangedEvent(m_DelayedPackageSelection.Item1, m_DelayedPackageSelection.Item2); + SendPackageSelectionChangedEvent(m_DelayedPackageSelection); m_DelayedPackageSelection = null; } } @@ -120,14 +120,14 @@ public void SendWindowDestroyEvent() m_Window = null; } - public void SendPackageSelectionChangedEvent(IPackage package, IPackageVersion version) + public void SendPackageSelectionChangedEvent(IPackage package) { // Due to the way the Package Manager window initializes, the first `OnPackageSelectionChanged` would happen before the `OnWindowCreated` // That means the first time `OnPackageSelectionChanged` is triggered, the window is not fully ready and `m_Window` is null // Hence we want to delay calling this first `OnPackageSelectionChanged` until the window is created in `OnWindowCreated` if (m_Window == null) { - m_DelayedPackageSelection = new Tuple(package, version); + m_DelayedPackageSelection = package; return; } @@ -135,7 +135,7 @@ public void SendPackageSelectionChangedEvent(IPackage package, IPackageVersion v { try { - var args = new PackageSelectionArgs { package = package, packageVersion = version, window = m_Window }; + var args = new PackageSelectionArgs { package = package, packageVersion = package?.versions.primary, window = m_Window }; extension.OnPackageSelectionChanged(args); } catch (Exception exception) @@ -147,7 +147,7 @@ public void SendPackageSelectionChangedEvent(IPackage package, IPackageVersion v } private EventDispatcher m_EventDispatcher = new EventDispatcher(); - public void SendPackageSelectionChangedEvent(IPackage package, IPackageVersion version) => m_EventDispatcher.SendPackageSelectionChangedEvent(package, version); + public void SendPackageSelectionChangedEvent(IPackage package) => m_EventDispatcher.SendPackageSelectionChangedEvent(package); private IWindow m_Window = null; private VisualElement m_DetailsExtensionContainer; diff --git a/Modules/PackageManagerUI/Editor/Extensions/PackageSelectionArgs.cs b/Modules/PackageManagerUI/Editor/Extensions/PackageSelectionArgs.cs index 03d5a84749..7b44841f93 100644 --- a/Modules/PackageManagerUI/Editor/Extensions/PackageSelectionArgs.cs +++ b/Modules/PackageManagerUI/Editor/Extensions/PackageSelectionArgs.cs @@ -20,9 +20,9 @@ internal struct PackageSelectionArgs public IPackageVersion packageVersion { get; internal set; } /// - /// The selected package versions + /// The selected packages /// - public IPackageVersion[] versions { get; internal set; } + public IPackage[] packages { get; internal set; } /// /// The handle to the Package Manager window diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IPage.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IPage.cs index 81e126bf3e..db725a9339 100644 --- a/Modules/PackageManagerUI/Editor/Services/Interfaces/IPage.cs +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IPage.cs @@ -81,9 +81,9 @@ internal interface IPage void Load(string packageUniqueId); void LoadExtraItems(IEnumerable packages); - bool SetNewSelection(IPackage package, IPackageVersion version = null, bool isExplicitUserSelection = false); - bool SetNewSelection(IEnumerable packageAndVersionIdPairs, bool isExplicitUserSelection = false); - void RemoveSelection(IEnumerable toRemove, bool isExplicitUserSelection = false); + bool SetNewSelection(IPackage package, bool isExplicitUserSelection = false); + bool SetNewSelection(IEnumerable packageUniqueIds, bool isExplicitUserSelection = false); + void RemoveSelection(IEnumerable packageUniqueIds, bool isExplicitUserSelection = false); bool ToggleSelection(string packageUniqueId, bool isExplicitUserSelection = false); bool UpdateSelectionIfCurrentSelectionIsInvalid(); void TriggerOnSelectionChanged(bool isExplicitUserSelection = false); diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/AddAction.cs b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/AddAction.cs index 655a539013..28496e91b7 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/AddAction.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/AddAction.cs @@ -25,12 +25,13 @@ public AddAction(IPackageOperationDispatcher operationDispatcher, IApplicationPr m_PackageDatabase = packageDatabase; } - protected override bool TriggerActionImplementation(IList versions) + protected override bool TriggerActionImplementation(IList packages) { - m_OperationDispatcher.Install(versions); + var primaryVersions = packages.Select(p => p.versions.primary).ToArray(); + m_OperationDispatcher.Install(primaryVersions); // The current multi-select UI does not allow users to install non-recommended versions // Should this change in the future, we'll need to update the analytics event accordingly. - PackageManagerWindowAnalytics.SendEvent("installNewRecommended", versions); + PackageManagerWindowAnalytics.SendEvent("installNewRecommended", primaryVersions); return true; } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/CancelDownloadAction.cs b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/CancelDownloadAction.cs index 4653c1eef7..0d51478516 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/CancelDownloadAction.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/CancelDownloadAction.cs @@ -21,10 +21,10 @@ public CancelDownloadAction(IPackageOperationDispatcher operationDispatcher, IAs public override Icon icon => Icon.Cancel; - protected override bool TriggerActionImplementation(IList versions) + protected override bool TriggerActionImplementation(IList packages) { - m_OperationDispatcher.AbortDownload(versions.Select(v => v.package)); - PackageManagerWindowAnalytics.SendEvent("abortDownload", versions); + m_OperationDispatcher.AbortDownload(packages); + PackageManagerWindowAnalytics.SendEvent("abortDownload", packages.Select(p => p.versions.primary)); return true; } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/DeselectAction.cs b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/DeselectAction.cs index a8f350db8c..0557e46521 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/DeselectAction.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/DeselectAction.cs @@ -18,17 +18,18 @@ public DeselectAction(IPageManager pageManager, string analyticsEventName = null m_AnalyticsEventName = analyticsEventName; } - protected override bool TriggerActionImplementation(IList versions) + protected override bool TriggerActionImplementation(IList packages) { - m_PageManager.activePage.RemoveSelection(versions.Select(v => new PackageAndVersionIdPair(v.package.uniqueId, v.uniqueId))); + var packageUniqueIds = packages.Select(p => p.uniqueId).ToArray(); + m_PageManager.activePage.RemoveSelection(packageUniqueIds); if (!string.IsNullOrEmpty(m_AnalyticsEventName)) - PackageManagerWindowAnalytics.SendEvent(m_AnalyticsEventName, packageIds: versions.Select(v => v.package.uniqueId)); + PackageManagerWindowAnalytics.SendEvent(m_AnalyticsEventName, packageIds: packageUniqueIds); return true; } protected override bool TriggerActionImplementation(IPackageVersion version) { - m_PageManager.activePage.RemoveSelection(new[] { new PackageAndVersionIdPair(version.package.uniqueId, version.uniqueId) }); + m_PageManager.activePage.RemoveSelection(new[] { version.package.uniqueId }); return true; } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/DownloadActionBase.cs b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/DownloadActionBase.cs index fe94e98c5b..f72f1aef32 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/DownloadActionBase.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/DownloadActionBase.cs @@ -27,11 +27,11 @@ protected DownloadActionBase(IPackageOperationDispatcher operationDispatcher, protected abstract string analyticEventName { get; } - protected override bool TriggerActionImplementation(IList versions) + protected override bool TriggerActionImplementation(IList packages) { - var canDownload = m_OperationDispatcher.Download(versions.Select(v => v.package)); + var canDownload = m_OperationDispatcher.Download(packages); if (canDownload) - PackageManagerWindowAnalytics.SendEvent(analyticEventName, versions); + PackageManagerWindowAnalytics.SendEvent(analyticEventName, packages.Select(p => p.versions.primary)); return canDownload; } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/PackageAction.cs b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/PackageAction.cs index 6a64232fd5..02a75ddff5 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/PackageAction.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/PackageAction.cs @@ -77,13 +77,13 @@ public void TriggerAction(IPackageVersion version) // Returns true if the action is triggered, false otherwise. protected abstract bool TriggerActionImplementation(IPackageVersion version); - public void TriggerAction(IList versions) + public void TriggerAction(IList packages) { - if (TriggerActionImplementation(versions)) + if (TriggerActionImplementation(packages)) onActionTriggered?.Invoke(); } // By default buttons does not support bulk action - protected virtual bool TriggerActionImplementation(IList versions) => false; + protected virtual bool TriggerActionImplementation(IList packages) => false; public abstract bool IsInProgress(IPackageVersion version); diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/RemoveAction.cs b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/RemoveAction.cs index c78c43cf59..885da1a711 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/RemoveAction.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/RemoveAction.cs @@ -27,10 +27,10 @@ public RemoveAction(IPackageOperationDispatcher operationDispatcher, m_PageManager = pageManager; } - protected override bool TriggerActionImplementation(IList versions) + protected override bool TriggerActionImplementation(IList packages) { - var isModules = versions.FirstOrDefault()?.HasTag(PackageTag.BuiltIn) == true; - var title = string.Format(L10n.Tr(isModules ? "Disabling {0} items" : "Removing {0} items"), versions.Count); + var isModules = packages.FirstOrDefault()?.versions.primary.HasTag(PackageTag.BuiltIn) == true; + var title = string.Format(L10n.Tr(isModules ? "Disabling {0} items" : "Removing {0} items"), packages.Count); var result = 0; if (!m_PackageManagerPrefs.skipMultiSelectRemoveConfirmation) @@ -47,10 +47,10 @@ protected override bool TriggerActionImplementation(IList versi if (result == 2) m_PackageManagerPrefs.skipMultiSelectRemoveConfirmation = true; - m_OperationDispatcher.Uninstall(versions.Select(v => v.package)); - PackageManagerWindowAnalytics.SendEvent("uninstall", versions); + m_OperationDispatcher.Uninstall(packages); + PackageManagerWindowAnalytics.SendEvent("uninstall", packages.Select(p => p.versions.primary)); // After a bulk removal, we want to deselect them to avoid installing them back by accident. - DeselectVersions(versions); + DeselectPackages(packages); return true; } @@ -162,8 +162,8 @@ protected override IEnumerable GetAllDisableConditions(IPackag yield return new DisableIfInstalledAsDependency(version); } - private void DeselectVersions(IList versions) + private void DeselectPackages(IList packages) { - m_PageManager.activePage.RemoveSelection(versions.Select(v => new PackageAndVersionIdPair(v.package.uniqueId, v.uniqueId))); + m_PageManager.activePage.RemoveSelection(packages.Select(p => p.uniqueId)); } } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/RemoveImportedAction.cs b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/RemoveImportedAction.cs index 440f0b01eb..eacb02b293 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/RemoveImportedAction.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/RemoveImportedAction.cs @@ -24,15 +24,15 @@ protected override bool TriggerActionImplementation(IPackageVersion version) return true; } - protected override bool TriggerActionImplementation(IList versions) + protected override bool TriggerActionImplementation(IList packages) { if (!m_Application.DisplayDialog("removeMultiImported", L10n.Tr("Removing imported packages"), L10n.Tr("Remove all assets from these packages?\nAny changes you made to the assets will be lost."), L10n.Tr("Remove"), L10n.Tr("Cancel"))) return false; - m_OperationDispatcher.RemoveImportedAssets(versions); - PackageManagerWindowAnalytics.SendEvent("removeImported", versions); + m_OperationDispatcher.RemoveImportedAssets(packages); + PackageManagerWindowAnalytics.SendEvent("removeImported", packages.Select(p => p.versions.primary)); return true; } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/UnlockAction.cs b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/UnlockAction.cs index 214c854167..6d6a46191b 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/UnlockAction.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/UnlockAction.cs @@ -15,10 +15,11 @@ public UnlockAction(IPageManager pageManager) m_PageManager = pageManager; } - protected override bool TriggerActionImplementation(IList versions) + protected override bool TriggerActionImplementation(IList packages) { - m_PageManager.activePage.SetPackagesUserUnlockedState(versions.Select(v => v.package.uniqueId), true); - PackageManagerWindowAnalytics.SendEvent("unlock", packageIds: versions.Select(v => v.package.uniqueId)); + var packageUniqueIds = packages.Select(p => p.uniqueId).ToArray(); + m_PageManager.activePage.SetPackagesUserUnlockedState(packageUniqueIds, true); + PackageManagerWindowAnalytics.SendEvent("unlock", packageIds: packageUniqueIds); return true; } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/UpdateAction.cs b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/UpdateAction.cs index 111ccde559..88d559558d 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/UpdateAction.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/UpdateAction.cs @@ -33,12 +33,12 @@ public UpdateAction(IPackageOperationDispatcher operationDispatcher, m_ShowVersion = showVersion; } - protected override bool TriggerActionImplementation(IList versions) + protected override bool TriggerActionImplementation(IList packages) { - m_OperationDispatcher.Install(versions.Select(v => v?.package?.versions.GetUpdateTarget(v))); + m_OperationDispatcher.Install(packages.Select(p => p?.versions.GetUpdateTarget(p.versions.primary))); // The current multi-select UI does not allow users to install non-recommended versions // Should this change in the future, we'll need to update the analytics event accordingly. - PackageManagerWindowAnalytics.SendEvent("installUpdateRecommended", versions); + PackageManagerWindowAnalytics.SendEvent("installUpdateRecommended", packages.Select(p => p.versions.primary)); return true; } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageAndVersionIdPair.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageAndVersionIdPair.cs deleted file mode 100644 index fd4289c059..0000000000 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageAndVersionIdPair.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; - -namespace UnityEditor.PackageManager.UI.Internal -{ - [Serializable] - internal class PackageAndVersionIdPair - { - public PackageAndVersionIdPair(string packageUniqueId, string versionUniqueId = null) - { - this.packageUniqueId = packageUniqueId; - this.versionUniqueId = versionUniqueId; - } - - public string packageUniqueId; - public string versionUniqueId; - } -} diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageDatabase.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageDatabase.cs index d8254afe79..dafa936883 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageDatabase.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageDatabase.cs @@ -23,8 +23,6 @@ internal interface IPackageDatabase : IService IPackage GetPackage(long productId); void GetPackageAndVersionByIdOrName(string idOrName, out IPackage package, out IPackageVersion version, bool bruteForceSearch); IPackage GetPackageByIdOrName(string idOrName); - void GetPackageAndVersion(string packageUniqueId, string versionUniqueId, out IPackage package, out IPackageVersion version); - void GetPackageAndVersion(PackageAndVersionIdPair pair, out IPackage package, out IPackageVersion version); void GetPackageAndVersion(DependencyInfo info, out IPackage package, out IPackageVersion version); IEnumerable GetReverseDependencies(IPackageVersion version, bool directDependenciesOnly = false); IEnumerable GetFeaturesThatUseThisPackage(IPackageVersion version); @@ -87,22 +85,17 @@ public PackageDatabase(IUniqueIdMapper uniqueIdMapper, public IEnumerable allPackages => m_Packages.Values; - public IPackage GetPackage(string uniqueId) - { - return GetPackage(uniqueId, false); - } - public IPackage GetPackage(long productId) { - return GetPackage(productId.ToString(), false); + return GetPackage(productId.ToString()); } - private IPackage GetPackage(string uniqueId, bool retryWithIdMapper) + public IPackage GetPackage(string uniqueId) { if (string.IsNullOrEmpty(uniqueId)) return null; var package = m_Packages.Get(uniqueId); - if (package != null || !retryWithIdMapper) + if (package != null) return package; // We only retry with productId now because in the case where productId and package Name both exist for a package @@ -116,7 +109,7 @@ private IPackage GetPackage(string uniqueId, bool retryWithIdMapper) public void GetPackageAndVersionByIdOrName(string idOrName, out IPackage package, out IPackageVersion version, bool bruteForceSearch) { // GetPackage by packageUniqueId itself is not an expensive operation, so we want to try and see if the input string is a packageUniqueId first. - package = GetPackage(idOrName, true); + package = GetPackage(idOrName); if (package != null) { version = null; @@ -128,9 +121,12 @@ public void GetPackageAndVersionByIdOrName(string idOrName, out IPackage package if (idOrDisplayNameSplit?.Length == 2) { var packageUniqueId = idOrDisplayNameSplit[0]; - GetPackageAndVersion(packageUniqueId, idOrName, out package, out version); + package = GetPackage(packageUniqueId); if (package != null) + { + version = package.versions.FirstOrDefault(v => v.uniqueId == idOrName); return; + } } // If none of those find-by-index options work, we'll just have to find it the brute force way by matching the name & display name @@ -144,17 +140,6 @@ public IPackage GetPackageByIdOrName(string idOrName) return package; } - public void GetPackageAndVersion(string packageUniqueId, string versionUniqueId, out IPackage package, out IPackageVersion version) - { - package = GetPackage(packageUniqueId, true); - version = package?.versions.FirstOrDefault(v => v.uniqueId == versionUniqueId); - } - - public void GetPackageAndVersion(PackageAndVersionIdPair pair, out IPackage package, out IPackageVersion version) - { - GetPackageAndVersion(pair?.packageUniqueId, pair?.versionUniqueId, out package, out version); - } - public void GetPackageAndVersion(DependencyInfo info, out IPackage package, out IPackageVersion version) { package = GetPackage(info.name); diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageOperationDispatcher.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageOperationDispatcher.cs index f83edd18d5..1a2801aa2e 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageOperationDispatcher.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageOperationDispatcher.cs @@ -39,7 +39,7 @@ internal interface IPackageOperationDispatcher : IService void Import(IPackage package); void RemoveImportedAssets(IPackage package); - void RemoveImportedAssets(IEnumerable versions); + void RemoveImportedAssets(IEnumerable packages); } internal class PackageOperationDispatcher : BaseService, IPackageOperationDispatcher @@ -197,12 +197,12 @@ public void RemoveImportedAssets(IPackage package) m_AssetStorePackageInstaller.Uninstall(package.product.id, true); } - public void RemoveImportedAssets(IEnumerable versions) + public void RemoveImportedAssets(IEnumerable packages) { - if (versions?.Any() != true) + if (packages?.Any() != true) return; - m_AssetStorePackageInstaller.Uninstall(versions.Select(v => v.package.product.id)); + m_AssetStorePackageInstaller.Uninstall(packages.Select(p => p.product.id)); } } } diff --git a/Modules/PackageManagerUI/Editor/Services/Pages/BasePage.cs b/Modules/PackageManagerUI/Editor/Services/Pages/BasePage.cs index eabcc71db5..2914420add 100644 --- a/Modules/PackageManagerUI/Editor/Services/Pages/BasePage.cs +++ b/Modules/PackageManagerUI/Editor/Services/Pages/BasePage.cs @@ -157,7 +157,7 @@ private void OnPackageUniqueIdFinalize(string tempPackageUniqueId, string finalP { if (!GetSelection().Contains(tempPackageUniqueId)) return; - AmendSelection(new[] { new PackageAndVersionIdPair(finalPackageUniqueId) }, new[] { new PackageAndVersionIdPair(tempPackageUniqueId) }); + AmendSelection(new[] { finalPackageUniqueId }, new[] { tempPackageUniqueId }); } public void UpdateVisualStateVisibilityWithSearchText() @@ -265,37 +265,37 @@ public virtual void TriggerOnSelectionChanged(bool isExplicitUserSelection = fal public IEnumerable GetSelectedVisualStates() { - return m_Selection.Select(s => visualStates.Get(s?.packageUniqueId)).Where(v => v != null); + return m_Selection.Select(s => visualStates.Get(s)).Where(v => v != null); } - public virtual bool SetNewSelection(IPackage package, IPackageVersion version = null, bool isExplicitUserSelection = false) + public virtual bool SetNewSelection(IPackage package, bool isExplicitUserSelection = false) { - return SetNewSelection(new[] { new PackageAndVersionIdPair(package?.uniqueId, version?.uniqueId) }, isExplicitUserSelection); + return SetNewSelection(new[] { package?.uniqueId }, isExplicitUserSelection); } - public virtual bool SetNewSelection(PackageAndVersionIdPair packageAndVersionId, bool isExplicitUserSelection = false) + public virtual bool SetNewSelection(string packageUniqueId, bool isExplicitUserSelection = false) { - return SetNewSelection(new[] { packageAndVersionId }, isExplicitUserSelection); + return SetNewSelection(new[] { packageUniqueId }, isExplicitUserSelection); } - public virtual bool SetNewSelection(IEnumerable packageAndVersionIds, bool isExplicitUserSelection = false) + public virtual bool SetNewSelection(IEnumerable packageUniqueIds, bool isExplicitUserSelection = false) { - if (!m_Selection.SetNewSelection(packageAndVersionIds) && !isExplicitUserSelection) + if (!m_Selection.SetNewSelection(packageUniqueIds) && !isExplicitUserSelection) return false; TriggerOnSelectionChanged(isExplicitUserSelection); return true; } - public virtual void RemoveSelection(IEnumerable toRemove, bool isExplicitUserSelection = false) + public virtual void RemoveSelection(IEnumerable toRemove, bool isExplicitUserSelection = false) { var previousFirstSelection = GetSelection().firstSelection; - AmendSelection(Enumerable.Empty(), toRemove, isExplicitUserSelection); + AmendSelection(Enumerable.Empty(), toRemove, isExplicitUserSelection); if (!GetSelection().Any()) SetNewSelection(new[] { previousFirstSelection }, isExplicitUserSelection); } - public virtual bool AmendSelection(IEnumerable toAddOrUpdate, IEnumerable toRemove, bool isExplicitUserSelection = false) + public virtual bool AmendSelection(IEnumerable toAddOrUpdate, IEnumerable toRemove, bool isExplicitUserSelection = false) { if (!m_Selection.AmendSelection(toAddOrUpdate, toRemove) && !isExplicitUserSelection) return false; @@ -317,24 +317,24 @@ public virtual bool UpdateSelectionIfCurrentSelectionIsInvalid() { var selection = GetSelection(); - var invalidSelectionsToRemove = new List(); - foreach (var item in selection) + var invalidSelectionsToRemove = new List(); + foreach (var packageUniqueId in selection) { - m_PackageDatabase.GetPackageAndVersion(item, out var package, out var _); - var visualState = visualStates.Get(item.packageUniqueId); + var package = m_PackageDatabase.GetPackage(packageUniqueId); + var visualState = visualStates.Get(packageUniqueId); if (package == null || visualState?.visible != true) - invalidSelectionsToRemove.Add(item); + invalidSelectionsToRemove.Add(packageUniqueId); } if (selection.Count > 0 && invalidSelectionsToRemove.Count == 0) return false; - var newSelectionToAdd = new List(); + var newSelectionToAdd = new List(); if (invalidSelectionsToRemove.Count == selection.Count) { var firstVisible = visualStates.FirstOrDefault(v => v.visible && !selection.Contains(v.packageUniqueId)); if (firstVisible != null) - newSelectionToAdd.Add(new PackageAndVersionIdPair(firstVisible.packageUniqueId)); + newSelectionToAdd.Add(firstVisible.packageUniqueId); } return AmendSelection(newSelectionToAdd, invalidSelectionsToRemove); diff --git a/Modules/PackageManagerUI/Editor/Services/Pages/PageManager.cs b/Modules/PackageManagerUI/Editor/Services/Pages/PageManager.cs index 860bb3cffa..5cc5cf8ea4 100644 --- a/Modules/PackageManagerUI/Editor/Services/Pages/PageManager.cs +++ b/Modules/PackageManagerUI/Editor/Services/Pages/PageManager.cs @@ -28,8 +28,8 @@ internal interface IPageManager : IService void AddExtensionPage(ExtensionPageArgs args); IPage GetPage(string pageId); IPage GetPage(RegistryInfo registryInfo); - IPage FindPage(IPackage package, IPackageVersion version = null); - IPage FindPage(IList packageVersions); + IPage FindPage(IPackage package); + IPage FindPage(IList packages); void OnWindowDestroy(); } @@ -228,22 +228,22 @@ private void OnUserLoginStateChange(bool userInfoReady, bool loggedIn) GetPage(MyAssetsPage.k_Id).ClearFilters(true); } - public IPage FindPage(IPackage package, IPackageVersion version = null) + public IPage FindPage(IPackage package) { - return FindPage(new[] { version ?? package?.versions.primary }); + return FindPage(new[] { package}); } - public IPage FindPage(IList packageVersions) + public IPage FindPage(IList packages) { - if (packageVersions?.Any() != true || packageVersions.All(v => activePage.visualStates.Contains(v.package.uniqueId) || activePage.ShouldInclude(v.package))) + if (packages?.Any() != true || packages.All(p => activePage.visualStates.Contains(p.uniqueId) || activePage.ShouldInclude(p))) return activePage; var pageIdsToCheck = new[] { BuiltInPage.k_Id, InProjectPage.k_Id, UnityRegistryPage.k_Id, MyAssetsPage.k_Id, MyRegistriesPage.k_Id}; foreach (var page in pageIdsToCheck.Select(GetPage).Where(p => !p.isActivePage)) - if (packageVersions.All(v => page.ShouldInclude(v.package))) + if (packages.All(p => page.ShouldInclude(p))) return page; - if (!m_SettingsProxy.enablePreReleasePackages && packageVersions.Any(v => v.version?.Prerelease.StartsWith("pre.") == true)) + if (!m_SettingsProxy.enablePreReleasePackages && packages.Any(p => p.versions.primary.version?.Prerelease.StartsWith("pre.") == true)) Debug.Log(L10n.Tr("You must check \"Enable Pre-release Packages\" in Project Settings > Package Manager in order to see this package.")); return null; } diff --git a/Modules/PackageManagerUI/Editor/Services/Pages/PageSelection.cs b/Modules/PackageManagerUI/Editor/Services/Pages/PageSelection.cs index a0d4fe0e5f..10e8dec675 100644 --- a/Modules/PackageManagerUI/Editor/Services/Pages/PageSelection.cs +++ b/Modules/PackageManagerUI/Editor/Services/Pages/PageSelection.cs @@ -12,39 +12,41 @@ namespace UnityEditor.PackageManager.UI.Internal { [Serializable] - internal class PageSelection : IEnumerable, ISerializationCallbackReceiver + internal class PageSelection : IEnumerable, ISerializationCallbackReceiver { - private IEnumerable m_PreviousSelections = Enumerable.Empty(); + private IEnumerable m_PreviousSelections = Enumerable.Empty(); - private Dictionary m_SelectionsLookup = new Dictionary(); + private HashSet m_SelectionsLookup = new (); + // The order of the selection is the order in which the user selects the packages. + // We keep track of it to make sure that if the user uses the keyboard to move in the package list, we start from their last selection [SerializeField] - private List m_OrderedSelections = new List(); + private List m_OrderedSelections = new (); [SerializeField] - private PackageAndVersionIdPair[] m_SerializedSelectionsLookup = new PackageAndVersionIdPair[0]; + private string[] m_SerializedSelectionsLookup = Array.Empty(); - public IEnumerable previousSelections => m_PreviousSelections; - public IEnumerable orderedSelections => m_OrderedSelections.Select(s => TryGetValue(s, out var value) ? value : null).Where(s => s != null); + public IEnumerable previousSelections => m_PreviousSelections; + public IEnumerable orderedSelections => m_OrderedSelections.Where(s => Contains(s)); - public PackageAndVersionIdPair firstSelection => orderedSelections.FirstOrDefault(); - public PackageAndVersionIdPair lastSelection => orderedSelections.LastOrDefault(); + public string firstSelection => orderedSelections.FirstOrDefault(); + public string lastSelection => orderedSelections.LastOrDefault(); // Normally we begin with lower case for public attribute, but `Count` is a very common container attribute, we want to make it consistent with System collections. public int Count => m_SelectionsLookup.Count; - public bool SetNewSelection(IEnumerable packageAndVersionIds) + public bool SetNewSelection(IEnumerable packageUniqueIds) { - var newSelectionLookup = packageAndVersionIds.ToDictionary(s => s.packageUniqueId, s => s); - var selectionUpdated = newSelectionLookup.Values.Any(s => !m_SelectionsLookup.TryGetValue(s.packageUniqueId, out var oldSelection) || oldSelection.versionUniqueId != s.versionUniqueId) - || m_SelectionsLookup.Values.Any(s => !newSelectionLookup.TryGetValue(s.packageUniqueId, out var newSelection) || newSelection.versionUniqueId != s.versionUniqueId); + var newSelectionLookup = packageUniqueIds.ToHashSet(); + var selectionUpdated = newSelectionLookup.Any(s => !m_SelectionsLookup.Contains(s)) + || m_SelectionsLookup.Any(s => !newSelectionLookup.Contains(s)); if (selectionUpdated) { m_PreviousSelections = orderedSelections.ToArray(); m_SelectionsLookup = newSelectionLookup; - m_OrderedSelections = packageAndVersionIds.Select(s => s.packageUniqueId).ToList(); + m_OrderedSelections = packageUniqueIds.ToList(); } return selectionUpdated; } @@ -52,30 +54,26 @@ public bool SetNewSelection(IEnumerable packageAndVersi private void TrimOrderedSelection() { if (m_OrderedSelections.Count != m_SelectionsLookup.Count) - m_OrderedSelections = m_OrderedSelections.Where(s => Contains(s)).ToList() ; + m_OrderedSelections = m_OrderedSelections.Where(s => Contains(s)).ToList(); } - public bool AmendSelection(IEnumerable toAddOrUpdate, IEnumerable toRemove) + public bool AmendSelection(IEnumerable toAddOrUpdate, IEnumerable toRemove) { - var itemsToAdd = toAddOrUpdate?.Where(item => !TryGetValue(item.packageUniqueId, out var value)).ToArray() ?? new PackageAndVersionIdPair[0]; - var itemsToUpdate = toAddOrUpdate?.Where(item => TryGetValue(item.packageUniqueId, out var value) && item.versionUniqueId != value.versionUniqueId).ToArray() ?? new PackageAndVersionIdPair[0]; - var itemsToRemove = toRemove?.Where(item => Contains(item.packageUniqueId)).ToArray() ?? new PackageAndVersionIdPair[0]; - if (!itemsToAdd.Any() && !itemsToUpdate.Any() && !itemsToRemove.Any()) + var itemsToAdd = toAddOrUpdate?.Where(s => !Contains(s)).ToArray() ?? Array.Empty(); + var itemsToRemove = toRemove?.Where(s => Contains(s)).ToArray() ?? Array.Empty(); + if (!itemsToAdd.Any() && !itemsToRemove.Any()) return false; m_PreviousSelections = orderedSelections.ToArray(); foreach (var item in itemsToAdd) { - m_SelectionsLookup[item.packageUniqueId] = item; - m_OrderedSelections.Add(item.packageUniqueId); + m_SelectionsLookup.Add(item); + m_OrderedSelections.Add(item); } - foreach (var item in itemsToUpdate) - m_SelectionsLookup[item.packageUniqueId] = item; - foreach (var item in itemsToRemove) - m_SelectionsLookup.Remove(item.packageUniqueId); + m_SelectionsLookup.Remove(item); TrimOrderedSelection(); @@ -93,7 +91,7 @@ public bool ToggleSelection(string packageUniqueId) m_PreviousSelections = orderedSelections.ToArray(); if (!packageSelected) { - m_SelectionsLookup.Add(packageUniqueId, new PackageAndVersionIdPair(packageUniqueId)); + m_SelectionsLookup.Add(packageUniqueId); m_OrderedSelections.Add(packageUniqueId); } else @@ -106,34 +104,29 @@ public bool ToggleSelection(string packageUniqueId) public void OnBeforeSerialize() { - m_SerializedSelectionsLookup = m_SelectionsLookup.Values.ToArray(); + m_SerializedSelectionsLookup = m_SelectionsLookup.ToArray(); } public void OnAfterDeserialize() { - m_SelectionsLookup = m_SerializedSelectionsLookup.ToDictionary(s => s.packageUniqueId, s => s); + m_SelectionsLookup = m_SerializedSelectionsLookup.ToHashSet(); } public bool Contains(string packageUniqueId) { - return m_SelectionsLookup.ContainsKey(packageUniqueId); - } - - public bool TryGetValue(string packageUniqueId, out PackageAndVersionIdPair value) - { - return m_SelectionsLookup.TryGetValue(packageUniqueId, out value); + return m_SelectionsLookup.Contains(packageUniqueId); } [ExcludeFromCodeCoverage] - public IEnumerator GetEnumerator() + public IEnumerator GetEnumerator() { - return m_SelectionsLookup.Values.Cast().GetEnumerator(); + return m_SelectionsLookup.Cast().GetEnumerator(); } [ExcludeFromCodeCoverage] IEnumerator IEnumerable.GetEnumerator() { - return m_SelectionsLookup.Values.GetEnumerator(); + return m_SelectionsLookup.GetEnumerator(); } } } diff --git a/Modules/PackageManagerUI/Editor/Services/Pages/PageTypes/MyAssetsPage.cs b/Modules/PackageManagerUI/Editor/Services/Pages/PageTypes/MyAssetsPage.cs index ab8ea7e641..1aad922e89 100644 --- a/Modules/PackageManagerUI/Editor/Services/Pages/PageTypes/MyAssetsPage.cs +++ b/Modules/PackageManagerUI/Editor/Services/Pages/PageTypes/MyAssetsPage.cs @@ -140,7 +140,7 @@ public override void Load(string packageUniqueId) else TriggerOnListUpdate(updated: new[] { package }); - SetNewSelection(new[] { new PackageAndVersionIdPair(package.uniqueId, version?.uniqueId) }); + SetNewSelection(new[] { package.uniqueId }); } } @@ -172,7 +172,7 @@ public void OnProductExtraFetched(long productId) TriggerOnListUpdate(added: new[] { package }); else TriggerOnListUpdate(updated: new[] { package }); - SetNewSelection(new[] { new PackageAndVersionIdPair(package.uniqueId) }); + SetNewSelection(new[] { package.uniqueId }); } public void OnProductListFetched(AssetStorePurchases purchases) diff --git a/Modules/PackageManagerUI/Editor/UI/AddPackageByNameDropdown.cs b/Modules/PackageManagerUI/Editor/UI/AddPackageByNameDropdown.cs index 010980feff..431bce594d 100644 --- a/Modules/PackageManagerUI/Editor/UI/AddPackageByNameDropdown.cs +++ b/Modules/PackageManagerUI/Editor/UI/AddPackageByNameDropdown.cs @@ -182,7 +182,7 @@ private void InstallByNameAndVersion(string packageName, string packageVersion = if (page != null) { m_PageManager.activePage = page; - page.SetNewSelection(package, package.versions?.FirstOrDefault(v => v.versionString == packageVersion)); + page.SetNewSelection(package); } } diff --git a/Modules/PackageManagerUI/Editor/UI/Common/InspectorSelectionHandler.cs b/Modules/PackageManagerUI/Editor/UI/Common/InspectorSelectionHandler.cs index 08da2669a1..23a5369980 100644 --- a/Modules/PackageManagerUI/Editor/UI/Common/InspectorSelectionHandler.cs +++ b/Modules/PackageManagerUI/Editor/UI/Common/InspectorSelectionHandler.cs @@ -11,8 +11,8 @@ namespace UnityEditor.PackageManager.UI.Internal { internal interface IInspectorSelectionHandler : IService { - PackageSelectionObject GetPackageSelectionObject(PackageAndVersionIdPair pair, bool createIfNotFound = false); - PackageSelectionObject GetPackageSelectionObject(IPackage package, IPackageVersion version = null, bool createIfNotFound = false); + PackageSelectionObject GetPackageSelectionObject(string packageUniqueId, bool createIfNotFound = false); + PackageSelectionObject GetPackageSelectionObject(IPackage package, bool createIfNotFound = false); } [Serializable] @@ -42,24 +42,24 @@ public void OnAfterDeserialize() {} private void OnEditorSelectionChanged() { - var selectionIds = new List(); - var selectedVersions = new List(); + var selectionIds = new List(); + var selectedPackages = new List(); foreach (var selectionObject in m_Selection.objects) { var packageSelectionObject = selectionObject as PackageSelectionObject; if (packageSelectionObject == null) return; - m_PackageDatabase.GetPackageAndVersion(packageSelectionObject.packageUniqueId, packageSelectionObject.versionUniqueId, out var package, out var version); - if (package == null && version == null) + var package = m_PackageDatabase.GetPackage(packageSelectionObject.packageUniqueId); + if (package == null) continue; - selectedVersions.Add(version ?? package?.versions.primary); - selectionIds.Add(new PackageAndVersionIdPair(packageSelectionObject.packageUniqueId, packageSelectionObject.versionUniqueId)); + selectedPackages.Add(package); + selectionIds.Add(packageSelectionObject.packageUniqueId); } if (!selectionIds.Any()) return; - var page = m_PageManager.FindPage(selectedVersions); + var page = m_PageManager.FindPage(selectedPackages); if (page != null) { m_PageManager.activePage = page; @@ -83,19 +83,19 @@ private void OnPageSelectionChanged(PageSelectionChangeArgs args) } } - public PackageSelectionObject GetPackageSelectionObject(PackageAndVersionIdPair pair, bool createIfNotFound = false) + public PackageSelectionObject GetPackageSelectionObject(string packageUniqueId, bool createIfNotFound = false) { - m_PackageDatabase.GetPackageAndVersion(pair?.packageUniqueId, pair?.versionUniqueId, out var package, out var version); - return GetPackageSelectionObject(package, version, createIfNotFound); + var package = m_PackageDatabase.GetPackage(packageUniqueId); + return GetPackageSelectionObject(package, createIfNotFound); } // The virtual keyword is needed for unit tests - public virtual PackageSelectionObject GetPackageSelectionObject(IPackage package, IPackageVersion version = null, bool createIfNotFound = false) + public virtual PackageSelectionObject GetPackageSelectionObject(IPackage package, bool createIfNotFound = false) { if (package == null) return null; - var uniqueId = version?.uniqueId ?? package.uniqueId; + var uniqueId = package.uniqueId; var packageSelectionObject = m_PackageSelectionObjects.Get(uniqueId); if (packageSelectionObject == null && createIfNotFound) { @@ -104,7 +104,6 @@ public virtual PackageSelectionObject GetPackageSelectionObject(IPackage package packageSelectionObject.name = package.displayName; packageSelectionObject.displayName = package.displayName; packageSelectionObject.packageUniqueId = package.uniqueId; - packageSelectionObject.versionUniqueId = version?.uniqueId; m_PackageSelectionObjects[uniqueId] = packageSelectionObject; } return packageSelectionObject; @@ -117,7 +116,7 @@ public void OnPackagesChanged(PackagesChangeArgs args) var packageSelectionObject = GetPackageSelectionObject(package); if (packageSelectionObject != null) { - m_PackageSelectionObjects.Remove(packageSelectionObject.uniqueId); + m_PackageSelectionObjects.Remove(packageSelectionObject.packageUniqueId); UnityEngine.Object.DestroyImmediate(packageSelectionObject); } } @@ -129,7 +128,7 @@ private void InitializeSelectionObjects() { var packageSelectionObject = UnityEngine.Object.FindObjectFromInstanceID(id) as PackageSelectionObject; if (packageSelectionObject != null) - m_PackageSelectionObjects[packageSelectionObject.uniqueId] = packageSelectionObject; + m_PackageSelectionObjects[packageSelectionObject.packageUniqueId] = packageSelectionObject; } } diff --git a/Modules/PackageManagerUI/Editor/UI/InProgressDropdown.cs b/Modules/PackageManagerUI/Editor/UI/InProgressDropdown.cs index bf39efa680..6b6a134c2d 100644 --- a/Modules/PackageManagerUI/Editor/UI/InProgressDropdown.cs +++ b/Modules/PackageManagerUI/Editor/UI/InProgressDropdown.cs @@ -134,7 +134,7 @@ private void ViewPackagesOnPage(IPage page, PackageProgress progress, PackageTag { m_PageManager.activePage = page; page.LoadExtraItems(packagesInProgress); - page.SetNewSelection(packagesInProgress.Select(p => new PackageAndVersionIdPair(p.uniqueId))); + page.SetNewSelection(packagesInProgress.Select(p => p.uniqueId)); } Close(); } diff --git a/Modules/PackageManagerUI/Editor/UI/MultiSelect/CheckUpdateFoldout.cs b/Modules/PackageManagerUI/Editor/UI/MultiSelect/CheckUpdateFoldout.cs index 15e5c33360..4f41d909bc 100644 --- a/Modules/PackageManagerUI/Editor/UI/MultiSelect/CheckUpdateFoldout.cs +++ b/Modules/PackageManagerUI/Editor/UI/MultiSelect/CheckUpdateFoldout.cs @@ -18,16 +18,16 @@ public CheckUpdateFoldout(IPageManager pageManager, IAssetStoreCache assetStoreC headerTextTemplate = L10n.Tr("Checking update for {0}..."); } - public override bool AddPackageVersion(IPackageVersion version) + public override bool AddPackage(IPackage package) { - var product = version.package.product; + var product = package.product; if(product == null) return false; if (m_AssetStoreCache.GetLocalInfo(product.id) != null && m_AssetStoreCache.GetUpdateInfo(product.id) == null) { m_BackgroundFetchHandler.PushToCheckUpdateStack(product.id); - return base.AddPackageVersion(version); + return base.AddPackage(package); } return false; } diff --git a/Modules/PackageManagerUI/Editor/UI/MultiSelect/IMultiSelectFoldoutElement.cs b/Modules/PackageManagerUI/Editor/UI/MultiSelect/IMultiSelectFoldoutElement.cs index 1666ff8008..aad758ca15 100644 --- a/Modules/PackageManagerUI/Editor/UI/MultiSelect/IMultiSelectFoldoutElement.cs +++ b/Modules/PackageManagerUI/Editor/UI/MultiSelect/IMultiSelectFoldoutElement.cs @@ -7,7 +7,7 @@ namespace UnityEditor.PackageManager.UI.Internal internal interface IMultiSelectFoldoutElement { void Refresh(); - bool AddPackageVersion(IPackageVersion version); - void ClearVersions(); + bool AddPackage(IPackage package); + void ClearPackages(); } } diff --git a/Modules/PackageManagerUI/Editor/UI/MultiSelect/InstallFoldoutGroup.cs b/Modules/PackageManagerUI/Editor/UI/MultiSelect/InstallFoldoutGroup.cs index 17fea35f62..cde65902ae 100644 --- a/Modules/PackageManagerUI/Editor/UI/MultiSelect/InstallFoldoutGroup.cs +++ b/Modules/PackageManagerUI/Editor/UI/MultiSelect/InstallFoldoutGroup.cs @@ -15,12 +15,12 @@ public InstallFoldoutGroup(IApplicationProxy applicationProxy, IPackageDatabase public override void Refresh() { - if (mainFoldout.versions.FirstOrDefault()?.HasTag(PackageTag.BuiltIn) == true) + if (mainFoldout.packages.FirstOrDefault()?.versions.primary.HasTag(PackageTag.BuiltIn) == true) mainFoldout.headerTextTemplate = L10n.Tr("Enable {0}"); else mainFoldout.headerTextTemplate = L10n.Tr("Install {0}"); - if (inProgressFoldout.versions.FirstOrDefault()?.HasTag(PackageTag.BuiltIn) == true) + if (inProgressFoldout.packages.FirstOrDefault()?.versions.primary.HasTag(PackageTag.BuiltIn) == true) inProgressFoldout.headerTextTemplate = L10n.Tr("Enabling {0}"); else inProgressFoldout.headerTextTemplate = L10n.Tr("Installing {0}"); @@ -28,11 +28,11 @@ public override void Refresh() base.Refresh(); } - public override bool AddPackageVersion(IPackageVersion version) + public override bool AddPackage(IPackage package) { - if (!version.HasTag(PackageTag.UpmFormat)) + if (!package.versions.primary.HasTag(PackageTag.UpmFormat)) return false; - return base.AddPackageVersion(version); + return base.AddPackage(package); } } } diff --git a/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectDetails.cs b/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectDetails.cs index 170d45dd32..795040ae05 100644 --- a/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectDetails.cs +++ b/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectDetails.cs @@ -150,37 +150,36 @@ public bool Refresh(PageSelection selections) title.text = string.Format(L10n.Tr("{0} {1} selected"), selections.Count, selections.Count > 1 ? L10n.Tr("items") : L10n.Tr("item")); // We get the versions from the visual states instead of directly from the selection to keep the ordering of packages - var versions = m_PageManager.activePage.visualStates.Select(visualState => + var packages = m_PageManager.activePage.visualStates.Select(visualState => { - if (!selections.TryGetValue(visualState.packageUniqueId, out var pair)) + if (!selections.Contains(visualState.packageUniqueId)) return null; - m_PackageDatabase.GetPackageAndVersion(pair, out var package, out var version); - return version ?? package?.versions.primary; - }).Where(version => version != null); + return m_PackageDatabase.GetPackage(visualState.packageUniqueId); + }).Where(package => package != null); foreach (var foldoutElement in allFoldoutElements) - foldoutElement.ClearVersions(); + foldoutElement.ClearPackages(); - foreach (var version in versions) + foreach (var package in packages) { - if (m_UnlockFoldout.AddPackageVersion(version)) + if (m_UnlockFoldout.AddPackage(package)) continue; - if (m_CheckUpdateFoldout.AddPackageVersion(version)) + if (m_CheckUpdateFoldout.AddPackage(package)) continue; var isActionable = false; foreach (var foldoutGroup in m_FoldoutGroups) - isActionable |= foldoutGroup.AddPackageVersion(version); + isActionable |= foldoutGroup.AddPackage(package); if (!isActionable) - m_NoActionFoldout.AddPackageVersion(version); + m_NoActionFoldout.AddPackage(package); } foreach (var foldoutElement in allFoldoutElements) foldoutElement.Refresh(); - UIUtils.SetElementDisplay(infoBoxContainer, m_UnlockFoldout.versions.Any()); + UIUtils.SetElementDisplay(infoBoxContainer, m_UnlockFoldout.packages.Any()); return true; } @@ -191,8 +190,9 @@ private void Refresh() private void OnDeselectLockedSelectionsClicked() { - m_PageManager.activePage.RemoveSelection(m_UnlockFoldout.versions.Select(s => new PackageAndVersionIdPair(s.package.uniqueId, s.uniqueId))); - PackageManagerWindowAnalytics.SendEvent("deselectLocked", packageIds: m_UnlockFoldout.versions.Select(v => v.package.uniqueId)); + var packageUniqueIds = m_UnlockFoldout.packages.Select(p => p.uniqueId).ToArray(); + m_PageManager.activePage.RemoveSelection(packageUniqueIds); + PackageManagerWindowAnalytics.SendEvent("deselectLocked", packageIds: packageUniqueIds); } private VisualElementCache cache { get; } diff --git a/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectFoldout.cs b/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectFoldout.cs index a48dcc5159..108d18b91b 100644 --- a/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectFoldout.cs +++ b/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectFoldout.cs @@ -12,8 +12,8 @@ internal class MultiSelectFoldout : VisualElement, IMultiSelectFoldoutElement { public string headerTextTemplate { get; set; } - private List m_Versions = new(); - public List versions => m_Versions; + private List m_Packages = new(); + public List packages => m_Packages; public PackageAction action { get; } @@ -41,21 +41,21 @@ public MultiSelectFoldout(PackageAction action = null) public virtual void Refresh() { - var isVisible = m_Versions.Any(); + var isVisible = m_Packages.Any(); UIUtils.SetElementDisplay(this, isVisible); if (!isVisible) return; RefreshHeader(); RefreshContent(); - m_Button?.Refresh(m_Versions); + m_Button?.Refresh(m_Packages); } private void RefreshHeader() { if (string.IsNullOrEmpty(headerTextTemplate)) return; - var numItemsText = string.Format(m_Versions.Count > 1 ? L10n.Tr("{0} items") : L10n.Tr("{0} item"), m_Versions.Count); + var numItemsText = string.Format(m_Packages.Count > 1 ? L10n.Tr("{0} items") : L10n.Tr("{0} item"), m_Packages.Count); m_Toggle.text = string.Format(headerTextTemplate, numItemsText); } @@ -65,23 +65,23 @@ private void RefreshContent() return; m_Container.Clear(); - foreach (var version in m_Versions) + foreach (var version in m_Packages) m_Container.Add(CreateMultiSelectItem(version)); } - protected virtual MultiSelectItem CreateMultiSelectItem(IPackageVersion version) => new MultiSelectItem(version); + protected virtual MultiSelectItem CreateMultiSelectItem(IPackage package) => new (package); // Most foldouts are controlled by the group it belongs to, hence AddPackageVersion always return true. // For special standalone foldouts, the function should be overridden to provide their own logic. - public virtual bool AddPackageVersion(IPackageVersion version) + public virtual bool AddPackage(IPackage package) { - m_Versions.Add(version); + m_Packages.Add(package); return true; } - public void ClearVersions() + public void ClearPackages() { - m_Versions.Clear(); + m_Packages.Clear(); } private void SetExpanded(bool expanded) diff --git a/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectFoldoutGroup.cs b/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectFoldoutGroup.cs index 2bb954884e..f1c0a70f9b 100644 --- a/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectFoldoutGroup.cs +++ b/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectFoldoutGroup.cs @@ -23,13 +23,13 @@ public MultiSelectFoldoutGroup(MultiSelectFoldout mainFoldout, MultiSelectFoldou this.inProgressFoldout = inProgressFoldout; } - public virtual bool AddPackageVersion(IPackageVersion version) + public virtual bool AddPackage(IPackage package) { - var state = mainAction.GetActionState(version, out _, out _); + var state = mainAction.GetActionState(package.versions.primary, out _, out _); if (state.HasFlag(PackageActionState.InProgress)) - inProgressFoldout.AddPackageVersion(version); + inProgressFoldout.AddPackage(package); else if (state == PackageActionState.Visible || state.HasFlag(PackageActionState.DisabledTemporarily)) - mainFoldout.AddPackageVersion(version); + mainFoldout.AddPackage(package); else return false; return true; @@ -41,10 +41,10 @@ public virtual void Refresh() inProgressFoldout.Refresh(); } - public void ClearVersions() + public void ClearPackages() { - mainFoldout.ClearVersions(); - inProgressFoldout.ClearVersions(); + mainFoldout.ClearPackages(); + inProgressFoldout.ClearPackages(); } } } diff --git a/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectItem.cs b/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectItem.cs index 3d1366443b..0a0fe0d608 100644 --- a/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectItem.cs +++ b/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectItem.cs @@ -8,12 +8,12 @@ namespace UnityEditor.PackageManager.UI.Internal { internal class MultiSelectItem : VisualElement { - private IPackageVersion m_Version; + private IPackage m_Package; private string m_RightInfoText; - public MultiSelectItem(IPackageVersion version, string rightInfoText = "") + public MultiSelectItem(IPackage package, string rightInfoText = "") { - m_Version = version; + m_Package = package; m_RightInfoText = rightInfoText; m_MainContainer = new VisualElement { name = "mainContainer" }; @@ -28,7 +28,7 @@ public MultiSelectItem(IPackageVersion version, string rightInfoText = "") m_NameLabel = new Label { name = "nameLabel" }; m_LeftContainer.Add(m_NameLabel); - if (m_Version?.HasTag(PackageTag.Feature | PackageTag.LegacyFormat | PackageTag.BuiltIn) == false) + if (m_Package?.versions.primary.HasTag(PackageTag.Feature | PackageTag.LegacyFormat | PackageTag.BuiltIn) == false) { m_VersionLabel = new Label { name = "versionLabel" }; m_LeftContainer.Add(m_VersionLabel); @@ -47,17 +47,18 @@ public MultiSelectItem(IPackageVersion version, string rightInfoText = "") public void Refresh() { - m_TypeIcon.EnableClassToggle("featureIcon", "packageIcon", m_Version?.HasTag(PackageTag.Feature) == true); - m_NameLabel.text = m_Version.displayName; + var version = m_Package?.versions.primary; + m_TypeIcon.EnableClassToggle("featureIcon", "packageIcon", version?.HasTag(PackageTag.Feature) == true); + m_NameLabel.text = version?.displayName; if (m_VersionLabel != null) - m_VersionLabel.text = m_Version.versionString; + m_VersionLabel.text = version?.versionString; m_RightInfoLabel.text = m_RightInfoText; - if (m_Version.HasTag(PackageTag.LegacyFormat)) + if (version?.HasTag(PackageTag.LegacyFormat) == true) return; - if (m_Version.package.progress != PackageProgress.None) + if (m_Package != null && m_Package.progress != PackageProgress.None) StartSpinner(); else StopSpinner(); diff --git a/Modules/PackageManagerUI/Editor/UI/MultiSelect/RemoveFoldoutGroup.cs b/Modules/PackageManagerUI/Editor/UI/MultiSelect/RemoveFoldoutGroup.cs index 6ff5068dde..be5326bda7 100644 --- a/Modules/PackageManagerUI/Editor/UI/MultiSelect/RemoveFoldoutGroup.cs +++ b/Modules/PackageManagerUI/Editor/UI/MultiSelect/RemoveFoldoutGroup.cs @@ -19,12 +19,12 @@ public RemoveFoldoutGroup(IApplicationProxy applicationProxy, public override void Refresh() { - if (mainFoldout.versions.FirstOrDefault()?.HasTag(PackageTag.BuiltIn) == true) + if (mainFoldout.packages.FirstOrDefault()?.versions.primary.HasTag(PackageTag.BuiltIn) == true) mainFoldout.headerTextTemplate = L10n.Tr("Disable {0}"); else mainFoldout.headerTextTemplate = L10n.Tr("Remove {0}"); - if (inProgressFoldout.versions.FirstOrDefault()?.HasTag(PackageTag.BuiltIn) == true) + if (inProgressFoldout.packages.FirstOrDefault()?.versions.primary.HasTag(PackageTag.BuiltIn) == true) inProgressFoldout.headerTextTemplate = L10n.Tr("Disabling {0}"); else inProgressFoldout.headerTextTemplate = L10n.Tr("Removing {0}"); @@ -32,9 +32,9 @@ public override void Refresh() base.Refresh(); } - public override bool AddPackageVersion(IPackageVersion version) + public override bool AddPackage(IPackage package) { - return version.HasTag(PackageTag.UpmFormat) && base.AddPackageVersion(version); + return package.versions.primary.HasTag(PackageTag.UpmFormat) && base.AddPackage(package); } } } diff --git a/Modules/PackageManagerUI/Editor/UI/MultiSelect/RemoveImportedFoldoutGroup.cs b/Modules/PackageManagerUI/Editor/UI/MultiSelect/RemoveImportedFoldoutGroup.cs index bb2d980f9e..11db207871 100644 --- a/Modules/PackageManagerUI/Editor/UI/MultiSelect/RemoveImportedFoldoutGroup.cs +++ b/Modules/PackageManagerUI/Editor/UI/MultiSelect/RemoveImportedFoldoutGroup.cs @@ -20,9 +20,9 @@ public override void Refresh() base.Refresh(); } - public override bool AddPackageVersion(IPackageVersion version) + public override bool AddPackage(IPackage package) { - return version.importedAssets?.Any() == true && base.AddPackageVersion(version); + return package.versions.primary.importedAssets?.Any() == true && base.AddPackage(package); } } } diff --git a/Modules/PackageManagerUI/Editor/UI/MultiSelect/UnlockFoldout.cs b/Modules/PackageManagerUI/Editor/UI/MultiSelect/UnlockFoldout.cs index 2a12e9c1c7..c8664ee433 100644 --- a/Modules/PackageManagerUI/Editor/UI/MultiSelect/UnlockFoldout.cs +++ b/Modules/PackageManagerUI/Editor/UI/MultiSelect/UnlockFoldout.cs @@ -11,11 +11,11 @@ public UnlockFoldout(IPageManager pageManager) : base(new UnlockAction(pageManag headerTextTemplate = L10n.Tr("Unlock {0}"); } - public override bool AddPackageVersion(IPackageVersion version) + public override bool AddPackage(IPackage package) { - if (!action.GetActionState(version, out _, out _).HasFlag(PackageActionState.Visible)) + if (!action.GetActionState(package?.versions.primary, out _, out _).HasFlag(PackageActionState.Visible)) return false; - return base.AddPackageVersion(version); + return base.AddPackage(package); } } } diff --git a/Modules/PackageManagerUI/Editor/UI/MultiSelect/UpdateFoldout.cs b/Modules/PackageManagerUI/Editor/UI/MultiSelect/UpdateFoldout.cs index 6cde6c153d..f44b9041aa 100644 --- a/Modules/PackageManagerUI/Editor/UI/MultiSelect/UpdateFoldout.cs +++ b/Modules/PackageManagerUI/Editor/UI/MultiSelect/UpdateFoldout.cs @@ -16,10 +16,10 @@ public UpdateFoldout(IApplicationProxy applicationProxy, { } - protected override MultiSelectItem CreateMultiSelectItem(IPackageVersion version) + protected override MultiSelectItem CreateMultiSelectItem(IPackage package) { - var rightInfoText = string.Format(k_UpdateInfoTextFormat, version?.package?.versions.GetUpdateTarget(version).versionString); - return new MultiSelectItem(version, rightInfoText); + var rightInfoText = string.Format(k_UpdateInfoTextFormat, package?.versions.GetUpdateTarget(package.versions.primary).versionString); + return new MultiSelectItem(package, rightInfoText); } } } diff --git a/Modules/PackageManagerUI/Editor/UI/MultiSelect/UpdateFoldoutGroup.cs b/Modules/PackageManagerUI/Editor/UI/MultiSelect/UpdateFoldoutGroup.cs index f627abdc47..f079cdfcc1 100644 --- a/Modules/PackageManagerUI/Editor/UI/MultiSelect/UpdateFoldoutGroup.cs +++ b/Modules/PackageManagerUI/Editor/UI/MultiSelect/UpdateFoldoutGroup.cs @@ -16,11 +16,11 @@ public UpdateFoldoutGroup(IApplicationProxy applicationProxy, inProgressFoldout.headerTextTemplate = L10n.Tr("Updating {0}..."); } - public override bool AddPackageVersion(IPackageVersion version) + public override bool AddPackage(IPackage package) { - if (!version.HasTag(PackageTag.UpmFormat)) + if (!package.versions.primary.HasTag(PackageTag.UpmFormat)) return false; - return base.AddPackageVersion(version); + return base.AddPackage(package); } } } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageDetails.cs b/Modules/PackageManagerUI/Editor/UI/PackageDetails.cs index 6772771e79..d754339bad 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageDetails.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageDetails.cs @@ -142,21 +142,21 @@ public void Refresh(PageSelection selections = null) if (selections.Count == 1) { var selection = selections.FirstOrDefault(); - m_PackageDatabase.GetPackageAndVersion(selection.packageUniqueId, selection.versionUniqueId, out var package, out var version); - Refresh(package, version); + var package = m_PackageDatabase.GetPackage(selection); + RefreshUI(package); } else { // We call Refresh(null, null) to make sure that all single package details elements are hidden properly // We want to hide those elements when 1) there's nothing selected or 2) the multi select details view is visible. - Refresh(null, null); + RefreshUI(null); UIUtils.SetElementDisplay(multiSelectDetails, multiSelectDetails.Refresh(selections)); } } - private void Refresh(IPackage package, IPackageVersion version) + private void RefreshUI(IPackage package) { - version ??= package?.versions.primary; + var version = package?.versions.primary; var shouldDisplayProgress = inProgressView.ShouldDisplayProgress(package); inProgressView.Refresh(shouldDisplayProgress ? package : null); @@ -165,14 +165,14 @@ private void Refresh(IPackage package, IPackageVersion version) if (!detailVisible) { - RefreshExtensions(null, null); + RefreshExtensions(null); } else { - header.Refresh(package, version); - body.Refresh(package, version); - toolbar.Refresh(package, version); - RefreshExtensions(package, version); + header.Refresh(package); + body.Refresh(package); + toolbar.Refresh(package); + RefreshExtensions(package); } // Set visibility @@ -185,7 +185,7 @@ private void Refresh(IPackage package, IPackageVersion version) RefreshDetailError(package, version); } - void RefreshExtensions(IPackage package, IPackageVersion version) + void RefreshExtensions(IPackage package) { UIUtils.SetElementDisplay(customContainer, customContainer.childCount > 0); // ExtensionV1 UIUtils.SetElementDisplay(extensionContainer, extensionContainer.childCount > 0); // ExtensionV2 @@ -194,6 +194,7 @@ void RefreshExtensions(IPackage package, IPackageVersion version) // This way no single select UI will be displayed for multi-select. We might handle it differently in the future in a new story if (PackageManagerExtensions.extensionsGUICreated) { + var version = package?.versions.primary; var packageInfo = version != null ? m_UpmCache.GetBestMatchPackageInfo(version.name, version.isInstalled, version.versionString) : null; PackageManagerExtensions.ExtensionCallback(() => { @@ -202,7 +203,7 @@ void RefreshExtensions(IPackage package, IPackageVersion version) }); } - m_ExtensionManager.SendPackageSelectionChangedEvent(package, version); + m_ExtensionManager.SendPackageSelectionChangedEvent(package); } private void OnPackagesChanged(PackagesChangeArgs args) diff --git a/Modules/PackageManagerUI/Editor/UI/PackageDetailsBody.cs b/Modules/PackageManagerUI/Editor/UI/PackageDetailsBody.cs index cc88a4a2f8..9a8572e13a 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageDetailsBody.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageDetailsBody.cs @@ -98,9 +98,9 @@ public void OnDisable() m_PageManager.onVisualStateChange -= RefreshVersionsHistory; } - public void Refresh(IPackage package, IPackageVersion version) + public void Refresh(IPackage package) { - m_Version = version; + m_Version = package.versions.primary; RefreshTabs(); } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageDetailsHeader.cs b/Modules/PackageManagerUI/Editor/UI/PackageDetailsHeader.cs index c72a5de987..853fefafd1 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageDetailsHeader.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageDetailsHeader.cs @@ -94,15 +94,15 @@ private void CreateTags() versionContainer.Add(new PackageScopedRegistryTagLabel()); } - public void Refresh(IPackage package, IPackageVersion version) + public void Refresh(IPackage package) { m_Package = package; - m_Version = version; + m_Version = package.versions.primary; detailTitle.SetValueWithoutNotify(m_Version.displayName); detailsLinks.Refresh(m_Version); - UIUtils.SetElementDisplay(disabledWarningBox, version.HasTag(PackageTag.Disabled)); + UIUtils.SetElementDisplay(disabledWarningBox, m_Version.HasTag(PackageTag.Disabled)); RefreshName(); RefreshDependency(); diff --git a/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionsTab.cs b/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionsTab.cs index 83e628646d..0997cef5dd 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionsTab.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionsTab.cs @@ -15,6 +15,7 @@ internal class PackageDetailsVersionsTab : PackageDetailsTabElement private readonly VisualElement m_VersionHistoryList; private readonly VisualElement m_VersionsToolbar; private readonly Button m_VersionsShowOthersButton; + private readonly Label m_LoadingLabel; private IPackageVersion m_Version; @@ -61,6 +62,9 @@ public PackageDetailsVersionsTab(IUnityConnectProxy unityConnect, m_VersionsShowOthersButton = new Button { name = "versionsShowAllButton", text = L10n.Tr("See other versions") }; m_VersionsToolbar.Add(m_VersionsShowOthersButton); + + m_LoadingLabel = new Label { name = "versionsLoadingLabel", text = L10n.Tr("Loading...") }; + m_Container.Add(m_LoadingLabel); m_VersionsShowOthersButton.clickable.clicked += ShowOthersVersion; } @@ -70,10 +74,16 @@ private void ShowOthersVersion() if (m_Version?.package == null) return; - m_UpmCache.SetLoadAllVersions(m_Version.package.uniqueId, true); - PackageManagerWindowAnalytics.SendEvent("seeAllVersions", m_Version.package.uniqueId); + UIUtils.SetElementDisplay(m_LoadingLabel, true); + UIUtils.SetElementDisplay(m_VersionsToolbar, false); - Refresh(m_Version); + EditorApplication.delayCall += () => + { + m_UpmCache.SetLoadAllVersions(m_Version.package.uniqueId, true); + PackageManagerWindowAnalytics.SendEvent("seeAllVersions", m_Version.package.uniqueId); + + Refresh(m_Version); + }; } public override bool IsValid(IPackageVersion version) @@ -103,6 +113,7 @@ protected override void RefreshContent(IPackageVersion version) var seeVersionsToolbar = versions.numUnloadedVersions > 0 && (m_SettingsProxy.seeAllPackageVersions || m_Version.availableRegistry != RegistryType.UnityRegistry || m_Version.package.versions.installed?.HasTag(PackageTag.Experimental) == true); UIUtils.SetElementDisplay(m_VersionsToolbar, seeVersionsToolbar); + UIUtils.SetElementDisplay(m_LoadingLabel, false); var latestVersion = m_Version.package?.versions.latest; var primaryVersion = m_Version.package?.versions.primary; diff --git a/Modules/PackageManagerUI/Editor/UI/PackageItem.cs b/Modules/PackageManagerUI/Editor/UI/PackageItem.cs index 1cc588527b..32d3ce18f3 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageItem.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageItem.cs @@ -28,20 +28,6 @@ internal class PackageItem : VisualElement, ISelectableItem internal PackageGroup packageGroup { get; set; } - private IPackageVersion selectedVersion - { - get - { - if (package != null && m_PageManager.activePage.GetSelection().TryGetValue(package.uniqueId, out var selection)) - { - if (string.IsNullOrEmpty(selection.versionUniqueId)) - return package.versions.primary; - return package.versions.FirstOrDefault(v => v.uniqueId == selection.versionUniqueId); - } - return null; - } - } - private readonly IPageManager m_PageManager; private readonly IPackageDatabase m_PackageDatabase; @@ -256,7 +242,7 @@ private void RefreshFeatureState() public void RefreshSelection() { - var enable = selectedVersion != null; + var enable = package != null && m_PageManager.activePage.GetSelection().Contains(package.uniqueId); EnableInClassList(k_SelectedClassName, enable); m_MainItem.EnableInClassList(k_SelectedClassName, enable); } @@ -271,7 +257,7 @@ private void RefreshEntitlement() public void SelectMainItem() { - m_PageManager.activePage.SetNewSelection(package, null, true); + m_PageManager.activePage.SetNewSelection(package, true); } public void ToggleSelectMainItem() diff --git a/Modules/PackageManagerUI/Editor/UI/PackageList.cs b/Modules/PackageManagerUI/Editor/UI/PackageList.cs index c5a6418e78..c3715525fa 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageList.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageList.cs @@ -151,11 +151,11 @@ private void OnSelectionChanged(PageSelectionChangeArgs args) return; var currentView = this.currentView; - foreach (var item in args.selection.previousSelections.Where(s => !args.selection.Contains(s.packageUniqueId)).Concat(args.selection)) - currentView.GetPackageItem(item.packageUniqueId)?.RefreshSelection(); + foreach (var item in args.selection.previousSelections.Where(s => !args.selection.Contains(s)).Concat(args.selection)) + currentView.GetPackageItem(item)?.RefreshSelection(); if (args.selection.previousSelections.Count() == 1) - m_UpmCache.SetLoadAllVersions(args.selection.previousSelections.FirstOrDefault().packageUniqueId, false); + m_UpmCache.SetLoadAllVersions(args.selection.previousSelections.FirstOrDefault(), false); } private void OnCheckUpdateProgress() @@ -224,7 +224,7 @@ public void HideListShowEmptyArea(string message, string buttonText = null, Acti m_ButtonAction = buttonAction; UIUtils.SetElementDisplay(emptyAreaButton, buttonAction != null); - m_PageManager.activePage.SetNewSelection(Enumerable.Empty()); + m_PageManager.activePage.SetNewSelection(Enumerable.Empty()); } private void HideEmptyAreaShowList(bool skipListRebuild) diff --git a/Modules/PackageManagerUI/Editor/UI/PackageListScrollView.cs b/Modules/PackageManagerUI/Editor/UI/PackageListScrollView.cs index 2f3a06e5ea..d53e40a57d 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageListScrollView.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageListScrollView.cs @@ -79,9 +79,8 @@ public PackageItem GetPackageItem(string packageUniqueId) private ISelectableItem GetFirstSelectedItem() { - m_PackageDatabase.GetPackageAndVersion(m_PageManager.activePage.GetSelection().firstSelection, out var package, out var version); - var selectedVersion = version ?? package?.versions.primary; - return GetPackageItem(selectedVersion?.package.uniqueId); + var package = m_PackageDatabase.GetPackage(m_PageManager.activePage.GetSelection().firstSelection); + return GetPackageItem(package?.uniqueId); } public void ScrollToSelection() @@ -291,11 +290,11 @@ private PackageItem GetPackageItemFromMouseEvent(MouseDownEvent evt) private void SelectAllBetween(string firstPackageUniqueId, string secondPackageUniqueId) { - var newSelections = new List(); + var newSelections = new List(); var inBetweenTwoPackages = false; if (firstPackageUniqueId == secondPackageUniqueId) { - newSelections.Add(new PackageAndVersionIdPair(firstPackageUniqueId)); + newSelections.Add(firstPackageUniqueId); } else { @@ -310,7 +309,7 @@ private void SelectAllBetween(string firstPackageUniqueId, string secondPackageU var matchFirstPackage = packageUniqueId == firstPackageUniqueId; var matchSecondPackage = packageUniqueId == secondPackageUniqueId; if (matchFirstPackage || matchSecondPackage || inBetweenTwoPackages) - newSelections.Add(new PackageAndVersionIdPair(packageUniqueId)); + newSelections.Add(packageUniqueId); if (matchFirstPackage || matchSecondPackage) { @@ -332,7 +331,7 @@ private void SelectAllBetween(string firstPackageUniqueId, string secondPackageU private void SelectAllVisible() { var validItems = packageItems.Where(p => !string.IsNullOrEmpty(p.package?.uniqueId) && UIUtils.IsElementVisible(p)); - m_PageManager.activePage.SetNewSelection(validItems.Select(item => new PackageAndVersionIdPair(item.package.uniqueId)), true); + m_PageManager.activePage.SetNewSelection(validItems.Select(item => item.package.uniqueId), true); } private void OnMouseDown(MouseDownEvent evt) @@ -346,7 +345,7 @@ private void OnMouseDown(MouseDownEvent evt) if (evt.shiftKey) { - var firstItem = m_PageManager.activePage.GetSelection().firstSelection?.packageUniqueId; + var firstItem = m_PageManager.activePage.GetSelection().firstSelection; SelectAllBetween(firstItem, packageItem.package.uniqueId); return; } @@ -365,8 +364,8 @@ private bool HandleShiftSelection(NavigationMoveEvent evt) if (evt.direction == NavigationMoveEvent.Direction.Up || evt.direction == NavigationMoveEvent.Direction.Down) { var selection = m_PageManager.activePage.GetSelection(); - var firstItem = selection.firstSelection?.packageUniqueId; - var lastItem = selection.lastSelection?.packageUniqueId; + var firstItem = selection.firstSelection; + var lastItem = selection.lastSelection; var nextItem = FindNextVisiblePackageItem(GetPackageItem(lastItem), evt.direction == NavigationMoveEvent.Direction.Up); SelectAllBetween(firstItem, nextItem?.package.uniqueId ?? lastItem); @@ -423,7 +422,7 @@ internal bool SelectNext(bool reverseOrder) var nextElement = FindNextVisibleSelectableItem(reverseOrder); if (nextElement != null) { - m_PageManager.activePage.SetNewSelection(nextElement.package, nextElement.targetVersion); + m_PageManager.activePage.SetNewSelection(nextElement.package); ScrollIfNeeded(nextElement.element); return true; } @@ -434,7 +433,7 @@ private ISelectableItem FindNextVisibleSelectableItem(bool reverseOrder) { // We use the `lastSelection` here as that is the one the user interacted last and it feels more natural that way when navigating with keyboard var lastSelection = m_PageManager.activePage.GetSelection().lastSelection; - var packageItem = GetPackageItem(lastSelection?.packageUniqueId); + var packageItem = GetPackageItem(lastSelection); if (packageItem == null) return null; diff --git a/Modules/PackageManagerUI/Editor/UI/PackageListView.cs b/Modules/PackageManagerUI/Editor/UI/PackageListView.cs index eee40a7fcd..8d44180b46 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageListView.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageListView.cs @@ -71,10 +71,8 @@ private void SyncListViewSelectionToPageManager(IEnumerable items) { var visualState = item as VisualState; var package = m_PackageDatabase.GetPackage(visualState?.packageUniqueId); - if (package != null) - return new PackageAndVersionIdPair(package.uniqueId); - return null; - }).Where(s => s != null).ToArray(); + return package?.uniqueId; + }).Where(s => !string.IsNullOrEmpty(s)).ToArray(); // SelectionChange happens before BindItems, hence we use m_PageManager.SetSelected instead of packageItem.SelectMainItem // as PackageItems are null sometimes when SelectionChange is triggered @@ -185,7 +183,7 @@ public void ScrollToSelection() } // For now we want to just scroll to any of the selections, this behaviour might change in the future depending on how users react - var firstSelectedPackageUniqueId = m_PageManager.activePage.GetSelection().firstSelection?.packageUniqueId; + var firstSelectedPackageUniqueId = m_PageManager.activePage.GetSelection().firstSelection; if (string.IsNullOrEmpty(firstSelectedPackageUniqueId)) return; diff --git a/Modules/PackageManagerUI/Editor/UI/PackageManagerWindowRoot.cs b/Modules/PackageManagerUI/Editor/UI/PackageManagerWindowRoot.cs index aa47f1993e..48b742da72 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageManagerWindowRoot.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageManagerWindowRoot.cs @@ -303,7 +303,7 @@ private bool ApplyPackageAndPageSelection(PackageAndPageSelectionArgs args) if (!string.IsNullOrEmpty(args.packageToSelect)) { m_PackageDatabase.GetPackageAndVersionByIdOrName(args.packageToSelect, out var package, out var version, true); - m_PageManager.activePage.SetNewSelection(package, version, true); + m_PageManager.activePage.SetNewSelection(package, true); packageList.OnFocus(); } return true; @@ -360,7 +360,7 @@ public void SelectPackageAndPage(string packageToSelect = null, string pageId = { m_PackageDatabase.GetPackageAndVersionByIdOrName(packageToSelect, out var package, out var version, true); if (package != null) - args.page = m_PageManager.FindPage(package, version) ?? m_PageManager.activePage; + args.page = m_PageManager.FindPage(package) ?? m_PageManager.activePage; else { var packageToSelectSplit = packageToSelect.Split('@'); @@ -447,14 +447,14 @@ public PackageSelectionArgs activeSelection // When there are multiple versions selected, we want to make the legacy single select arguments to be null // that way extension UI implemented for single package selection will not show for multi-select cases. - var versions = selections.Select(selection => + var packages = selections.Select(selection => { - m_PackageDatabase.GetPackageAndVersion(selection, out var package, out var version); - return version ?? package?.versions.primary; + var package = m_PackageDatabase.GetPackage(selection); + return package; }).ToArray(); - var version = versions.Length > 1 ? null : versions.FirstOrDefault(); - return new PackageSelectionArgs { package = version?.package, packageVersion = version, versions = versions, window = this }; + var package = packages.Length > 1 ? null : packages.FirstOrDefault(); + return new PackageSelectionArgs { package = package, packageVersion = package?.versions.primary, packages = packages, window = this }; } } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs b/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs index 654b3a9741..66a529f8a0 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs @@ -88,9 +88,8 @@ void OnDisable() private void GetPackageAndVersion(PackageSelectionObject packageSelectionObject) { - m_PackageDatabase.GetPackageAndVersion(packageSelectionObject.packageUniqueId, packageSelectionObject.versionUniqueId, out m_Package, out m_Version); - if (m_Version == null && string.IsNullOrEmpty(packageSelectionObject.versionUniqueId)) - m_Version = m_Package?.versions.primary; + m_Package = m_PackageDatabase.GetPackage(packageSelectionObject.packageUniqueId); + m_Version = m_Package?.versions.primary; } private void OnPackagesChanged(PackagesChangeArgs args) @@ -200,7 +199,10 @@ internal override void OnForceReloadInspector() var packageDatabase = ServicesContainer.instance.Resolve(); if (packageSelectionObject != null && (m_Package == null || m_Version == null)) - packageDatabase.GetPackageAndVersion(packageSelectionObject.packageUniqueId, packageSelectionObject.versionUniqueId, out m_Package, out m_Version); + { + m_Package = packageDatabase.GetPackage(packageSelectionObject.packageUniqueId); + m_Version = m_Package?.versions.primary; + } } internal override bool HasLargeHeader() diff --git a/Modules/PackageManagerUI/Editor/UI/PackageSelectionObject.cs b/Modules/PackageManagerUI/Editor/UI/PackageSelectionObject.cs index 086df35987..5459029417 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageSelectionObject.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageSelectionObject.cs @@ -13,8 +13,5 @@ internal class PackageSelectionObject : ScriptableObject { public string displayName; public string packageUniqueId; - public string versionUniqueId; - - public string uniqueId => string.IsNullOrEmpty(versionUniqueId) ? packageUniqueId : versionUniqueId; } } diff --git a/Modules/PackageManagerUI/Editor/UI/ToolBar/LegacyFormatDropdownButton.cs b/Modules/PackageManagerUI/Editor/UI/ToolBar/LegacyFormatDropdownButton.cs index 4a49a0eb1d..b263183631 100644 --- a/Modules/PackageManagerUI/Editor/UI/ToolBar/LegacyFormatDropdownButton.cs +++ b/Modules/PackageManagerUI/Editor/UI/ToolBar/LegacyFormatDropdownButton.cs @@ -140,7 +140,7 @@ private int FindMainActionIndex(IList<(PackageAction action, string text, string } [ExcludeFromCodeCoverage] - public override void Refresh(IEnumerable versions) + public override void Refresh(IEnumerable packages) { // Do nothing since this button is not available for multi-select } diff --git a/Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBar.cs b/Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBar.cs index 342f53d957..0fd287c7d6 100644 --- a/Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBar.cs +++ b/Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBar.cs @@ -135,10 +135,10 @@ public void OnDisable() m_AssetStoreDownloadManager.onDownloadFinalized -= OnDownloadProgress; } - public void Refresh(IPackage package, IPackageVersion version) + public void Refresh(IPackage package) { m_Package = package; - m_Version = version; + m_Version = package.versions.primary; Refresh(); } @@ -156,7 +156,7 @@ private void Refresh() // Returns true if the progress bar is visible and there's no need to further check other containers private bool RefreshProgressContainer(IOperation operation = null) { - operation ??= m_AssetStoreDownloadManager.GetDownloadOperation(m_Version?.package?.product?.id); + operation ??= m_AssetStoreDownloadManager.GetDownloadOperation(m_Package?.product?.id); var progressVisible = operation != null && m_Version?.package?.uniqueId == operation.packageUniqueId && m_DownloadProgress.UpdateProgress(operation); UIUtils.SetElementDisplay(m_ProgressContainer, progressVisible); if (progressVisible) diff --git a/Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBarButton.cs b/Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBarButton.cs index b3483481f9..6b00494c2d 100644 --- a/Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBarButton.cs +++ b/Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBarButton.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using UnityEngine.UIElements; using System; +using System.Linq; namespace UnityEditor.PackageManager.UI.Internal { @@ -12,7 +13,7 @@ internal abstract class PackageToolBarButton : VisualElement { public abstract void Refresh(IPackageVersion version); - public abstract void Refresh(IEnumerable versions); + public abstract void Refresh(IEnumerable packages); public abstract event Action onActionTriggered; } @@ -45,9 +46,9 @@ private void SetPackageVersions(IEnumerable versions) m_Versions.AddRange(versions); } - public override void Refresh(IEnumerable versions) + public override void Refresh(IEnumerable packages) { - SetPackageVersions(versions); + SetPackageVersions(packages.Select(p => p.versions.primary)); if (m_Versions.Count == 0) return; @@ -89,7 +90,7 @@ protected void TriggerAction() m_Action.TriggerAction(m_Versions[0]); break; default: - m_Action.TriggerAction(m_Versions); + m_Action.TriggerAction(m_Versions.Select(v => v.package).ToArray()); break; } } diff --git a/Modules/Properties/Runtime/AssemblyInfo.cs b/Modules/Properties/Runtime/AssemblyInfo.cs index a1fd77ff8e..329b441e20 100644 --- a/Modules/Properties/Runtime/AssemblyInfo.cs +++ b/Modules/Properties/Runtime/AssemblyInfo.cs @@ -7,6 +7,7 @@ [assembly: InternalsVisibleTo("UnityEditor.PropertiesModule")] [assembly: InternalsVisibleTo("Unity.Properties.CodeGen.IntegrationTests")] +[assembly: InternalsVisibleTo("PropertyBags.GenerationTests")] [assembly: InternalsVisibleTo("Unity.Properties.Reflection.Tests")] [assembly: InternalsVisibleTo("Unity.Properties.Tests")] diff --git a/Modules/Properties/Runtime/Properties/ReflectedMemberProperty.cs b/Modules/Properties/Runtime/Properties/ReflectedMemberProperty.cs index f854bc3122..e02fee2d4c 100644 --- a/Modules/Properties/Runtime/Properties/ReflectedMemberProperty.cs +++ b/Modules/Properties/Runtime/Properties/ReflectedMemberProperty.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using Unity.Properties.Internal; using System.Reflection.Emit; @@ -62,10 +63,11 @@ interface IMemberInfo public FieldMember(FieldInfo fieldInfo) { m_FieldInfo = fieldInfo; + Name = ReflectionUtilities.SanitizeMemberName(m_FieldInfo); } /// - public string Name => m_FieldInfo.Name; + public string Name { get; } /// public bool IsReadOnly => m_FieldInfo.IsInitOnly; @@ -88,7 +90,7 @@ public FieldMember(FieldInfo fieldInfo) internal readonly PropertyInfo m_PropertyInfo; /// - public string Name => m_PropertyInfo.Name; + public string Name { get; } /// public bool IsReadOnly => !m_PropertyInfo.CanWrite; @@ -100,7 +102,11 @@ public FieldMember(FieldInfo fieldInfo) /// Initializes a new instance. /// /// The backing object. - public PropertyMember(PropertyInfo propertyInfo) => m_PropertyInfo = propertyInfo; + public PropertyMember(PropertyInfo propertyInfo) + { + m_PropertyInfo = propertyInfo; + Name = ReflectionUtilities.SanitizeMemberName(m_PropertyInfo); + } /// public object GetValue(object obj) => m_PropertyInfo.GetValue(obj); diff --git a/Modules/Properties/Runtime/PropertyBags/Internal/PropertyBagStore.cs b/Modules/Properties/Runtime/PropertyBags/Internal/PropertyBagStore.cs index 26868f6d2a..6637516608 100644 --- a/Modules/Properties/Runtime/PropertyBags/Internal/PropertyBagStore.cs +++ b/Modules/Properties/Runtime/PropertyBags/Internal/PropertyBagStore.cs @@ -70,9 +70,17 @@ internal static void AddPropertyBag(IPropertyBag propert if (null != TypedStore.PropertyBag) { + var currentPropertyBag = TypedStore.PropertyBag; + // When registering a property bag, prefer to use the one coming from its own assembly. + if (currentPropertyBag.GetType().Assembly == typeof(TContainer).Assembly) + return; + if (propertyBag.GetType().GetCustomAttributes().Any()) { - return; + // If there is already a property bag registered, only register the provided one + // if it is contained in the same assembly as its target type. + if (propertyBag.GetType().Assembly != typeof(TContainer).Assembly) + return; } } diff --git a/Modules/Properties/Runtime/Reflection/Internal/ReflectionUtilities.cs b/Modules/Properties/Runtime/Reflection/Internal/ReflectionUtilities.cs new file mode 100644 index 0000000000..25fc94afb3 --- /dev/null +++ b/Modules/Properties/Runtime/Reflection/Internal/ReflectionUtilities.cs @@ -0,0 +1,20 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System.Reflection; + +namespace Unity.Properties.Internal +{ + internal static class ReflectionUtilities + { + public static string SanitizeMemberName(MemberInfo info) + { + return info.Name + .Replace(".", "_") + .Replace("<", "_") + .Replace(">", "") + .Replace("+", "_"); + } + } +} diff --git a/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabase.cs b/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabase.cs index 73bf4e3c0b..abe66490fd 100644 --- a/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabase.cs +++ b/Modules/QuickSearch/Editor/PropertyDatabase/PropertyDatabase.cs @@ -193,7 +193,7 @@ public PropertyDatabase(string filePath, bool autoFlush, double backgroundUpdate // the automatic update during tests. this.autoFlush = autoFlush && !Utils.IsRunningTests(); - m_Debounce = Delayer.Debounce(_ => TriggerBackgroundUpdate(), backgroundUpdateDebounceInSeconds); + m_Debounce = Delayer.Debounce(_ => TriggerBackgroundUpdate(), TimeSpan.FromSeconds(backgroundUpdateDebounceInSeconds)); m_Valid = true; } else diff --git a/Modules/QuickSearch/Editor/UITK/SearchBaseCollectionView.cs b/Modules/QuickSearch/Editor/UITK/SearchBaseCollectionView.cs index 17fb520002..6d6b799fb8 100644 --- a/Modules/QuickSearch/Editor/UITK/SearchBaseCollectionView.cs +++ b/Modules/QuickSearch/Editor/UITK/SearchBaseCollectionView.cs @@ -43,7 +43,7 @@ protected override void OnAttachToPanel(AttachToPanelEvent evt) m_Throttler = Delayer.Throttle(o => { UpdateView(); - }, SearchView.resultViewUpdateThrottleDelay, true); + }, TimeSpan.FromSeconds(SearchView.resultViewUpdateThrottleDelay), true); m_ListView.selectedIndicesChanged += HandleItemsSelected; m_ListView.itemsChosen += OnItemsChosen; diff --git a/Modules/QuickSearch/Editor/UITK/SearchGridView.cs b/Modules/QuickSearch/Editor/UITK/SearchGridView.cs index 1e376d5bb5..4ff281059b 100644 --- a/Modules/QuickSearch/Editor/UITK/SearchGridView.cs +++ b/Modules/QuickSearch/Editor/UITK/SearchGridView.cs @@ -118,7 +118,7 @@ protected override void OnAttachToPanel(AttachToPanelEvent evt) m_Throttler = Delayer.Throttle(o => { UpdateView(); - }, SearchView.resultViewUpdateThrottleDelay, true); + }, TimeSpan.FromSeconds(SearchView.resultViewUpdateThrottleDelay), true); m_GridView.itemsBuilt += UpdateSelection; m_GridView.itemsChosen += OnItemsChosen; diff --git a/Modules/TextCoreFontEngine/Managed/FontEngine.bindings.cs b/Modules/TextCoreFontEngine/Managed/FontEngine.bindings.cs index 18e1d17051..3eb65c10c8 100644 --- a/Modules/TextCoreFontEngine/Managed/FontEngine.bindings.cs +++ b/Modules/TextCoreFontEngine/Managed/FontEngine.bindings.cs @@ -1171,22 +1171,11 @@ extern static bool TryAddGlyphsToTexture_Internal_MultiThread([Out] GlyphMarshal int padding, GlyphPackingMode packingMode, [Out] GlyphRect[] freeGlyphRects, ref int freeGlyphRectCount, [Out] GlyphRect[] usedGlyphRects, ref int usedGlyphRectCount, GlyphRenderMode renderMode, Texture2D texture); - /// /// Internal function used to add multiple glyphs to atlas texture. /// [VisibleToOtherModules("UnityEngine.TextCoreTextEngineModule")] internal static bool TryAddGlyphsToTexture(List glyphIndexes, int padding, GlyphPackingMode packingMode, List freeGlyphRects, List usedGlyphRects, GlyphRenderMode renderMode, Texture2D texture, out Glyph[] glyphs) - { - return TryAddGlyphsToTexture(glyphIndexes, padding, packingMode, freeGlyphRects, usedGlyphRects, renderMode, texture, out glyphs); - } - - /// - /// Internal function used to add multiple glyphs to atlas texture. - /// Also returns the glyphsAddedCount, since glyphIndexes.Count might not be exact. - /// - [VisibleToOtherModules("UnityEngine.TextCoreTextEngineModule")] - internal static bool TryAddGlyphsToTexture(List glyphIndexes, int padding, GlyphPackingMode packingMode, List freeGlyphRects, List usedGlyphRects, GlyphRenderMode renderMode, Texture2D texture, out Glyph[] glyphs, out int glyphsAddedCount) { Profiler.BeginSample("FontEngine.TryAddGlyphsToTexture"); @@ -1195,7 +1184,6 @@ internal static bool TryAddGlyphsToTexture(List glyphIndexes, int padding, if (glyphIndexes == null || glyphIndexes.Count == 0) { Profiler.EndSample(); - glyphsAddedCount = 0; return false; } @@ -1270,7 +1258,6 @@ internal static bool TryAddGlyphsToTexture(List glyphIndexes, int padding, } glyphs = s_Glyphs; - glyphsAddedCount = glyphCount; Profiler.EndSample(); diff --git a/Modules/TextCoreTextEngine/Managed/TextAssets/FontAsset.cs b/Modules/TextCoreTextEngine/Managed/TextAssets/FontAsset.cs index b35ae6f42d..3e5be52c17 100644 --- a/Modules/TextCoreTextEngine/Managed/TextAssets/FontAsset.cs +++ b/Modules/TextCoreTextEngine/Managed/TextAssets/FontAsset.cs @@ -597,6 +597,73 @@ public static FontAsset CreateFontAsset(string familyName, string styleName, int return null; } + /// + /// Create a List of Font Assets with a list of fallbacks defined by FamilyNames, all regular styles + /// + /// The desired fonts to be included, ordered by preferred fallback + /// Optional point size. + /// A List of FontAsset containing the available fallbacks for the current platform. + internal static List CreateFontAssetOSFallbackList(string[] fallbacksFamilyNames, Shader shader, int pointSize = 90) + { + List fallbackList = new List(); + FontAsset currentFontAsset; + + foreach (var familyName in fallbacksFamilyNames) + { + currentFontAsset = CreateFontAssetFromFamilyName(familyName, shader, pointSize); + + if (currentFontAsset == null) + continue; + + fallbackList.Add(currentFontAsset); + } + + return fallbackList; + } + + internal static FontAsset CreateFontAssetWithOSFallbackList(string[] fallbacksFamilyNames, Shader shader, int pointSize = 90) + { + FontAsset mainFontAsset = null; + FontAsset currentFontAsset; + + foreach (var familyName in fallbacksFamilyNames) + { + currentFontAsset = CreateFontAssetFromFamilyName(familyName, shader, pointSize); + + if (currentFontAsset == null) + continue; + + if (mainFontAsset == null) + mainFontAsset = currentFontAsset; + + if (mainFontAsset.fallbackFontAssetTable == null) + mainFontAsset.fallbackFontAssetTable = new List(); + + mainFontAsset.fallbackFontAssetTable.Add(currentFontAsset); + } + + return mainFontAsset; + } + + private static FontAsset CreateFontAssetFromFamilyName(string familyName, Shader shader, int pointSize = 90) + { + FontAsset fontAsset = null; + + if (FontEngine.TryGetSystemFontReference(familyName, null, out FontReference fontRef)) + fontAsset = CreateFontAsset(fontRef.filePath, fontRef.faceIndex, pointSize, 9, GlyphRenderMode.SDFAA, 1024, 1024, AtlasPopulationMode.DynamicOS, true); + + if (fontAsset == null) + return null; + + fontAsset.hideFlags = HideFlags.DontSave; + fontAsset.atlasTextures[0].hideFlags = HideFlags.DontSave; + fontAsset.material.hideFlags = HideFlags.DontSave; + fontAsset.isMultiAtlasTexturesEnabled = true; + fontAsset.material.shader = shader; + + return fontAsset; + } + /// /// Creates a new font asset instance from the font file at the given file path. /// @@ -640,6 +707,11 @@ public static FontAsset CreateFontAsset(Font font) return CreateFontAsset(font, 90, 9, GlyphRenderMode.SDFAA, 1024, 1024); } + internal static FontAsset CreateFontAsset(Font font, int samplingPointSize, int atlasPadding, GlyphRenderMode renderMode, int atlasWidth, int atlasHeight, Shader shader, AtlasPopulationMode atlasPopulationMode = AtlasPopulationMode.Dynamic, bool enableMultiAtlasSupport = true) + { + return CreateFontAsset(font, 0, samplingPointSize, atlasPadding, renderMode, atlasWidth, atlasHeight, shader, atlasPopulationMode, enableMultiAtlasSupport); + } + /// /// Creates a new font asset instance from the provided font object. /// @@ -654,28 +726,30 @@ public static FontAsset CreateFontAsset(Font font) /// An instance of the newly created font asset. public static FontAsset CreateFontAsset(Font font, int samplingPointSize, int atlasPadding, GlyphRenderMode renderMode, int atlasWidth, int atlasHeight, AtlasPopulationMode atlasPopulationMode = AtlasPopulationMode.Dynamic, bool enableMultiAtlasSupport = true) { - return CreateFontAsset(font, 0, samplingPointSize, atlasPadding, renderMode, atlasWidth, atlasHeight, atlasPopulationMode, enableMultiAtlasSupport); + return CreateFontAsset(font, 0, samplingPointSize, atlasPadding, renderMode, atlasWidth, atlasHeight, null, atlasPopulationMode, enableMultiAtlasSupport); } - static FontAsset CreateFontAsset(Font font, int faceIndex, int samplingPointSize, int atlasPadding, GlyphRenderMode renderMode, int atlasWidth, int atlasHeight, AtlasPopulationMode atlasPopulationMode = AtlasPopulationMode.Dynamic, bool enableMultiAtlasSupport = true) + static FontAsset CreateFontAsset(Font font, int faceIndex, int samplingPointSize, int atlasPadding, GlyphRenderMode renderMode, int atlasWidth, int atlasHeight, Shader shader, AtlasPopulationMode atlasPopulationMode = AtlasPopulationMode.Dynamic, bool enableMultiAtlasSupport = true) { - // Load Font Face - if (FontEngine.LoadFontFace(font, samplingPointSize, faceIndex) != FontEngineError.Success) + if (font.name == "LegacyRuntime") { - if (font.name == "LegacyRuntime") + var fonts = Font.GetOSFallbacks(); + if (FontEngine.LoadFontFace(font, samplingPointSize, faceIndex) == FontEngineError.Success) { - RuntimePlatform platform = Application.platform; - - switch (platform) - { - case RuntimePlatform.LinuxPlayer: - return FontAsset.CreateFontAsset("Liberation Sans", "Regular"); - case RuntimePlatform.Switch: - return FontAsset.CreateFontAsset("nintendo_udsg-r_std_003", "R"); - default: - return FontAsset.CreateFontAsset("Arial", "Regular"); - } + var mainFontAssset = CreateFontAssetInstance(font, atlasPadding, renderMode, atlasWidth, atlasHeight, atlasPopulationMode, enableMultiAtlasSupport); + var fallbacks = CreateFontAssetOSFallbackList(fonts, shader, samplingPointSize); + mainFontAssset.fallbackFontAssetTable = fallbacks; + return mainFontAssset; } + + var fontAsset = CreateFontAssetWithOSFallbackList(fonts, shader, samplingPointSize); + if (fontAsset != null) + return fontAsset; + } + + // Load Font Face + if (FontEngine.LoadFontFace(font, samplingPointSize, faceIndex) != FontEngineError.Success) + { FontAsset systemFontAsset = CreateFontAsset(font.name, "Regular"); if (systemFontAsset != null) return systemFontAsset; diff --git a/Modules/TextCoreTextEngine/Managed/TextAssets/FontAsset/FontAssetAtlasPopulation.cs b/Modules/TextCoreTextEngine/Managed/TextAssets/FontAsset/FontAssetAtlasPopulation.cs index dcd711c177..3d037b9d4f 100644 --- a/Modules/TextCoreTextEngine/Managed/TextAssets/FontAsset/FontAssetAtlasPopulation.cs +++ b/Modules/TextCoreTextEngine/Managed/TextAssets/FontAsset/FontAssetAtlasPopulation.cs @@ -256,7 +256,7 @@ public bool TryAddCharacters(uint[] unicodes, out uint[] missingUnicodes, bool i } Glyph[] glyphs; - var allGlyphsAddedToTexture = FontEngine.TryAddGlyphsToTexture(m_GlyphsToAdd, m_AtlasPadding, GlyphPackingMode.BestShortSideFit, m_FreeGlyphRects, m_UsedGlyphRects, m_AtlasRenderMode, m_AtlasTextures[m_AtlasTextureIndex], out glyphs, out int glyphsAddedCount); + var allGlyphsAddedToTexture = FontEngine.TryAddGlyphsToTexture(m_GlyphsToAdd, m_AtlasPadding, GlyphPackingMode.BestShortSideFit, m_FreeGlyphRects, m_UsedGlyphRects, m_AtlasRenderMode, m_AtlasTextures[m_AtlasTextureIndex], out glyphs); // Add new glyphs to relevant font asset data structure { @@ -267,7 +267,7 @@ public bool TryAddCharacters(uint[] unicodes, out uint[] missingUnicodes, bool i EnsureAdditionalCapacity(m_GlyphIndexList, additionalCapacity); } - for (int i = 0; i < glyphsAddedCount && glyphs[i] != null; i++) + for (int i = 0; i < glyphs.Length && glyphs[i] != null; i++) { Glyph glyph = glyphs[i]; @@ -574,10 +574,10 @@ bool TryAddGlyphsToNewAtlasTexture() Glyph[] glyphs; // Try adding remaining glyphs in the newly created atlas texture - bool allGlyphsAddedToTexture = FontEngine.TryAddGlyphsToTexture(m_GlyphsToAdd, m_AtlasPadding, GlyphPackingMode.BestShortSideFit, m_FreeGlyphRects, m_UsedGlyphRects, m_AtlasRenderMode, m_AtlasTextures[m_AtlasTextureIndex], out glyphs, out int glyphsAddedCount); + bool allGlyphsAddedToTexture = FontEngine.TryAddGlyphsToTexture(m_GlyphsToAdd, m_AtlasPadding, GlyphPackingMode.BestShortSideFit, m_FreeGlyphRects, m_UsedGlyphRects, m_AtlasRenderMode, m_AtlasTextures[m_AtlasTextureIndex], out glyphs); // Add new glyphs to relevant data structures. - for (int i = 0; i < glyphsAddedCount && glyphs[i] != null; i++) + for (int i = 0; i < glyphs.Length && glyphs[i] != null; i++) { Glyph glyph = glyphs[i]; uint glyphIndex = glyph.index; diff --git a/Modules/TextCoreTextEngine/Managed/TextAssets/FontAsset/NativeFontAsset.cs b/Modules/TextCoreTextEngine/Managed/TextAssets/FontAsset/NativeFontAsset.cs index 90f5d19988..7ee23f9dd5 100644 --- a/Modules/TextCoreTextEngine/Managed/TextAssets/FontAsset/NativeFontAsset.cs +++ b/Modules/TextCoreTextEngine/Managed/TextAssets/FontAsset/NativeFontAsset.cs @@ -91,12 +91,15 @@ private bool HasRecursionInternal(FontAsset fontAsset) // Mark the node as visited visitedFontAssets.Add(fontAsset.instanceID); - // Recursively check children for recursion - foreach (var child in fontAsset.fallbackFontAssetTable) + if (fontAsset.fallbackFontAssetTable != null) { - if (HasRecursionInternal(child)) + // Recursively check children for recursion + foreach (var child in fontAsset.fallbackFontAssetTable) { - return true; + if (HasRecursionInternal(child)) + { + return true; + } } } diff --git a/Modules/TextCoreTextEngine/Managed/TextAssets/FontAssetUtilities.cs b/Modules/TextCoreTextEngine/Managed/TextAssets/FontAssetUtilities.cs index a83e14d517..2ba3b8ad17 100644 --- a/Modules/TextCoreTextEngine/Managed/TextAssets/FontAssetUtilities.cs +++ b/Modules/TextCoreTextEngine/Managed/TextAssets/FontAssetUtilities.cs @@ -223,12 +223,31 @@ private static Character GetCharacterFromFontAsset_Internal(uint unicode, FontAs /// The font weight /// Determines if the OUT font asset is an alternative typeface or fallback font asset /// - public static Character GetCharacterFromFontAssets(uint unicode, FontAsset sourceFontAsset, List fontAssets, bool includeFallbacks, FontStyles fontStyle, TextFontWeight fontWeight, out bool isAlternativeTypeface) + public static Character GetCharacterFromFontAssets(uint unicode, FontAsset sourceFontAsset, List fontAssets, List OSFallbackList, bool includeFallbacks, FontStyles fontStyle, TextFontWeight fontWeight, out bool isAlternativeTypeface) { - return GetCharacterFromFontAssetsInternal(unicode, sourceFontAsset, fontAssets, includeFallbacks, fontStyle, fontWeight, out isAlternativeTypeface); + return GetCharacterFromFontAssetsInternal(unicode, sourceFontAsset, fontAssets, OSFallbackList, includeFallbacks, fontStyle, fontWeight, out isAlternativeTypeface); } - internal static Character GetCharacterFromFontAssetsInternal(uint unicode, FontAsset sourceFontAsset, List fontAssets, bool includeFallbacks, FontStyles fontStyle, TextFontWeight fontWeight, out bool isAlternativeTypeface, bool populateLigatures = true) + internal static Character GetCharacterFromFontAssetsInternal(uint unicode, FontAsset sourceFontAsset, List fontAssets, List OSFallbackList, bool includeFallbacks, FontStyles fontStyle, TextFontWeight fontWeight, out bool isAlternativeTypeface, bool populateLigatures = true) + { + isAlternativeTypeface = false; + + if (includeFallbacks) + { + if (k_SearchedAssets == null) + k_SearchedAssets = new HashSet(); + else + k_SearchedAssets.Clear(); + } + + Character character = GetCharacterFromFontAssetsInternal(unicode, fontAssets, includeFallbacks, fontStyle, fontWeight, out isAlternativeTypeface, populateLigatures); + if (character != null) + return character; + + return GetCharacterFromFontAssetsInternal(unicode, OSFallbackList, includeFallbacks, fontStyle, fontWeight, out isAlternativeTypeface, populateLigatures); + } + + private static Character GetCharacterFromFontAssetsInternal(uint unicode, List fontAssets, bool includeFallbacks, FontStyles fontStyle, TextFontWeight fontWeight, out bool isAlternativeTypeface, bool populateLigatures = true) { isAlternativeTypeface = false; diff --git a/Modules/TextCoreTextEngine/Managed/TextAssets/TextSettings.cs b/Modules/TextCoreTextEngine/Managed/TextAssets/TextSettings.cs index 8b3a5808d2..995fb1bf2f 100644 --- a/Modules/TextCoreTextEngine/Managed/TextAssets/TextSettings.cs +++ b/Modules/TextCoreTextEngine/Managed/TextAssets/TextSettings.cs @@ -65,6 +65,30 @@ public List fallbackFontAssets [FormerlySerializedAs("m_fallbackFontAssets")][SerializeField] protected List m_FallbackFontAssets; + internal List fallbackOSFontAssets + { + get + { + if (GetStaticFallbackOSFontAsset() == null) + { + SetStaticFallbackOSFontAsset(GetOSFontAssetList()); + } + return GetStaticFallbackOSFontAsset(); + } + } + + private static List s_FallbackOSFontAssetInternal; + + internal virtual List GetStaticFallbackOSFontAsset() + { + return s_FallbackOSFontAssetInternal; + } + + internal virtual void SetStaticFallbackOSFontAsset(List fontAssets) + { + s_FallbackOSFontAssetInternal = fontAssets; + } + /// /// Determines if the text system will use an instance material derived from the primary material preset or use the default material of the fallback font asset. /// @@ -265,6 +289,7 @@ public bool displayWarnings void OnEnable() { lineBreakingRules.LoadLineBreakingRules(); + SetStaticFallbackOSFontAsset(null); if (s_GlobalSpriteAsset == null) s_GlobalSpriteAsset = Resources.Load("Sprite Assets/Default Sprite Asset"); } @@ -348,7 +373,7 @@ internal FontAsset GetCachedFontAsset(Font font, Shader shader) } else { - fontAsset = FontAsset.CreateFontAsset(font, 90, 9, GlyphRenderMode.SDFAA, 1024, 1024, AtlasPopulationMode.Dynamic, true); + fontAsset = FontAsset.CreateFontAsset(font, 90, 9, GlyphRenderMode.SDFAA, 1024, 1024, shader, AtlasPopulationMode.Dynamic, true); } if (fontAsset != null) @@ -366,6 +391,17 @@ internal FontAsset GetCachedFontAsset(Font font, Shader shader) return fontAsset; } + internal virtual Shader GetFontShader() + { + return TextShaderUtilities.ShaderRef_MobileSDF; + } + + private List GetOSFontAssetList() + { + var fonts = Font.GetOSFallbacks(); + return FontAsset.CreateFontAssetOSFallbackList(fonts, GetFontShader()); + } + [VisibleToOtherModules("UnityEngine.IMGUIModule", "UnityEngine.UIElementsModule")] internal virtual float GetEditorTextSharpness() { diff --git a/Modules/TextCoreTextEngine/Managed/TextGenerator/TextGeneratorPrepare.cs b/Modules/TextCoreTextEngine/Managed/TextGenerator/TextGeneratorPrepare.cs index 5059cb92c9..e00ed2ef01 100644 --- a/Modules/TextCoreTextEngine/Managed/TextGenerator/TextGeneratorPrepare.cs +++ b/Modules/TextCoreTextEngine/Managed/TextGenerator/TextGeneratorPrepare.cs @@ -57,13 +57,13 @@ internal bool PrepareFontAsset(TextGenerationSettings generationSettings) m_FontWeightInternal = (m_FontStyleInternal & FontStyles.Bold) == FontStyles.Bold ? TextFontWeight.Bold : generationSettings.fontWeight; // Find and cache Underline & Ellipsis characters. - GetSpecialCharacters(generationSettings); + if (!GetSpecialCharacters(generationSettings)) + return false; //ParseInputText PopulateTextBackingArray(generationSettings.renderedText); PopulateTextProcessingArray(generationSettings); - bool success = PopulateFontAsset(generationSettings, m_TextProcessingArray); - return success; + return PopulateFontAsset(generationSettings, m_TextProcessingArray); } // This function parses through the Char[] to determine how many characters will be visible. It then makes sure the arrays are large enough for all those characters. @@ -275,9 +275,7 @@ int SetArraySizes(TextProcessingElement[] textProcessingArray, TextGenerationSet if (character == null) { - // Search for the missing glyph character in the Settings Fallback list. - if (textSettings.fallbackFontAssets != null && textSettings.fallbackFontAssets.Count > 0) - character = FontAssetUtilities.GetCharacterFromFontAssetsInternal((uint)unicode, m_CurrentFontAsset, textSettings.fallbackFontAssets, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface, ligature); + character = FontAssetUtilities.GetCharacterFromFontAssetsInternal((uint)unicode, m_CurrentFontAsset, textSettings.fallbackFontAssets, textSettings.fallbackOSFontAssets, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface, ligature); } if (character == null) @@ -562,7 +560,7 @@ TextElement GetTextElement(TextGenerationSettings generationSettings, uint unico // Search potential list of fallback font assets assigned to the font asset. if (fontAsset.m_FallbackFontAssetTable != null && fontAsset.m_FallbackFontAssetTable.Count > 0) - character = FontAssetUtilities.GetCharacterFromFontAssetsInternal(unicode, fontAsset, fontAsset.m_FallbackFontAssetTable, true, fontStyle, fontWeight, out isUsingAlternativeTypeface, populateLigatures); + character = FontAssetUtilities.GetCharacterFromFontAssetsInternal(unicode, fontAsset, fontAsset.m_FallbackFontAssetTable, OSFallbackList: null, true, fontStyle, fontWeight, out isUsingAlternativeTypeface, populateLigatures); if (character != null) { @@ -593,7 +591,7 @@ TextElement GetTextElement(TextGenerationSettings generationSettings, uint unico // Search list of potential fallback font assets assigned to the primary font asset. if (generationSettings.fontAsset.m_FallbackFontAssetTable != null && generationSettings.fontAsset.m_FallbackFontAssetTable.Count > 0) - character = FontAssetUtilities.GetCharacterFromFontAssetsInternal(unicode, fontAsset, generationSettings.fontAsset.m_FallbackFontAssetTable, true, fontStyle, fontWeight, out isUsingAlternativeTypeface, populateLigatures); + character = FontAssetUtilities.GetCharacterFromFontAssetsInternal(unicode, fontAsset, generationSettings.fontAsset.m_FallbackFontAssetTable, OSFallbackList: null, true, fontStyle, fontWeight, out isUsingAlternativeTypeface, populateLigatures); if (character != null) { @@ -613,9 +611,10 @@ TextElement GetTextElement(TextGenerationSettings generationSettings, uint unico return spriteCharacter; } + if (textSettings.GetStaticFallbackOSFontAsset() == null && !canWriteOnAsset) + return null; // Search for the character in the list of fallback assigned in the settings (General Fallbacks). - if (textSettings.fallbackFontAssets != null && textSettings.fallbackFontAssets.Count > 0) - character = FontAssetUtilities.GetCharacterFromFontAssetsInternal(unicode, fontAsset, textSettings.fallbackFontAssets, true, fontStyle, fontWeight, out isUsingAlternativeTypeface, populateLigatures); + character = FontAssetUtilities.GetCharacterFromFontAssetsInternal(unicode, fontAsset, textSettings.fallbackFontAssets, textSettings.fallbackOSFontAssets, true, fontStyle, fontWeight, out isUsingAlternativeTypeface, populateLigatures); if (character != null) { @@ -1066,9 +1065,10 @@ bool PopulateFontAsset(TextGenerationSettings generationSettings, TextProcessing if (character == null) { + if (textSettings.GetStaticFallbackOSFontAsset() == null && !canWriteOnAsset) + return false; // Search for the missing glyph character in the Settings Fallback list. - if (textSettings.fallbackFontAssets != null && textSettings.fallbackFontAssets.Count > 0) - character = FontAssetUtilities.GetCharacterFromFontAssetsInternal((uint)unicode, m_CurrentFontAsset, textSettings.fallbackFontAssets, true, m_FontStyleInternal, m_FontWeightInternal, out _, ligature); + character = FontAssetUtilities.GetCharacterFromFontAssetsInternal((uint)unicode, m_CurrentFontAsset, textSettings.fallbackFontAssets, textSettings.fallbackOSFontAssets, true, m_FontStyleInternal, m_FontWeightInternal, out _, ligature); } if (character == null) @@ -1313,15 +1313,17 @@ public SpecialCharacter(Character character, int materialIndex) /// Method used to find and cache references to the Underline and Ellipsis characters. /// /// - protected void GetSpecialCharacters(TextGenerationSettings generationSettings) + protected bool GetSpecialCharacters(TextGenerationSettings generationSettings) { - GetEllipsisSpecialCharacter(generationSettings); + if (!GetEllipsisSpecialCharacter(generationSettings)) + return false; - GetUnderlineSpecialCharacter(generationSettings); + return GetUnderlineSpecialCharacter(generationSettings); } - protected void GetEllipsisSpecialCharacter(TextGenerationSettings generationSettings) + protected bool GetEllipsisSpecialCharacter(TextGenerationSettings generationSettings) { + bool canWriteOnAsset = !IsExecutingJob; bool isUsingAlternativeTypeface; FontAsset fontAsset = m_CurrentFontAsset ?? generationSettings.fontAsset; @@ -1335,14 +1337,15 @@ protected void GetEllipsisSpecialCharacter(TextGenerationSettings generationSett { // Search primary fallback list if (fontAsset.m_FallbackFontAssetTable != null && fontAsset.m_FallbackFontAssetTable.Count > 0) - character = FontAssetUtilities.GetCharacterFromFontAssetsInternal(k_HorizontalEllipsis, fontAsset, fontAsset.m_FallbackFontAssetTable, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface, populateLigature); + character = FontAssetUtilities.GetCharacterFromFontAssetsInternal(k_HorizontalEllipsis, fontAsset, fontAsset.m_FallbackFontAssetTable, OSFallbackList: null, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface, populateLigature); } // Search the setting's general fallback list if (character == null) { - if (textSettings.fallbackFontAssets != null && textSettings.fallbackFontAssets.Count > 0) - character = FontAssetUtilities.GetCharacterFromFontAssetsInternal(k_HorizontalEllipsis, fontAsset, textSettings.fallbackFontAssets, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface, populateLigature); + if (textSettings.GetStaticFallbackOSFontAsset() == null && !canWriteOnAsset) + return false; + character = FontAssetUtilities.GetCharacterFromFontAssetsInternal(k_HorizontalEllipsis, fontAsset, textSettings.fallbackFontAssets, textSettings.fallbackOSFontAssets, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface, populateLigature); } // Search the setting's default font asset @@ -1354,10 +1357,13 @@ protected void GetEllipsisSpecialCharacter(TextGenerationSettings generationSett if (character != null) m_Ellipsis = new SpecialCharacter(character, 0); + + return true; } - protected void GetUnderlineSpecialCharacter(TextGenerationSettings generationSettings) + protected bool GetUnderlineSpecialCharacter(TextGenerationSettings generationSettings) { + bool canWriteOnAsset = !IsExecutingJob; bool isUsingAlternativeTypeface; FontAsset fontAsset = m_CurrentFontAsset ?? generationSettings.fontAsset; @@ -1367,8 +1373,13 @@ protected void GetUnderlineSpecialCharacter(TextGenerationSettings generationSet // Search base font asset Character character = FontAssetUtilities.GetCharacterFromFontAsset(0x5F, fontAsset, false, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface, populateLigature); + if (character == null && !canWriteOnAsset) + return false; + if (character != null) m_Underline = new SpecialCharacter(character, m_CurrentMaterialIndex); + + return true; } protected void DoMissingGlyphCallback(uint unicode, int stringIndex, FontAsset fontAsset, TextInfo textInfo) diff --git a/Modules/TextRendering/TextRendering.bindings.cs b/Modules/TextRendering/TextRendering.bindings.cs index 2546c1cd4f..70221bda13 100644 --- a/Modules/TextRendering/TextRendering.bindings.cs +++ b/Modules/TextRendering/TextRendering.bindings.cs @@ -378,6 +378,8 @@ public bool HasCharacter(char c) public static extern string[] GetOSInstalledFontNames(); public static extern string[] GetPathsToOSFonts(); + [VisibleToOtherModules("UnityEngine.TextCoreTextEngineModule")] + internal static extern string[] GetOSFallbacks(); private static extern void Internal_CreateFont([Writable] Font self, string name); private static extern void Internal_CreateFontFromPath([Writable] Font self, string fontPath); diff --git a/Modules/UIBuilder/Editor/Builder/BuilderSelection.cs b/Modules/UIBuilder/Editor/Builder/BuilderSelection.cs index 254a6af7b1..d27c22705b 100644 --- a/Modules/UIBuilder/Editor/Builder/BuilderSelection.cs +++ b/Modules/UIBuilder/Editor/Builder/BuilderSelection.cs @@ -47,6 +47,10 @@ internal enum BuilderStylingChangeType internal interface IBuilderSelectionNotifier { + void BeforeSelectionChanged() + { + } + void SelectionChanged(); void HierarchyChanged(VisualElement element, BuilderHierarchyChangeType changeType); void StylingChanged(List styles, BuilderStylingChangeType changeType); @@ -162,6 +166,8 @@ public void Select(IBuilderSelectionNotifier source, VisualElement ve) if (ve == null) return; + NotifyOfBeforeSelectionChange(source); + foreach (var sel in m_Selection) { if (sel == null) @@ -188,6 +194,8 @@ void AddToSelection(IBuilderSelectionNotifier source, VisualElement ve, bool und if (ve == null) return; + NotifyOfBeforeSelectionChange(source); + m_Selection.Add(ve); if (sort) @@ -201,6 +209,8 @@ void AddToSelection(IBuilderSelectionNotifier source, VisualElement ve, bool und public void RemoveFromSelection(IBuilderSelectionNotifier source, VisualElement ve) { + NotifyOfBeforeSelectionChange(source); + m_Selection.Remove(ve); BuilderAssetUtilities.RemoveElementFromSelectionInAsset(m_PaneWindow.document, ve); @@ -212,6 +222,8 @@ public void ClearSelection(IBuilderSelectionNotifier source, bool undo = true) if (isEmpty) return; + NotifyOfBeforeSelectionChange(source); + if (undo) foreach (var sel in m_Selection) BuilderAssetUtilities.RemoveElementFromSelectionInAsset(m_PaneWindow.document, sel); @@ -297,6 +309,16 @@ public void NotifyOfStylingChange(IBuilderSelectionNotifier source = null, List< QueueUpPostPanelUpdaterChangeAction(NotifyOfStylingChangePostStylingUpdate); } + void NotifyOfBeforeSelectionChange(IBuilderSelectionNotifier source) + { + if (m_Notifiers == null || m_Notifiers.Count == 0) + return; + + foreach (var notifier in m_Notifiers) + if (notifier != source) + notifier.BeforeSelectionChanged(); + } + void NotifyOfSelectionChange(IBuilderSelectionNotifier source) { if (m_Notifiers == null || m_Notifiers.Count == 0) diff --git a/Modules/UIBuilder/Editor/Builder/Document/BuilderDocumentOpenUXML.cs b/Modules/UIBuilder/Editor/Builder/Document/BuilderDocumentOpenUXML.cs index 81c94e0e97..dc5db12c87 100644 --- a/Modules/UIBuilder/Editor/Builder/Document/BuilderDocumentOpenUXML.cs +++ b/Modules/UIBuilder/Editor/Builder/Document/BuilderDocumentOpenUXML.cs @@ -930,7 +930,22 @@ void ClearCanvasDocumentRootElement(VisualElement documentRootElement) if (documentRootElement == null) return; + documentRootElement.Clear(); + + if (documentRootElement is TemplateContainer rootTemplate) + { + // If the contentContainer was set then + if (documentRootElement.contentContainer != documentRootElement) + { + // Clear the hierarchy + documentRootElement.hierarchy.Clear(); + + // Reset the content container + rootTemplate.SetContentContainer(rootTemplate); + } + } + ResetCanvasDocumentRootElementStyleSheets(documentRootElement); BuilderSharedStyles.ClearContainer(documentRootElement); diff --git a/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorerItem.cs b/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorerItem.cs index 7e6df40011..ec29ef8fb7 100644 --- a/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorerItem.cs +++ b/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorerItem.cs @@ -42,13 +42,13 @@ public void ActivateRenameElementMode() { var documentElement = GetProperty(BuilderConstants.ElementLinkedDocumentVisualElementVEPropertyName) as VisualElement; - if ((!documentElement.IsPartOfCurrentDocument() || BuilderSharedStyles.IsDocumentElement(documentElement)) && + if ((!documentElement.IsPartOfCurrentDocument() || + BuilderSharedStyles.IsDocumentElement(documentElement)) && !BuilderSharedStyles.IsSelectorElement(documentElement)) return; + documentElement.schedule.Execute(FocusOnRenameTextField).ExecuteLater(100); SetReorderingZonesEnabled(false); - - FocusOnRenameTextField(); } internal void SetReorderingZonesEnabled(bool value) diff --git a/Modules/UIBuilder/Editor/Builder/Explorer/BuilderHierarchy.cs b/Modules/UIBuilder/Editor/Builder/Explorer/BuilderHierarchy.cs index 5769990296..89d2ad2e10 100644 --- a/Modules/UIBuilder/Editor/Builder/Explorer/BuilderHierarchy.cs +++ b/Modules/UIBuilder/Editor/Builder/Explorer/BuilderHierarchy.cs @@ -43,8 +43,10 @@ public override void HierarchyChanged(VisualElement element, BuilderHierarchyCha if ((changeType & (BuilderHierarchyChangeType.ElementName | BuilderHierarchyChangeType.ClassList)) != 0) { - var selectedId = m_ElementHierarchyView.GetSelectedItemId(); - var index = m_ElementHierarchyView.treeView.viewController.GetIndexForId(selectedId); + // Look for the item associated with the element renamed. Note that the edited element may not be selected + // yet. + var item = m_ElementHierarchyView.FindElement(m_ElementHierarchyView.treeRootItems, element); + var index = m_ElementHierarchyView.treeView.viewController.GetIndexForId(item.id); if (index == -1) { return; diff --git a/Modules/UIBuilder/Editor/Builder/Explorer/BuilderStyleSheets.cs b/Modules/UIBuilder/Editor/Builder/Explorer/BuilderStyleSheets.cs index cc7e903388..07c6bcbd36 100644 --- a/Modules/UIBuilder/Editor/Builder/Explorer/BuilderStyleSheets.cs +++ b/Modules/UIBuilder/Editor/Builder/Explorer/BuilderStyleSheets.cs @@ -246,7 +246,7 @@ void OnEnter(KeyDownEvent evt) void CreateNewSelector(StyleSheet styleSheet) { var newValue = m_NewSelectorTextField.text; - if (newValue == BuilderConstants.ExplorerInExplorerNewClassSelectorInfoMessage) + if (string.IsNullOrEmpty(newValue) || newValue == BuilderConstants.ExplorerInExplorerNewClassSelectorInfoMessage) return; if (styleSheet == null) diff --git a/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderBindingUxmlAtttributesView.cs b/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderBindingUxmlAtttributesView.cs index 027a95d449..d639197b59 100644 --- a/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderBindingUxmlAtttributesView.cs +++ b/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderBindingUxmlAtttributesView.cs @@ -23,6 +23,7 @@ internal class BuilderBindingUxmlAttributesView : BuilderDataSourceAndPathView, internal new struct TestAccess { + public ToggleButtonGroup buttonStrip; public BuilderObjectField dataSourceField; public BaseField dataSourceTypeField; public TextField dataSourcePathField; @@ -45,6 +46,7 @@ internal class BuilderBindingUxmlAttributesView : BuilderDataSourceAndPathView, var baseTestAccess = base.testAccess; return new TestAccess { + buttonStrip = baseTestAccess.buttonStrip, dataSourceField = baseTestAccess.dataSourceField, dataSourceTypeField = baseTestAccess.dataSourceTypeField, dataSourcePathField = baseTestAccess.dataSourcePathField, @@ -388,7 +390,7 @@ public void TransferBindingInstance(string path, BuilderUxmlAttributesView targe Undo.CollapseUndoOperations(undoGroup); // Apply changes to the element - targetView.CallDeserializeOnElement(); + targetView.CallDeserializeOnElement(); targetView.SendNotifyAttributesChanged(); } diff --git a/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderBindingWindow.cs b/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderBindingWindow.cs index 74e6c531b8..996ede782f 100644 --- a/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderBindingWindow.cs +++ b/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderBindingWindow.cs @@ -51,6 +51,8 @@ void OnEnable() { Builder.ActiveWindow.closing += Close; } + + AssemblyReloadEvents.beforeAssemblyReload += Close; } private void OnDisable() @@ -62,6 +64,8 @@ private void OnDisable() m_View.closing?.Invoke(); m_View = null; s_Window = null; + + AssemblyReloadEvents.beforeAssemblyReload -= Close; } internal override void OnResized() diff --git a/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderDataSourceAndPathView.cs b/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderDataSourceAndPathView.cs index e6143e6881..bb754957a8 100644 --- a/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderDataSourceAndPathView.cs +++ b/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderDataSourceAndPathView.cs @@ -26,6 +26,7 @@ internal class BuilderDataSourceAndPathView : BuilderUxmlAttributesView internal struct TestAccess { + public ToggleButtonGroup buttonStrip; public BuilderObjectField dataSourceField; public BaseField dataSourceTypeField; public TextField dataSourcePathField; @@ -37,6 +38,7 @@ internal struct TestAccess // Note: They are internal only to be accessible in tests internal TestAccess testAccess => new() { + buttonStrip = m_ButtonStrip, dataSourceField = m_DataSourceField, dataSourceTypeField = m_DataSourceTypeField, dataSourcePathField = m_DataSourcePathField, @@ -126,6 +128,8 @@ public Type inheritedDataSourceType protected bool isBinding => bindingUxmlSerializedDataDescription != null; + private bool isShowingDataSource { get; set; } = true; + /// /// Notifies attributes have changed. /// @@ -239,12 +243,19 @@ void GenerateDataBindingFields(VisualElement root) { m_BindingsFoldout = new PersistedFoldout() { text = "Bindings", classList = { PersistedFoldout.unindentedUssClassName } }; - m_ButtonStrip = new ToggleButtonGroup("Data Source"); + m_ButtonStrip = new ToggleButtonGroup("Data Source") + { + viewDataKey = isBinding ? "builder__binding-window__data-source-field" : "builder__inspector-header__data-source-field" + }; m_ButtonStrip.Add(new Button { text = "Object", style = { flexGrow = 1 }, tooltip = k_DataSourceObjectTooltip }); m_ButtonStrip.Add(new Button { text = "Type", style = { flexGrow = 1 }, tooltip = k_DataSourceTypeTooltip}); m_ButtonStrip.isMultipleSelection = false; m_ButtonStrip.AddToClassList(ToggleButtonGroup.alignedFieldUssClassName); m_ButtonStrip.RegisterValueChangedCallback(evt => SetSourceVisibility(evt.newValue[0])); + + // Show Asset by default. + m_ButtonStrip.value = new ToggleButtonGroupState(0b01, 2); + m_BindingsFoldout.Add(m_ButtonStrip); m_BindingsFoldout.Add(m_SourceWidgetContainer = new VisualElement() { style = { flexGrow = 1 } }); } @@ -279,9 +290,13 @@ void GenerateDataBindingFields(VisualElement root) var attribute = uxmlSerializedDataDescription?.FindAttributeWithUxmlName(k_BindingAttr_DataSourceType) ?? FindAttribute(k_BindingAttr_DataSourceType); SetupStyleRow(styleRow, m_TypeFieldContainer, attribute); - // Show Asset by default. - m_ButtonStrip.value = new ToggleButtonGroupState(0b01, 2); - SetSourceVisibility(true); + // Set current value + m_ButtonStrip.value = isShowingDataSource + ? new ToggleButtonGroupState(0b01, 2) + : new ToggleButtonGroupState(0b10, 2); + + // Force update visibility in case the value didn't change. + SetSourceVisibility(isShowingDataSource); if (isBinding) { @@ -345,8 +360,10 @@ VisualElement CreateAttributeField(string attribute) void SetSourceVisibility(bool showAsset) { + isShowingDataSource = showAsset; m_AssetFieldContainer.style.display = showAsset ? DisplayStyle.Flex : DisplayStyle.None; m_TypeFieldContainer.style.display = showAsset ? DisplayStyle.None : DisplayStyle.Flex; + UpdateCompleter(); } /// @@ -529,7 +546,7 @@ void UpdateCompleter() } } - m_DataSourcePathCompleter.UpdateResults(); + m_DataSourcePathCompleter.UpdateResults(isShowingDataSource); } void UpdateWarningBox() diff --git a/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderDataSourcePathCompleter.cs b/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderDataSourcePathCompleter.cs index 8498955900..ec94b85657 100644 --- a/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderDataSourcePathCompleter.cs +++ b/Modules/UIBuilder/Editor/Builder/Inspector/Binding/BuilderDataSourcePathCompleter.cs @@ -18,6 +18,7 @@ class BuilderDataSourcePathCompleter : FieldSearchCompleter private List m_ToUICompatibleTypes; private Dictionary> m_ToSrcCompatibleTypesMap; private List m_CompatibleProperties = new (); + private bool m_ShowForDataSource = true; private List m_AllProperties = new (); private DataBinding m_Binding; @@ -97,10 +98,10 @@ public BuilderDataSourcePathCompleter(TextField field) /// /// Updates the completer results /// - public void UpdateResults() + public void UpdateResults(bool showForDataSource) { enabled = element != null && (bindingDataSource != null || bindingDataSourceType != null); - UpdatePropertyList(); + UpdatePropertyList(showForDataSource); } protected override VisualElement MakeDetailsContent() @@ -114,11 +115,11 @@ protected override VisualElement MakeFooterContent() { if (m_Binding == null) return null; - + m_ShowOnlyCompatibleResultsToggle = new ShowOnlyCompatibleResultsToggle(); m_ShowOnlyCompatibleResultsToggle.toggle.RegisterValueChangedCallback((_) => { - UpdateResults(); + UpdateResults(m_ShowForDataSource); Refresh(); }); @@ -158,8 +159,9 @@ protected override FieldSearchCompleterPopup CreatePopup() return popup; } - void UpdatePropertyList() + void UpdatePropertyList(bool showForDataSource) { + m_ShowForDataSource = showForDataSource; m_AllProperties.Clear(); m_CompatibleProperties.Clear(); m_ToUICompatibleTypes?.Clear(); @@ -168,13 +170,16 @@ void UpdatePropertyList() if (enabled) { // If the binding data source is specified then ignore the binding data source type. - if (bindingDataSource != null) + if (m_ShowForDataSource) { - var source = bindingDataSource; + if (bindingDataSource != null) + { + var source = bindingDataSource; - if (source is BuilderObjectField.NonUnityObjectValue nonUnityObject) - source = nonUnityObject.data; - DataBindingUtility.GetPropertyPaths(source, int.MaxValue, m_AllProperties); + if (source is BuilderObjectField.NonUnityObjectValue nonUnityObject) + source = nonUnityObject.data; + DataBindingUtility.GetPropertyPaths(source, int.MaxValue, m_AllProperties); + } } else { diff --git a/Modules/UIBuilder/Editor/Builder/Inspector/BuilderInspector.cs b/Modules/UIBuilder/Editor/Builder/Inspector/BuilderInspector.cs index 230a31fcb8..96c3ad0298 100644 --- a/Modules/UIBuilder/Editor/Builder/Inspector/BuilderInspector.cs +++ b/Modules/UIBuilder/Editor/Builder/Inspector/BuilderInspector.cs @@ -1328,6 +1328,19 @@ public void HierarchyChanged(VisualElement element, BuilderHierarchyChangeType c } } + public void BeforeSelectionChanged() + { + // Check whether the focused element is a field in the inspector. If so, then blur it immediately + // to commit its value (e.g: delayed text field such as the name field) before the selection changes + if (focusController is { focusedElement: VisualElement focusedElement } && Contains(focusedElement)) + { + focusedElement.BlurImmediately(); + } + + // Force submit the pending committed value changes + m_AttributesSection.ProcessBatchedChanges(); + } + public void SelectionChanged() { using var marker = k_SelectionChangedMarker.Auto(); diff --git a/Modules/UIBuilder/Editor/Builder/Inspector/BuilderInspectorHeader.cs b/Modules/UIBuilder/Editor/Builder/Inspector/BuilderInspectorHeader.cs index 61de962def..0a18b247c5 100644 --- a/Modules/UIBuilder/Editor/Builder/Inspector/BuilderInspectorHeader.cs +++ b/Modules/UIBuilder/Editor/Builder/Inspector/BuilderInspectorHeader.cs @@ -63,6 +63,7 @@ public BuilderInspectorHeader(BuilderInspector inspector) m_TextField = m_Inspector.Q("header-selected-text-field"); m_TextField.isDelayed = true; + m_TextField.dispatchMode = DispatchMode.Immediate; m_TextField.tooltip = "name"; m_TextField.bindingPath = "name"; diff --git a/Modules/UIBuilder/Editor/Builder/Inspector/BuilderInspectorPreview.cs b/Modules/UIBuilder/Editor/Builder/Inspector/BuilderInspectorPreview.cs index de01fc385a..5aae1da974 100644 --- a/Modules/UIBuilder/Editor/Builder/Inspector/BuilderInspectorPreview.cs +++ b/Modules/UIBuilder/Editor/Builder/Inspector/BuilderInspectorPreview.cs @@ -42,13 +42,13 @@ public BuilderInspectorPreview(BuilderInspector inspector) m_DefaultBackgroundElement = new VisualElement(); m_DefaultBackgroundElement.AddToClassList(s_DefaultBackgroundClassName); m_DefaultBackgroundElement.style.display = DisplayStyle.None; - + // preview text m_Text = new Label(s_PreviewTextContent); m_Text.AddToClassList(s_TextClassName); m_Text.RemoveFromClassList(Label.ussClassName); m_Text.RemoveFromClassList(TextElement.ussClassName); - + // transparency toggle m_BackgroundToggle = new ToolbarToggle(); m_BackgroundToggle.tooltip = BuilderConstants.PreviewTransparencyToggleTooltip; @@ -61,7 +61,7 @@ public BuilderInspectorPreview(BuilderInspector inspector) container.Add(m_CheckerboardBackgroundElement); container.Add(m_DefaultBackgroundElement); container.Add(m_Text); - + Add(container); } @@ -85,7 +85,7 @@ protected override void InitEllipsisMenu() pane.AppendActionToEllipsisMenu(BuilderConstants.PreviewMinimizeInInspector, a => m_Inspector.TogglePreviewInInspector(), - a => !m_Inspector.showingPreview ? + a => !m_Inspector.showingPreview ? DropdownMenuAction.Status.Checked : DropdownMenuAction.Status.Normal); } @@ -93,18 +93,18 @@ private void RefreshPreview() { if (currentVisualElement == null) return; - + SetTextStyles(); } public void ToggleBackground(ChangeEvent evt) { var value = evt.newValue; - - m_CheckerboardBackgroundElement.style.display = value ? DisplayStyle.None : DisplayStyle.Flex; + + m_CheckerboardBackgroundElement.style.display = value ? DisplayStyle.None : DisplayStyle.Flex; m_DefaultBackgroundElement.style.display = value ? DisplayStyle.Flex : DisplayStyle.None; } - + private void SetTextStyles() { m_Text.style.unityFont = currentVisualElement.resolvedStyle.unityFont; diff --git a/Modules/UIBuilder/Editor/Builder/Library/BuilderLibrary.cs b/Modules/UIBuilder/Editor/Builder/Library/BuilderLibrary.cs index 36062d21be..5b64f73286 100644 --- a/Modules/UIBuilder/Editor/Builder/Library/BuilderLibrary.cs +++ b/Modules/UIBuilder/Editor/Builder/Library/BuilderLibrary.cs @@ -327,7 +327,6 @@ public void ResetCurrentlyLoadedUxmlStyles() { RefreshView(); } - public void SelectionChanged() { } public void HierarchyChanged(VisualElement element, BuilderHierarchyChangeType changeType) { } diff --git a/Modules/UIBuilder/Editor/Builder/UxmlAttributesView/BuilderUxmlAttributesView.cs b/Modules/UIBuilder/Editor/Builder/UxmlAttributesView/BuilderUxmlAttributesView.cs index e71709bdfb..0b8d2b4873 100644 --- a/Modules/UIBuilder/Editor/Builder/UxmlAttributesView/BuilderUxmlAttributesView.cs +++ b/Modules/UIBuilder/Editor/Builder/UxmlAttributesView/BuilderUxmlAttributesView.cs @@ -1697,7 +1697,7 @@ int GetCurrentUndoGroup() return m_CurrentUndoGroup.Value; } - void ProcessBatchedChanges() + internal void ProcessBatchedChanges() { if (m_BatchedChanges.Count == 0) return; diff --git a/Modules/UIBuilder/Editor/Builder/Viewport/BuilderViewport.cs b/Modules/UIBuilder/Editor/Builder/Viewport/BuilderViewport.cs index 6a3dc1a2ca..71c31a3bf5 100644 --- a/Modules/UIBuilder/Editor/Builder/Viewport/BuilderViewport.cs +++ b/Modules/UIBuilder/Editor/Builder/Viewport/BuilderViewport.cs @@ -432,7 +432,7 @@ public VisualElement PickElement(Vector2 mousePosition, List pick void OnPick(MouseDownEvent evt) { // Do not prevent zoom and pan - if (evt.button == 2 || (evt.actionKey && evt.altKey || (evt.button == (int)MouseButton.RightMouse && evt.altKey))) + if (evt.button == 2 || (evt.actionKey && evt.altKey || (evt.button == (int)MouseButton.RightMouse && evt.altKey)) || evt.button == 0 && evt.ctrlKey) return; m_PickedElements.Clear(); diff --git a/Modules/UIBuilder/Editor/Utilities/ElementHierarchyView/ElementHierarchyView.cs b/Modules/UIBuilder/Editor/Utilities/ElementHierarchyView/ElementHierarchyView.cs index 4c34d270a8..af141bce1e 100644 --- a/Modules/UIBuilder/Editor/Utilities/ElementHierarchyView/ElementHierarchyView.cs +++ b/Modules/UIBuilder/Editor/Utilities/ElementHierarchyView/ElementHierarchyView.cs @@ -916,7 +916,7 @@ VisualElement MakeItem() return element; } - TreeViewItem FindElement(IEnumerable list, VisualElement element) + public TreeViewItem FindElement(IEnumerable list, VisualElement element) { if (list == null) return default; diff --git a/Modules/UIElements/Core/Bindings/DataBinding.cs b/Modules/UIElements/Core/Bindings/DataBinding.cs index 8b1dea0080..d527e2d9dd 100644 --- a/Modules/UIElements/Core/Bindings/DataBinding.cs +++ b/Modules/UIElements/Core/Bindings/DataBinding.cs @@ -81,7 +81,7 @@ private static MethodInfo CacheReflectionInfo() /// /// This information is only used by the UI Builder as a hint to provide some completion to the data source path field when the effective data source cannot be specified at design time. /// - internal Type dataSourceType { get; set; } + public Type dataSourceType { get; set; } internal string dataSourceTypeString { diff --git a/Modules/UIElements/Core/Controls/InputField/BaseField.cs b/Modules/UIElements/Core/Controls/InputField/BaseField.cs index 79682fabe2..543df64332 100644 --- a/Modules/UIElements/Core/Controls/InputField/BaseField.cs +++ b/Modules/UIElements/Core/Controls/InputField/BaseField.cs @@ -195,6 +195,12 @@ protected TValueType rawValue internal event Func onValidateValue; + // This has been introduced as part of the fix for UUM-62652. + // Enable some fields to specify how ValueChanged events should be dispatched (queued or immediate). It is mainly used by delayed text fields + // to immediately notify on value change as soon as the focus is lost, which was required to fix UUM-62652. + [VisibleToOtherModules("UnityEditor.UIBuilderModule")] + internal DispatchMode dispatchMode { get; set; } = DispatchMode.Default; + /// /// The value associated with the field. /// @@ -217,7 +223,7 @@ public virtual TValueType value using (ChangeEvent evt = ChangeEvent.GetPooled(previousValue, m_Value)) { evt.elementTarget = this; - SendEvent(evt); + SendEvent(evt, dispatchMode); } NotifyPropertyChanged(valueProperty); } diff --git a/Modules/UIElements/Core/Controls/MultiColumn/Column.cs b/Modules/UIElements/Core/Controls/MultiColumn/Column.cs index 0bb4411eba..6fd6b328aa 100644 --- a/Modules/UIElements/Core/Controls/MultiColumn/Column.cs +++ b/Modules/UIElements/Core/Controls/MultiColumn/Column.cs @@ -164,7 +164,7 @@ internal class UxmlObjectFactory : UxmlObjectFactory {} /// /// Defines for the . /// - [Obsolete("UxmlObjectTraits is deprecated and will be removed. Use UxmlElementAttribute instead.", false)]/// + [Obsolete("UxmlObjectTraits is deprecated and will be removed. Use UxmlElementAttribute instead.", false)] internal class UxmlObjectTraits : UnityEngine.UIElements.UxmlObjectTraits where T : Column { UxmlStringAttributeDescription m_Name = new UxmlStringAttributeDescription { name = "name" }; @@ -713,5 +713,20 @@ void NotifyChange(ColumnDataType type) { changed?.Invoke(this, type); } + + internal float GetWidth(float layoutWidth) + { + return width.unit == LengthUnit.Pixel ? width.value : width.value * layoutWidth / 100f; + } + + internal float GetMaxWidth(float layoutWidth) + { + return maxWidth.unit == LengthUnit.Pixel ? maxWidth.value : maxWidth.value * layoutWidth / 100f; + } + + internal float GetMinWidth(float layoutWidth) + { + return minWidth.unit == LengthUnit.Pixel ? minWidth.value : minWidth.value * layoutWidth / 100f; + } } } diff --git a/Modules/UIElements/Core/Controls/MultiColumn/ColumnLayout.cs b/Modules/UIElements/Core/Controls/MultiColumn/ColumnLayout.cs index efa140833b..2d275a649d 100644 --- a/Modules/UIElements/Core/Controls/MultiColumn/ColumnLayout.cs +++ b/Modules/UIElements/Core/Controls/MultiColumn/ColumnLayout.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; +using UnityEngine.Pool; namespace UnityEngine.UIElements { @@ -15,6 +16,8 @@ class ColumnLayout { List m_StretchableColumns = new List(); List m_FixedColumns = new List(); + List m_RelativeWidthColumns = new List(); + List m_MixedWidthColumns = new List(); Columns m_Columns; float m_ColumnsWidth = 0; bool m_ColumnsWidthDirty = true; @@ -22,6 +25,7 @@ class ColumnLayout float m_MinColumnsWidth = 0; bool m_IsDirty = false; float m_PreviousWidth = float.NaN; + float m_LayoutWidth = float.NaN; // Drag info bool m_DragResizeInPreviewMode; @@ -30,6 +34,7 @@ class ColumnLayout float m_DragLastPos; float m_DragInitialColumnWidth; List m_DragStretchableColumns = new List(); + List m_DragRelativeColumns = new List(); List m_DragFixedColumns = new List(); Dictionary m_PreviewDesiredWidths; @@ -63,6 +68,11 @@ public float columnsWidth } } + /// + /// The width of the container. + /// + public float layoutWidth => m_LayoutWidth; + /// /// The total minimum width of all columns. /// @@ -78,6 +88,11 @@ public float columnsWidth /// public bool hasStretchableColumns => m_StretchableColumns.Count > 0; + /// + /// Indicates whether the layout contains relative width columns. + /// + public bool hasRelativeWidthColumns => m_RelativeWidthColumns.Count > 0 || m_MixedWidthColumns.Count > 0; + /// /// Called whenever the layout needs to be performed. /// @@ -192,22 +207,30 @@ static bool IsClamped(float value, float min, float max) /// The width of the container. public void DoLayout(float width) { + m_LayoutWidth = width; if (m_IsDirty) UpdateCache(); + if (hasRelativeWidthColumns) + UpdateMinAndMaxColumnsWidth(); + var totalColumnsWidth = 0f; var fixedColumnsWidth = 0f; var totalStretchableWidth = 0f; var stretchableColumnsWithInvalidWidth = new List(); var stretchableColumnsWithValidWidth = new List(); - /// step 1 - Compute the width of the fixed columns with invalid (not yet computed) width - /// and adjust clamp widths if necessary + // step 1 - Compute the width of the fixed columns with invalid (not yet computed) width + // and adjust clamp widths if necessary foreach (var column in m_Columns) { if (!column.visible) continue; + var minWidth = column.GetMinWidth(m_LayoutWidth); + var maxWidth = column.GetMaxWidth(m_LayoutWidth); + var columnWidth = column.GetWidth(m_LayoutWidth); + // If the actual width is not yet computed then set it if (float.IsNaN(column.desiredWidth)) { @@ -218,7 +241,7 @@ public void DoLayout(float width) continue; } - column.desiredWidth = Mathf.Clamp(column.width.value, column.minWidth.value, column.maxWidth.value); + column.desiredWidth = Mathf.Clamp(columnWidth, minWidth, maxWidth); } else { @@ -230,9 +253,14 @@ public void DoLayout(float width) } // If the actual width is no longer clamped with the min and max width then clamp it - if (!IsClamped(column.desiredWidth, column.minWidth.value, column.maxWidth.value)) + if (!IsClamped(column.desiredWidth, minWidth, maxWidth)) { - column.desiredWidth = Mathf.Clamp(column.width.value, column.minWidth.value, column.maxWidth.value); + column.desiredWidth = Mathf.Clamp(columnWidth, minWidth, maxWidth); + } + + if (columns.stretchMode == Columns.StretchMode.Grow && column.width.unit == LengthUnit.Percent) + { + column.desiredWidth = Mathf.Clamp(columnWidth, minWidth, maxWidth); } } @@ -241,26 +269,26 @@ public void DoLayout(float width) totalColumnsWidth += column.desiredWidth; } - /// step 2 - Compute the width of the stretchable columns with invalid width using the available remaining space + // step 2 - Compute the width of the stretchable columns with invalid width using the available remaining space if (stretchableColumnsWithInvalidWidth.Count > 0) { float availableWidth = Math.Max(0, width - fixedColumnsWidth); int count = m_StretchableColumns.Count; // Sort the columns ensure that the columns with the highest margins of growth are treated last - stretchableColumnsWithInvalidWidth.Sort((c1, c2) => c1.maxWidth.value.CompareTo(c2.maxWidth.value)); + stretchableColumnsWithInvalidWidth.Sort((c1, c2) => c1.GetMaxWidth(m_LayoutWidth).CompareTo(c2.GetMaxWidth(m_LayoutWidth))); foreach (var column in stretchableColumnsWithInvalidWidth) { var widthPerColumn = availableWidth / count; - column.desiredWidth = Mathf.Clamp(widthPerColumn, column.minWidth.value, column.maxWidth.value); + column.desiredWidth = Mathf.Clamp(widthPerColumn, column.GetMinWidth(m_LayoutWidth), column.GetMaxWidth(m_LayoutWidth)); availableWidth = Math.Max(0, availableWidth - column.desiredWidth); --count; } // Sort the columns ensure that the columns with the highest margins of growth are treated last - stretchableColumnsWithValidWidth.Sort((c1, c2) => c1.maxWidth.value.CompareTo(c2.maxWidth.value)); + stretchableColumnsWithValidWidth.Sort((c1, c2) => c1.GetMaxWidth(m_LayoutWidth).CompareTo(c2.GetMaxWidth(m_LayoutWidth))); // Dispatch the remaining space proportionally among the stretchable column with already computed width foreach (var column in stretchableColumnsWithValidWidth) @@ -269,14 +297,14 @@ public void DoLayout(float width) var ratio = oldWidth / totalStretchableWidth; var widthPerColumn = availableWidth * ratio; - column.desiredWidth = Mathf.Clamp(widthPerColumn, column.minWidth.value, column.maxWidth.value); + column.desiredWidth = Mathf.Clamp(widthPerColumn, column.GetMinWidth(m_LayoutWidth), column.GetMaxWidth(m_LayoutWidth)); availableWidth = Math.Max(0, availableWidth - column.desiredWidth); totalStretchableWidth -= oldWidth; --count; } } - if (hasStretchableColumns) + if (hasStretchableColumns || (hasRelativeWidthColumns && m_Columns.stretchMode == Columns.StretchMode.GrowAndFill)) { // Ensure that we do not exceed the combined min and max width of columns float deltaWidth = 0; @@ -291,7 +319,17 @@ public void DoLayout(float width) if (deltaWidth != 0) { - StretchResizeColumns(m_StretchableColumns, m_FixedColumns, ref deltaWidth, false); + // Copy as the original list gets cleared by Dirty() + + using var i = ListPool.Get(out var stretchableColumnsToFit); + using var j = ListPool.Get(out var fixedColumnsToFit); + using var k = ListPool.Get(out var relativeWidthColumnsToFit); + + stretchableColumnsToFit.AddRange(m_StretchableColumns); + fixedColumnsToFit.AddRange(m_FixedColumns); + relativeWidthColumnsToFit.AddRange(m_RelativeWidthColumns); + + StretchResizeColumns(stretchableColumnsToFit, fixedColumnsToFit, relativeWidthColumnsToFit, ref deltaWidth, false, false); } } m_PreviousWidth = width; @@ -305,261 +343,279 @@ public void DoLayout(float width) /// The list of fixed columns. /// The delta. /// Indicated whether this method is called by ResizeToFit. - public void StretchResizeColumns(List stretchableColumns, List fixedColumns, ref float delta, bool resizeToFit) + public void StretchResizeColumns(List stretchableColumns, List fixedColumns, List relativeWidthColumns, ref float delta, bool resizeToFit, bool dragResize) { - if (stretchableColumns.Count == 0 && fixedColumns.Count == 0) + if (stretchableColumns.Count == 0 && relativeWidthColumns.Count == 0 && fixedColumns.Count == 0) return; - int count = stretchableColumns.Count; - float distributedDelta = Math.Abs(delta); - if (delta > 0) { - if (!resizeToFit) - { - // Step 1 - Start distributing the delta to the fixed columns to their desired width from the right to the left - for (int i = fixedColumns.Count - 1; i >= 0; --i) - { - var fixedColumn = fixedColumns[i]; - var appliedDelta = 0f; - var boundWidth = Mathf.Clamp(fixedColumn.width.value, fixedColumn.minWidth.value, fixedColumn.maxWidth.value); + DistributeOverflow(stretchableColumns, fixedColumns, relativeWidthColumns, ref delta, resizeToFit, dragResize); + } + else + { + DistributeExcess(stretchableColumns, fixedColumns, relativeWidthColumns, ref delta, resizeToFit, dragResize); + } + } - // If the width is not set then ignore it - if (fixedColumn.width.value == 0) - continue; + void DistributeOverflow(List stretchableColumns, List fixedColumns, List relativeWidthColumns, ref float delta, bool resizeToFit, bool dragResize) + { + var distributedDelta = Math.Abs(delta); - if (GetDesiredWidth(fixedColumn) > boundWidth) - appliedDelta = Math.Min(distributedDelta, Math.Abs(GetDesiredWidth(fixedColumn) - boundWidth)); + if (!resizeToFit && !dragResize) + { + // Start distributing the delta to the fixed columns to their desired width from the right to the left + distributedDelta = RecomputeToDesiredWidth(fixedColumns, distributedDelta, true, true); - if (appliedDelta > 0f) - ResizeColumn(fixedColumn, GetDesiredWidth(fixedColumn) - appliedDelta, true); + // Recompute the desired width of the percentage columns from the right to the left + distributedDelta = RecomputeToDesiredWidth(relativeWidthColumns, distributedDelta, true, true); + } - distributedDelta -= appliedDelta; + // Start distributing the remaining delta amount to the stretchable columns proportionally to their current width + distributedDelta = RecomputeToMinWidthProportionally(stretchableColumns, distributedDelta, !(resizeToFit || dragResize)); - // If there is no delta to distribute then stop - if (distributedDelta <= 0) - break; - } - } + if (resizeToFit) + { + distributedDelta = RecomputeToMinWidthProportionally(relativeWidthColumns, distributedDelta, false); + distributedDelta = RecomputeToMinWidthProportionally(fixedColumns, distributedDelta, false); - // Step 2 - Start distributing the remaining delta amount to the stretchable columns proportionally to their current width + // When distributing proportionally to the min width, we may have some delta left if the ones with lowest proportions reach min width first + distributedDelta = RecomputeToMinWidth(relativeWidthColumns, distributedDelta, false); + distributedDelta = RecomputeToMinWidth(fixedColumns, distributedDelta, false); + + } + else if (dragResize) + { + // Start distributing the delta to the percentage columns to their min width from the left to the right + distributedDelta = RecomputeToMinWidth(relativeWidthColumns, distributedDelta, true); + + // Start distributing the delta to the fixed columns to their min from the left to the right + distributedDelta = RecomputeToMinWidth(fixedColumns, distributedDelta, true); + } + else + { + // If there is still some delta to distribute then distribute it to the relative and fixed columns + // to their minimum limit from the right to the left if (distributedDelta > 0) { - // Sort the strectable columns to treat the columns with the smallest min with last - stretchableColumns.Sort((c1, c2) => c2.minWidth.value.CompareTo(c1.minWidth.value)); - var totalStretchableWidth = 0f; + distributedDelta = RecomputeToMinWidth(relativeWidthColumns, distributedDelta, true); + distributedDelta = RecomputeToMinWidth(fixedColumns, distributedDelta, true); + } + } - stretchableColumns.ForEach((c) => totalStretchableWidth += GetDesiredWidth(c)); + // Removed the extra delta that could not be distributed. + delta = Math.Max(0, delta - distributedDelta); + } - for (var i = 0; i < stretchableColumns.Count; ++i) - { - var stretchableColumn = stretchableColumns[i]; - var oldWidth = GetDesiredWidth(stretchableColumn); - var ratio = GetDesiredWidth(stretchableColumn) / totalStretchableWidth; - var deltaPerColumn = distributedDelta * ratio; + void DistributeExcess(List stretchableColumns, List fixedColumns, List relativeWidthColumns, ref float delta, bool resizeToFit, bool dragResize) + { + var distributedDelta = Math.Abs(delta); - // Ignore the stretcable columns if they reach their minimum limit - var appliedDelta = 0f; - if (GetDesiredWidth(stretchableColumn) > stretchableColumn.minWidth.value) - appliedDelta = Math.Min(deltaPerColumn, GetDesiredWidth(stretchableColumn) - stretchableColumn.minWidth.value); + if (!resizeToFit && !dragResize) + { + // Start distributing the delta to the fixed columns to their desired width from the right to the left + distributedDelta = RecomputeToDesiredWidth(fixedColumns, distributedDelta, true, false); - if (appliedDelta > 0f) - ResizeColumn(stretchableColumn, GetDesiredWidth(stretchableColumn) - appliedDelta, !resizeToFit); + // Recompute the desired width of the percentage columns from the right to the left + distributedDelta = RecomputeToDesiredWidth(relativeWidthColumns, distributedDelta, true, false); + } - totalStretchableWidth -= oldWidth; - distributedDelta -= appliedDelta; + if (dragResize) + { + distributedDelta = RecomputeToDesiredWidth(fixedColumns, distributedDelta, true, false); + distributedDelta = RecomputeToDesiredWidth(relativeWidthColumns, distributedDelta, true, false); + } - // If there is no delta to distribute then stop - if (distributedDelta <= 0) - break; - } - } + // Start distributing the remaining delta amount to the stretchable columns proportionally to their max value + distributedDelta = RecomputeToMaxWidthProportionally(stretchableColumns, distributedDelta, !(resizeToFit || dragResize)); + + // If there is still some delta to distribute then distribute it to the fixed and relative columns proportionally + // to their maximum limit from the right to the left + if (resizeToFit) + { + distributedDelta = RecomputeToMaxWidthProportionally(relativeWidthColumns, distributedDelta, false); + distributedDelta = RecomputeToMaxWidthProportionally(fixedColumns, distributedDelta, false); + + // When distributing proportionally to the max width, we may have some delta left if the ones with highest proportions reach max width first + distributedDelta = RecomputeToMaxWidth(relativeWidthColumns, distributedDelta, false); + distributedDelta = RecomputeToMaxWidth(fixedColumns, distributedDelta, false); + } + + delta += distributedDelta; + } + + float RecomputeToMaxWidthProportionally(List columns, float distributedDelta, bool setDesiredWidthOnly = false) + { + if (distributedDelta > 0) + { + // Sort the columns to treat the columns with the greatest margins to grow last + columns.Sort((c1, c2) => c1.GetMaxWidth(m_LayoutWidth).CompareTo(c2.GetMaxWidth(m_LayoutWidth))); - if (resizeToFit) + var totalColumnWidth = 0f; + + columns.ForEach((c) => totalColumnWidth += GetDesiredWidth(c)); + + // Start distributing the delta amount to the columns + for (var i = 0; i < columns.Count; ++i) { - // Start distributing the remaining delta amount to the fixed columns proportionally to their current width - if (distributedDelta > 0) - { - // Sort the strectable columns to treat the columns with the smallest min with last - fixedColumns.Sort((c1, c2) => c2.minWidth.value.CompareTo(c1.minWidth.value)); - var totalFixedWidth = 0f; - - fixedColumns.ForEach((c) => totalFixedWidth += GetDesiredWidth(c)); - - for (var i = 0; i < fixedColumns.Count; ++i) - { - var fixedColumn = fixedColumns[i]; - var oldWidth = GetDesiredWidth(fixedColumn); - var ratio = GetDesiredWidth(fixedColumn) / totalFixedWidth; - var deltaPerColumn = distributedDelta * ratio; - - // Ignore the stretcable columns if they reach their minimum limit - var appliedDelta = 0f; - if (GetDesiredWidth(fixedColumn) > fixedColumn.minWidth.value) - appliedDelta = Math.Min(deltaPerColumn, GetDesiredWidth(fixedColumn) - fixedColumn.minWidth.value); - - if (appliedDelta > 0f) - ResizeColumn(fixedColumn, GetDesiredWidth(fixedColumn) - appliedDelta, false); - - totalFixedWidth -= oldWidth; - distributedDelta -= appliedDelta; - - // If there is no delta to distribute then stop - if (distributedDelta <= 0) - break; - } - } + var column = columns[i]; + var oldWidth = GetDesiredWidth(column); + var ratio = GetDesiredWidth(column) / totalColumnWidth; + var deltaPerColumn = distributedDelta * ratio; + var appliedDelta = 0f; + var maxWidth = column.GetMaxWidth(m_LayoutWidth); + + if (GetDesiredWidth(column) < maxWidth) + appliedDelta = Math.Min(deltaPerColumn, maxWidth - GetDesiredWidth(column)); + if (appliedDelta > 0f) + ResizeColumn(column, GetDesiredWidth(column) + appliedDelta, setDesiredWidthOnly); + + totalColumnWidth -= oldWidth; + distributedDelta -= appliedDelta; + + // If there is no delta to distribute then stop + if (distributedDelta <= 0) + break; } - else + } + + return distributedDelta; + } + + float RecomputeToMinWidthProportionally(List columns, float distributedDelta, bool setDesiredWidthOnly = false) + { + if (distributedDelta > 0) + { + // Sort the fixed columns to treat the columns with the smallest min with last + columns.Sort((c1, c2) => c2.GetMinWidth(m_LayoutWidth).CompareTo(c1.GetMinWidth(m_LayoutWidth))); + + var totalColumnsWidth = 0f; + + columns.ForEach((c) => totalColumnsWidth += GetDesiredWidth(c)); + + for (var i = 0; i < columns.Count; ++i) { - // step 3 - If there is still some delta to distribute then distribute it to the fixed columns - // to their minimum limit from the right to the left - if (distributedDelta > 0) - { - // Start distributing the delta amount the nonstretchable columns - for (int i = fixedColumns.Count - 1; i >= 0; --i) - { - var fixedColumn = fixedColumns[i]; - // Ignore the stretcable columns if they reach their limit - var appliedDelta = 0f; - if (GetDesiredWidth(fixedColumn) > fixedColumn.minWidth.value) - appliedDelta = Math.Min(distributedDelta, GetDesiredWidth(fixedColumn) - fixedColumn.minWidth.value); - if (appliedDelta > 0f) - ResizeColumn(fixedColumn, GetDesiredWidth(fixedColumn) - appliedDelta, true); - distributedDelta -= appliedDelta; - - // If there is no delta to distribute then stop - if (distributedDelta <= 0) - break; - } - } + var column = columns[i]; + var oldWidth = GetDesiredWidth(column); + var ratio = GetDesiredWidth(column) / totalColumnsWidth; + var deltaPerColumn = distributedDelta * ratio; + var appliedDelta = 0f; + + if (GetDesiredWidth(column) > column.GetMinWidth(m_LayoutWidth)) + appliedDelta = Math.Min(deltaPerColumn, GetDesiredWidth(column) - column.GetMinWidth(m_LayoutWidth)); + + if (appliedDelta > 0f) + ResizeColumn(column, GetDesiredWidth(column) - appliedDelta, setDesiredWidthOnly); + + totalColumnsWidth -= oldWidth; + distributedDelta -= appliedDelta; + + // If there is no delta to distribute then stop + if (distributedDelta <= 0) + break; } + } - // Removed the extra delta that could not be distrubuted. - delta = Math.Max(0, delta - distributedDelta); + return distributedDelta; + } + + float RecomputeToDesiredWidth(List columns, float distributedDelta, bool setDesiredWidthOnly, bool distributeOverflow) + { + if (distributeOverflow) + { + for (var i = columns.Count - 1; i >= 0; --i) + { + distributedDelta = RecomputeToDesiredWidth(columns[i], distributedDelta, setDesiredWidthOnly, true); + + // If there is no delta to distribute then stop + if (distributedDelta <= 0) + break; + } } else { - if (!resizeToFit) + for (var i = 0; i < columns.Count; ++i) { - // Start distributing the delta to the fixed columns to their max or desired width from the left to the right - for (int i = 0; i < fixedColumns.Count; ++i) - { - var fixedColumn = fixedColumns[i]; - // Ignore the stretchable columns if they reach their limit - var appliedDelta = 0f; - var clampedWidth = Mathf.Clamp(fixedColumn.width.value, fixedColumn.minWidth.value, fixedColumn.maxWidth.value); + distributedDelta = RecomputeToDesiredWidth(columns[i], distributedDelta, setDesiredWidthOnly, false); - if (GetDesiredWidth(fixedColumn) < clampedWidth) - appliedDelta = Math.Min(distributedDelta, Math.Abs(clampedWidth - GetDesiredWidth(fixedColumn))); + // If there is no delta to distribute then stop + if (distributedDelta <= 0) + break; + } + } - if (appliedDelta > 0f) - ResizeColumn(fixedColumn, GetDesiredWidth(fixedColumn) + appliedDelta, true); + return distributedDelta; + } - distributedDelta -= appliedDelta; + float RecomputeToDesiredWidth(Column column, float distributedDelta, bool setDesiredWidthOnly, bool distributeOverflow) + { + var appliedDelta = 0f; + var clampedWidth = Mathf.Clamp(column.GetWidth(m_LayoutWidth), column.GetMinWidth(m_LayoutWidth), column.GetMaxWidth(m_LayoutWidth)); - // If there is no delta to distribute then stop - if (distributedDelta <= 0) - break; - } - } + if (GetDesiredWidth(column) > clampedWidth && distributeOverflow) + appliedDelta = Math.Min(distributedDelta, Math.Abs(GetDesiredWidth(column) - clampedWidth)); - // Step 2 - Start distributing the remaining delta amount to the stretchable columns proportionally to their max value - if (distributedDelta > 0) - { - // Sort the stretchable columns to treat the columns with the greatest margins to grow last - stretchableColumns.Sort((c1, c2) => c1.maxWidth.value.CompareTo(c2.maxWidth.value)); + if (GetDesiredWidth(column) < clampedWidth && !distributeOverflow) + appliedDelta = Math.Min(distributedDelta, Math.Abs(clampedWidth - GetDesiredWidth(column))); - var totalStretchableWidth = 0f; + var width = distributeOverflow ? GetDesiredWidth(column) - appliedDelta : GetDesiredWidth(column) + appliedDelta; - stretchableColumns.ForEach((c) => totalStretchableWidth += GetDesiredWidth(c)); + if (appliedDelta > 0f) + ResizeColumn(column, width, setDesiredWidthOnly); - // Start distributing the delta amount the stretchable columns - for (var i = 0; i < stretchableColumns.Count; ++i) - { - var stretchableColumn = stretchableColumns[i]; - var oldWidth = GetDesiredWidth(stretchableColumn); - var ratio = GetDesiredWidth(stretchableColumn) / totalStretchableWidth; - var deltaPerColumn = distributedDelta * ratio; - - // Ignore the stretcable columns if they reach their limit - var appliedDelta = 0f; - if (GetDesiredWidth(stretchableColumn) < stretchableColumn.maxWidth.value) - appliedDelta = Math.Min(deltaPerColumn, stretchableColumn.maxWidth.value - GetDesiredWidth(stretchableColumn)); - if (appliedDelta > 0f) - ResizeColumn(stretchableColumn, GetDesiredWidth(stretchableColumn) + appliedDelta, !resizeToFit); - - totalStretchableWidth -= oldWidth; - distributedDelta -= appliedDelta; - - // If there is no delta to distribute then stop - if (distributedDelta <= 0) - break; - } - } + distributedDelta -= appliedDelta; - if (resizeToFit) + return distributedDelta; + } + + float RecomputeToMinWidth(List columns, float distributedDelta, bool setDesiredWidthOnly = false) + { + if (distributedDelta > 0) + { + for (int i = columns.Count - 1; i >= 0; --i) { - // Sort the fixed columns to treat the columns with the greatest margins to grow last - fixedColumns.Sort((c1, c2) => c1.maxWidth.value.CompareTo(c2.maxWidth.value)); + var column = columns[i]; + var appliedDelta = 0f; - var totalFixedWidth = 0f; + if (GetDesiredWidth(column) > column.GetMinWidth(m_LayoutWidth)) + appliedDelta = Math.Min(distributedDelta, GetDesiredWidth(column) - column.GetMinWidth(m_LayoutWidth)); + if (appliedDelta > 0f) + ResizeColumn(column, GetDesiredWidth(column) - appliedDelta, setDesiredWidthOnly); - fixedColumns.ForEach((c) => totalFixedWidth += GetDesiredWidth(c)); + distributedDelta -= appliedDelta; - // Start distributing the delta amount the fixed columns - for (var i = 0; i < fixedColumns.Count; ++i) - { - var fixedColumn = fixedColumns[i]; - var oldWidth = GetDesiredWidth(fixedColumn); - var ratio = GetDesiredWidth(fixedColumn) / totalFixedWidth; - var deltaPerColumn = distributedDelta * ratio; - - // Ignore the stretcable columns if they reach their limit - var appliedDelta = 0f; - if (GetDesiredWidth(fixedColumn) < fixedColumn.maxWidth.value) - appliedDelta = Math.Min(deltaPerColumn, fixedColumn.maxWidth.value - GetDesiredWidth(fixedColumn)); - if (appliedDelta > 0f) - ResizeColumn(fixedColumn, GetDesiredWidth(fixedColumn) + appliedDelta, false); - - totalFixedWidth -= oldWidth; - distributedDelta -= appliedDelta; - - // If there is no delta to distribute then stop - if (distributedDelta <= 0) - break; - } + // If there is no delta to distribute then stop + if (distributedDelta <= 0) + break; } - else + } + + return distributedDelta; + } + + float RecomputeToMaxWidth(List columns, float distributedDelta, bool setDesiredWidthOnly = false) + { + if (distributedDelta > 0) + { + for (var i = 0; i < columns.Count; ++i) { - // step 3 - If there is still some delta to distribute then distribute it to the fixed columns - // to their maximum limit from the left to the right - if (distributedDelta > 0) - { - for (int i = 0; i < fixedColumns.Count; ++i) - { - var fixedColumn = fixedColumns[i]; - // Ignore the stretcable columns if they reach their limit - var appliedDelta = 0f; - var nextMaxWidth = fixedColumn.maxWidth.value; + var column = columns[i]; + var appliedDelta = 0f; - if (GetDesiredWidth(fixedColumn) < nextMaxWidth) - appliedDelta = Math.Min(distributedDelta, Math.Abs(nextMaxWidth - GetDesiredWidth(fixedColumn))); + if (GetDesiredWidth(column) < column.GetMaxWidth(m_LayoutWidth)) + appliedDelta = Math.Min(distributedDelta, Math.Abs(column.GetMaxWidth(m_LayoutWidth) - GetDesiredWidth(column))); - if (appliedDelta > 0f) - ResizeColumn(fixedColumn, GetDesiredWidth(fixedColumn) + appliedDelta, true); + if (appliedDelta > 0f) + ResizeColumn(column, GetDesiredWidth(column) + appliedDelta, setDesiredWidthOnly); - distributedDelta -= appliedDelta; + distributedDelta -= appliedDelta; - // If there is no delta to distribute then stop - if (distributedDelta <= 0) - break; - } - } + // If there is no delta to distribute then stop + if (distributedDelta <= 0) + break; } - - delta = delta + distributedDelta; } + return distributedDelta; } /// @@ -570,10 +626,19 @@ public void ResizeToFit(float width) { float delta = columnsWidth - Mathf.Clamp(width, minColumnsWidth, maxColumnsWidth); - var stretchableColumnsToFit = new List(m_StretchableColumns); // Copy as the original list gets cleared by Dirty() - var fixedColumnsToFit = new List(m_FixedColumns); // Copy as the original list gets cleared by Dirty() + // Copy as the original list gets cleared by Dirty() + using var i = ListPool.Get(out var stretchableColumnsToFit); + using var j = ListPool.Get(out var fixedColumnsToFit); + using var k = ListPool.Get(out var relativeWidthColumnsToFit); + + stretchableColumnsToFit.AddRange(m_StretchableColumns); + fixedColumnsToFit.AddRange(m_FixedColumns); + relativeWidthColumnsToFit.AddRange(m_RelativeWidthColumns); + + StretchResizeColumns(stretchableColumnsToFit, fixedColumnsToFit, relativeWidthColumnsToFit, ref delta, true, false); - StretchResizeColumns(stretchableColumnsToFit, fixedColumnsToFit, ref delta, true); + if (m_IsDirty) + UpdateCache(); } /// @@ -584,6 +649,8 @@ public void ResizeToFit(float width) /// Indicated whether only the desired width should be changed. void ResizeColumn(Column column, float width, bool setDesiredWidthOnly = false) { + var widthInPercent = new Length(width / layoutWidth * 100, LengthUnit.Percent); + if (m_DragResizeInPreviewMode) { m_PreviewDesiredWidths[column] = width; @@ -592,7 +659,7 @@ void ResizeColumn(Column column, float width, bool setDesiredWidthOnly = false) { if (!setDesiredWidthOnly) { - column.width = width; + column.width = column.width.unit == LengthUnit.Percent ? widthInPercent : width; } column.desiredWidth = width; } @@ -620,6 +687,7 @@ internal void BeginDragResize(Column column, float pos, bool previewMode) m_DragInitialColumnWidth = column.desiredWidth; m_DragStretchableColumns.Clear(); m_DragFixedColumns.Clear(); + m_DragRelativeColumns.Clear(); if (m_DragResizeInPreviewMode) { @@ -638,6 +706,10 @@ internal void BeginDragResize(Column column, float pos, bool previewMode) { m_DragStretchableColumns.Add(otherColumn); } + else if (otherColumn.width.unit == LengthUnit.Percent) + { + m_DragRelativeColumns.Add(otherColumn); + } else { m_DragFixedColumns.Add(otherColumn); @@ -680,28 +752,56 @@ public float GetDesiredWidth(Column c) /// The new position of the pointer. public void DragResize(Column column, float pos) { + var minWidth = column.GetMinWidth(m_LayoutWidth); + var maxWidth = column.GetMaxWidth(m_LayoutWidth); + // If it contains stretchable columns... - if (hasStretchableColumns && m_Columns.stretchMode == Columns.StretchMode.GrowAndFill) + if (m_Columns.stretchMode == Columns.StretchMode.GrowAndFill) { float delta = pos - m_DragLastPos; - float newWidth = Mathf.Clamp(GetDesiredWidth(column) + delta, column.minWidth.value, column.maxWidth.value); + + float newWidth = Mathf.Clamp(GetDesiredWidth(column) + delta, minWidth, maxWidth); // Recompute the new delta to ensure we dont exceed the limits delta = newWidth - GetDesiredWidth(column); - StretchResizeColumns(m_DragStretchableColumns, m_DragFixedColumns, ref delta, false); + // if there's excess but no stretchable columns, just resize the column without affecting the others + if (m_DragStretchableColumns.Count == 0 && delta < 0) + { + StretchResizeColumns(m_DragStretchableColumns, m_DragFixedColumns, m_DragRelativeColumns, ref delta, false, true); + + // Recompute the new width with the new delta + newWidth = Mathf.Clamp(GetDesiredWidth(column) + newWidth - GetDesiredWidth(column), minWidth, maxWidth); + } + else + { + // if there is already excess, use that first + if (delta > 0 && columnsWidth + delta < m_LayoutWidth) + { + var requiredDelta = delta < m_LayoutWidth - columnsWidth ? 0 : delta - (m_LayoutWidth - columnsWidth); + + StretchResizeColumns(m_DragStretchableColumns, m_DragFixedColumns, m_DragRelativeColumns, ref requiredDelta, false, true); - // Recompute the new width with the new delta - newWidth = Mathf.Clamp(GetDesiredWidth(column) + delta, column.minWidth.value, column.maxWidth.value); + // Recompute the new width with the new delta + newWidth = Mathf.Clamp(GetDesiredWidth(column) + delta - requiredDelta, minWidth, maxWidth); + } + else + { + StretchResizeColumns(m_DragStretchableColumns, m_DragFixedColumns, m_DragRelativeColumns, ref delta, false, true); + + // Recompute the new width with the new delta + newWidth = Mathf.Clamp(GetDesiredWidth(column) + delta, minWidth, maxWidth); + } + } ResizeColumn(column, newWidth); } else { float delta = pos - m_DragStartPos; - float newsize = Math.Max(column.minWidth.value, Math.Min(column.maxWidth.value, m_DragInitialColumnWidth + delta)); + float newSize = Math.Max(minWidth, Math.Min(maxWidth, m_DragInitialColumnWidth + delta)); - ResizeColumn(column, newsize); + ResizeColumn(column, newSize); } m_DragLastPos = pos; } @@ -729,6 +829,7 @@ internal void EndDragResize(Column column, bool cancelled) m_DragResizing = false; m_DragStretchableColumns.Clear(); m_DragFixedColumns.Clear(); + m_DragRelativeColumns.Clear(); } /// @@ -736,14 +837,33 @@ internal void EndDragResize(Column column, bool cancelled) /// void UpdateCache() { + ClearCache(); foreach (var column in m_Columns.visibleList) { - if (column.stretchable) + if (column.stretchable && columns.stretchMode == Columns.StretchMode.GrowAndFill) m_StretchableColumns.Add(column); - else + else if (column.width.unit == LengthUnit.Pixel) m_FixedColumns.Add(column); - m_MaxColumnsWidth += column.maxWidth.value; - m_MinColumnsWidth += column.minWidth.value; + // Columns with percentage widths are added to relativeWidthColumns regardless of their stretchability. + if (column.width.unit == LengthUnit.Percent) + m_RelativeWidthColumns.Add(column); + + if (column.width.unit == LengthUnit.Pixel && (column.minWidth.unit == LengthUnit.Percent || column.maxWidth.unit == LengthUnit.Percent)) + m_MixedWidthColumns.Add(column); + + m_MaxColumnsWidth += column.GetMaxWidth(m_LayoutWidth); + m_MinColumnsWidth += column.GetMinWidth(m_LayoutWidth); + } + } + + void UpdateMinAndMaxColumnsWidth() + { + m_MaxColumnsWidth = 0; + m_MinColumnsWidth = 0; + foreach (var column in m_Columns.visibleList) + { + m_MaxColumnsWidth += column.GetMaxWidth(m_LayoutWidth); + m_MinColumnsWidth += column.GetMinWidth(m_LayoutWidth); } } @@ -753,6 +873,7 @@ void UpdateCache() void ClearCache() { m_StretchableColumns.Clear(); + m_RelativeWidthColumns.Clear(); m_FixedColumns.Clear(); m_MaxColumnsWidth = 0; m_MinColumnsWidth = 0; diff --git a/Modules/UIElements/Core/Controls/MultiColumn/MultiColumnCollectionHeader.cs b/Modules/UIElements/Core/Controls/MultiColumn/MultiColumnCollectionHeader.cs index a15561bb0e..f0c143dd13 100644 --- a/Modules/UIElements/Core/Controls/MultiColumn/MultiColumnCollectionHeader.cs +++ b/Modules/UIElements/Core/Controls/MultiColumn/MultiColumnCollectionHeader.cs @@ -31,7 +31,7 @@ struct ColumnState public int index; public string name; public float actualWidth; - public float width; + public Length width; public bool visible; } @@ -57,7 +57,7 @@ internal void Save(MultiColumnCollectionHeader header) foreach (var column in header.columns.displayList) { - var columnState = new ColumnState() { index = column.index, name = column.name, actualWidth = column.desiredWidth, width = column.width.value, visible = column.visible }; + var columnState = new ColumnState() { index = column.index, name = column.name, actualWidth = column.desiredWidth, width = column.width, visible = column.visible }; m_OrderedColumnStates.Add(columnState); } diff --git a/Modules/UIElements/Core/Controls/ScrollView.cs b/Modules/UIElements/Core/Controls/ScrollView.cs index 56e3ab22ff..6c573ffa7a 100644 --- a/Modules/UIElements/Core/Controls/ScrollView.cs +++ b/Modules/UIElements/Core/Controls/ScrollView.cs @@ -1103,12 +1103,14 @@ private void OnAttachToPanel(AttachToPanelEvent evt) if (evt.destinationPanel.contextType == ContextType.Player) { m_ContentAndVerticalScrollContainer.RegisterCallback(OnPointerMove); - contentContainer.RegisterCallback(OnPointerDown, TrickleDown.TrickleDown); contentContainer.RegisterCallback(OnPointerCancel); contentContainer.RegisterCallback(OnPointerUp, TrickleDown.TrickleDown); + contentContainer.RegisterCallback(OnPointerCapture); contentContainer.RegisterCallback(OnPointerCaptureOut); + + evt.destinationPanel.visualTree.RegisterCallback(OnRootPointerUp, TrickleDown.TrickleDown); } } @@ -1127,13 +1129,15 @@ private void OnDetachFromPanel(DetachFromPanelEvent evt) if (evt.originPanel.contextType == ContextType.Player) { - m_ContentAndVerticalScrollContainer.UnregisterCallback(OnPointerDown, TrickleDown.TrickleDown); m_ContentAndVerticalScrollContainer.UnregisterCallback(OnPointerMove); - m_ContentAndVerticalScrollContainer.UnregisterCallback(OnPointerCancel); - m_ContentAndVerticalScrollContainer.UnregisterCallback(OnPointerUp, TrickleDown.TrickleDown); + contentContainer.UnregisterCallback(OnPointerDown, TrickleDown.TrickleDown); + contentContainer.UnregisterCallback(OnPointerCancel); + contentContainer.UnregisterCallback(OnPointerUp, TrickleDown.TrickleDown); contentContainer.UnregisterCallback(OnPointerCapture); contentContainer.UnregisterCallback(OnPointerCaptureOut); + + evt.originPanel.visualTree.UnregisterCallback(OnRootPointerUp, TrickleDown.TrickleDown); } } @@ -1144,7 +1148,7 @@ void OnPointerCapture(PointerCaptureEvent evt) if (m_CapturedTarget == null) return; - m_ScrollingPointerId = evt.pointerId; + m_TouchPointerMoveAllowed = true; m_CapturedTarget.RegisterCallback(m_CapturedTargetPointerMoveCallback); m_CapturedTarget.RegisterCallback(m_CapturedTargetPointerUpCallback); } @@ -1220,7 +1224,6 @@ void ResetLayoutPass() m_FirstLayoutPass = -1; } - private int m_ScrollingPointerId = PointerId.invalidPointerId; private const float k_VelocityLerpTimeFactor = 10; internal const float ScrollThresholdSquared = 100; private Vector2 m_StartPosition; @@ -1231,6 +1234,7 @@ void ResetLayoutPass() private Vector2 m_HighBounds; private float m_LastVelocityLerpTime; private bool m_StartedMoving; + private bool m_TouchPointerMoveAllowed; private bool m_TouchStoppedVelocity; VisualElement m_CapturedTarget; EventCallback m_CapturedTargetPointerMoveCallback; @@ -1489,16 +1493,16 @@ void OnPointerDown(PointerDownEvent evt) if (evt.pointerType == PointerType.mouse || !evt.isPrimary) return; - if (m_ScrollingPointerId != PointerId.invalidPointerId) + if (evt.pointerId != PointerId.invalidPointerId) { - ReleaseScrolling(m_ScrollingPointerId, evt.target); + ReleaseScrolling(evt.pointerId, evt.target); } m_PostPointerUpAnimation?.Pause(); var touchStopsVelocityOnly = Mathf.Abs(m_Velocity.x) > 10 || Mathf.Abs(m_Velocity.y) > 10; - m_ScrollingPointerId = evt.pointerId; + m_TouchPointerMoveAllowed = true; m_StartedMoving = false; InitTouchScrolling(evt.position); @@ -1513,7 +1517,7 @@ void OnPointerDown(PointerDownEvent evt) void OnPointerMove(PointerMoveEvent evt) { - if (evt.pointerType == PointerType.mouse || !evt.isPrimary || evt.pointerId != m_ScrollingPointerId) + if (evt.pointerType == PointerType.mouse || !evt.isPrimary || !m_TouchPointerMoveAllowed) return; if (evt.isHandledByDraggable) @@ -1656,7 +1660,7 @@ bool ApplyTouchScrolling(Vector2 newScrollOffset) m_LastVelocityLerpTime = Time.unscaledTime; - var deltaTime = (m_ElasticAnimationIntervalMs/1000f); + var deltaTime = k_TouchScrollInertiaBaseTimeInterval; var newVelocity = (newScrollOffset - scrollOffset) / deltaTime; m_Velocity = Vector2.Lerp(m_Velocity, newVelocity, deltaTime * k_VelocityLerpTimeFactor); } @@ -1668,13 +1672,9 @@ bool ApplyTouchScrolling(Vector2 newScrollOffset) bool ReleaseScrolling(int pointerId, IEventHandler target) { - if (pointerId != m_ScrollingPointerId) - return false; - - m_ScrollingPointerId = PointerId.invalidPointerId; - m_TouchStoppedVelocity = false; m_StartedMoving = false; + m_TouchPointerMoveAllowed = false; if (target != contentContainer || !contentContainer.HasPointerCapture(pointerId)) return false; @@ -1689,7 +1689,7 @@ bool ReleaseScrolling(int pointerId, IEventHandler target) contentContainer.ReleasePointer(pointerId); return true; } - + void ExecuteElasticSpringAnimation() { ComputeInitialSpringBackVelocity(); @@ -1805,6 +1805,11 @@ void OnRootCustomStyleResolved(CustomStyleResolvedEvent evt) ReadSingleLineHeight(); } + void OnRootPointerUp(PointerUpEvent evt) + { + m_TouchPointerMoveAllowed = false; + } + void ReadSingleLineHeight() { if (m_AttachedRootVisualContainer?.computedStyle.customProperties != null && diff --git a/Modules/UIElements/Core/Controls/ToggleButtonGroup/ToggleButtonGroup.cs b/Modules/UIElements/Core/Controls/ToggleButtonGroup/ToggleButtonGroup.cs index 055054a2a3..9164bfa60d 100644 --- a/Modules/UIElements/Core/Controls/ToggleButtonGroup/ToggleButtonGroup.cs +++ b/Modules/UIElements/Core/Controls/ToggleButtonGroup/ToggleButtonGroup.cs @@ -241,6 +241,12 @@ public ToggleButtonGroup(string label, ToggleButtonGroupState toggleButtonGroupS public override VisualElement contentContainer => m_ButtonGroupContainer ?? this; + internal override void OnViewDataReady() + { + base.OnViewDataReady(); + UpdateButtonStates(value); + } + protected override void UpdateMixedValueContent() { if (showMixedValue) diff --git a/Modules/UIElements/Core/EventDispatcher.cs b/Modules/UIElements/Core/EventDispatcher.cs index f424681543..4fd15b2317 100644 --- a/Modules/UIElements/Core/EventDispatcher.cs +++ b/Modules/UIElements/Core/EventDispatcher.cs @@ -5,8 +5,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using JetBrains.Annotations; -using UnityEngine.UIElements.Experimental; +using UnityEngine.Bindings; +using NotNullAttribute = JetBrains.Annotations.NotNullAttribute; namespace UnityEngine.UIElements { @@ -24,7 +24,7 @@ namespace UnityEngine.UIElements // // For example 2: A keydown with Textfocus in TextField C // result ==> Phase TrickleDown [ root, A], Phase Target [C], Phase BubbleUp [ A, root ] - + [VisibleToOtherModules("UnityEditor.UIBuilderModule")] enum DispatchMode { Default = Queued, diff --git a/Modules/UIElements/Core/FocusController.cs b/Modules/UIElements/Core/FocusController.cs index da8d368a76..8e4e94b639 100644 --- a/Modules/UIElements/Core/FocusController.cs +++ b/Modules/UIElements/Core/FocusController.cs @@ -140,6 +140,7 @@ public virtual void Blur() focusController?.Blur(this); } + [VisibleToOtherModules("UnityEditor.UIBuilderModule")] internal void BlurImmediately() { focusController?.Blur(this, dispatchMode: DispatchMode.Immediate); diff --git a/Modules/UIElements/Core/Native/Renderer/UIPainter2D.bindings.cs b/Modules/UIElements/Core/Native/Renderer/UIPainter2D.bindings.cs index c29c5dcb08..0bed46ac7e 100644 --- a/Modules/UIElements/Core/Native/Renderer/UIPainter2D.bindings.cs +++ b/Modules/UIElements/Core/Native/Renderer/UIPainter2D.bindings.cs @@ -14,7 +14,7 @@ namespace UnityEngine.UIElements [NativeHeader("Modules/UIElements/Core/Native/Renderer/UIPainter2D.bindings.h")] internal static class UIPainter2D { - public static extern IntPtr Create(); + public static extern IntPtr Create(bool computeBBox = false); public static extern void Destroy(IntPtr handle); public static extern void Reset(IntPtr handle); @@ -50,6 +50,8 @@ internal static class UIPainter2D public static extern void QuadraticCurveTo(IntPtr handle, Vector2 p1, Vector2 p2); public static extern void ClosePath(IntPtr handle); + public static extern Rect GetBBox(IntPtr handle); + public static extern MeshWriteDataInterface Stroke(IntPtr handle); public static extern MeshWriteDataInterface Fill(IntPtr handle, FillRule fillRule); @@ -58,8 +60,6 @@ internal static class UIPainter2D public static extern void ClearSnapshots(IntPtr handle); [ThreadSafe] public static extern MeshWriteDataInterface ExecuteSnapshotFromJob(IntPtr painterHandle, int i); - - public static extern Rect ComputeBBoxFromArcs(IntPtr meshes, int meshCount); } /// diff --git a/Modules/UIElements/Core/Renderer/UIRPainter2D.cs b/Modules/UIElements/Core/Renderer/UIRPainter2D.cs index 344789b083..3e089e41fd 100644 --- a/Modules/UIElements/Core/Renderer/UIRPainter2D.cs +++ b/Modules/UIElements/Core/Renderer/UIRPainter2D.cs @@ -129,7 +129,9 @@ internal Painter2D(MeshGenerationContext ctx) /// public Painter2D() { - m_Handle = new SafeHandleAccess(UIPainter2D.Create()); + // Create the Painter2D with computeBBox flag set to true, + // This allows other APIs (such as SaveToVectorImage) to know the size of the content. + m_Handle = new SafeHandleAccess(UIPainter2D.Create(true)); m_DetachedAllocator = new DetachedAllocator(); isPainterActive = true; m_OnMeshGenerationDelegate = OnMeshGeneration; @@ -161,6 +163,7 @@ public void Clear() } m_DetachedAllocator.Clear(); + Reset(); } @@ -280,7 +283,7 @@ private bool ValidateState() } /// - /// Begins a new path and empties the list of recorded sub-paths and resets the pen position to (0,0). + /// Begins a new path and empties the list of recorded sub-paths. /// public void BeginPath() { @@ -562,14 +565,7 @@ public unsafe bool SaveToVectorImage(VectorImage vectorImage) // of the additional buffer around the shapes used for anti-aliasing. The // ComputeBoundingBoxFromArcs() method peeks into the arc data for more precise measurements. // This is a native method for performance reasons. - Rect bbox = Rect.zero; - NativeArray nativeMeshes; - using (nativeMeshes = new NativeArray(meshes.Count, Allocator.Temp, NativeArrayOptions.UninitializedMemory)) - { - for (int i = 0; i < meshes.Count; ++i) - nativeMeshes[i] = MeshWriteDataInterface.FromMeshWriteData(meshes[i]); - bbox = UIPainter2D.ComputeBBoxFromArcs(new IntPtr(nativeMeshes.GetUnsafePtr()), nativeMeshes.Length); - } + Rect bbox = UIPainter2D.GetBBox(m_Handle); // Allocate + copy var allVerts = new VectorImageVertex[vertCount]; diff --git a/Modules/UIElements/Core/StyleSheets/StyleVariable.cs b/Modules/UIElements/Core/StyleSheets/StyleVariable.cs index 4eab85bec4..64a60ba50a 100644 --- a/Modules/UIElements/Core/StyleSheets/StyleVariable.cs +++ b/Modules/UIElements/Core/StyleSheets/StyleVariable.cs @@ -48,20 +48,38 @@ internal class StyleVariableContext public void Add(StyleVariable sv) { - // Avoid duplicates. Otherwise the variable context explodes as hierarchy gets deeper. var hash = sv.GetHashCode(); + int ComputeOrderSensitiveHash(int index) + { + unchecked + { + // This needs to be reversible and order-sensitive. We use (index + 1) to avoid multiplying by 0. + return (index + 1) * hash; + } + } + + // Avoid duplicates. Otherwise the variable context explodes as hierarchy gets deeper. var hashIndex = m_SortedHash.BinarySearch(hash); if (hashIndex >= 0) - return; - - m_SortedHash.Insert(~hashIndex, hash); + { + // UUM-32738: if the variable is already there, we need to move it to the end. + var index = m_Variables.IndexOf(sv); - m_Variables.Add(sv); + // The new variable is already at the end. Nothing to update. + if (index == m_Variables.Count - 1) + return; - unchecked + // Otherwise, remove it and let it be re-added. + m_VariableHash ^= ComputeOrderSensitiveHash(index); + m_Variables.RemoveAt(index); + } + else { - m_VariableHash = m_Variables.Count == 0 ? sv.GetHashCode() : (m_VariableHash * 397) ^ sv.GetHashCode(); + m_SortedHash.Insert(~hashIndex, hash); } + + m_VariableHash ^= ComputeOrderSensitiveHash(m_Variables.Count); + m_Variables.Add(sv); } public void AddInitialRange(StyleVariableContext other) diff --git a/Modules/UIElements/Core/VisualElementDataBinding.cs b/Modules/UIElements/Core/VisualElementDataBinding.cs index 137bf60645..9ec51e8b9b 100644 --- a/Modules/UIElements/Core/VisualElementDataBinding.cs +++ b/Modules/UIElements/Core/VisualElementDataBinding.cs @@ -244,7 +244,7 @@ List bindings /// This information is only used by the UI Builder as a hint to provide some completion to the data source path field when the effective data source cannot be specified at design time. /// /// - internal Type dataSourceType { get; set; } + public Type dataSourceType { get; set; } internal string dataSourceTypeString { diff --git a/Modules/UIElementsEditor/Bindings/SerializedDefaultEnumBinding.cs b/Modules/UIElementsEditor/Bindings/SerializedDefaultEnumBinding.cs index feb4c9ba47..5f7bc6a663 100644 --- a/Modules/UIElementsEditor/Bindings/SerializedDefaultEnumBinding.cs +++ b/Modules/UIElementsEditor/Bindings/SerializedDefaultEnumBinding.cs @@ -122,23 +122,11 @@ private void SetBinding(PopupField c, SerializedObjectBindingContext con } - var originalValue = this.lastFieldValueIndex = c.index; + this.lastFieldValueIndex = c.index; BindingsStyleHelpers.RegisterRightClickMenu(c, property); this.field = c; - - if (originalValue == c.index) //the value hasn't changed, but we want the binding to send an event no matter what - { - if (c is VisualElement handler) - { - using (ChangeEvent evt = ChangeEvent.GetPooled(c.value, c.value)) - { - evt.elementTarget = handler; - handler.SendEvent(evt); - } - } - } } protected override void SyncPropertyToField(PopupField c, SerializedProperty p) diff --git a/Modules/UIElementsEditor/Bindings/SerializedIsExpandedBinding.cs b/Modules/UIElementsEditor/Bindings/SerializedIsExpandedBinding.cs index 8482cdde93..f1b196078a 100644 --- a/Modules/UIElementsEditor/Bindings/SerializedIsExpandedBinding.cs +++ b/Modules/UIElementsEditor/Bindings/SerializedIsExpandedBinding.cs @@ -35,18 +35,9 @@ protected void SetBinding(Foldout foldout, SerializedObjectBindingContext contex propCompareValues = SerializedPropertyHelper.ValueEquals; SetContext(context, property); - var originalValue = this.lastFieldValue = foldout.value; + this.lastFieldValue = foldout.value; BindingsStyleHelpers.RegisterRightClickMenu(foldout, property); field = foldout; - - if (propCompareValues(originalValue, property, propGetValue)) //the value hasn't changed, but we want the binding to send an event no matter what - { - using (ChangeEvent evt = ChangeEvent.GetPooled(originalValue, originalValue)) - { - evt.elementTarget = foldout; - foldout.SendEvent(evt); - } - } } public override void OnRelease() diff --git a/Modules/UIElementsEditor/Bindings/SerializedManagedEnumBinding.cs b/Modules/UIElementsEditor/Bindings/SerializedManagedEnumBinding.cs index 2f5529aec9..b058a01d58 100644 --- a/Modules/UIElementsEditor/Bindings/SerializedManagedEnumBinding.cs +++ b/Modules/UIElementsEditor/Bindings/SerializedManagedEnumBinding.cs @@ -193,7 +193,7 @@ public override void OnRelease() BindingsStyleHelpers.UnregisterRightClickMenu(saveField); field = null; - saveField.value = null; + saveField.SetValueWithoutNotify(null); ResetContext(); diff --git a/Modules/UIElementsEditor/Bindings/SerializedObjectBinding.cs b/Modules/UIElementsEditor/Bindings/SerializedObjectBinding.cs index 190923b75e..f386675d35 100644 --- a/Modules/UIElementsEditor/Bindings/SerializedObjectBinding.cs +++ b/Modules/UIElementsEditor/Bindings/SerializedObjectBinding.cs @@ -37,7 +37,7 @@ private void SetBinding(INotifyValueChanged c, SetContext(context, property); - var originalValue = this.lastFieldValue = c.value; + this.lastFieldValue = c.value; if (c is BaseField bf) { @@ -49,18 +49,6 @@ private void SetBinding(INotifyValueChanged c, } this.field = c; - - if (compareValues(originalValue, property, getValue)) //the value hasn't changed, but we want the binding to send an event no matter what - { - if (this.field is VisualElement handler) - { - using (ChangeEvent evt = ChangeEvent.GetPooled(originalValue, originalValue)) - { - evt.elementTarget = handler; - handler.SendEvent(evt); - } - } - } } public override void OnRelease() diff --git a/Modules/UIElementsEditor/Bindings/SerializedObjectBindingBase.cs b/Modules/UIElementsEditor/Bindings/SerializedObjectBindingBase.cs index 80b82f7d27..2f718a09df 100644 --- a/Modules/UIElementsEditor/Bindings/SerializedObjectBindingBase.cs +++ b/Modules/UIElementsEditor/Bindings/SerializedObjectBindingBase.cs @@ -176,8 +176,8 @@ public virtual void ResetUpdate() protected SerializedObjectBindingBase() { - m_OnFieldAttachedToPanel = OnFieldAttached; - m_OnFieldDetachedFromPanel = OnFieldDetached; + m_OnFieldAttachedToPanel = OnAttachToPanel; + m_OnFieldDetachedFromPanel = OnDetachFromPanel; } protected IBindable boundElement @@ -249,13 +249,23 @@ private set } } - private void OnFieldAttached(AttachToPanelEvent evt) + private void OnAttachToPanel(AttachToPanelEvent evt) + { + OnFieldAttached(); + } + + private void OnDetachFromPanel(DetachFromPanelEvent evt) + { + OnFieldDetached(); + } + + protected virtual void OnFieldAttached() { isFieldAttached = true; ResetCachedValues(); } - private void OnFieldDetached(DetachFromPanelEvent evt) + private void OnFieldDetached() { isFieldAttached = false; } @@ -284,11 +294,10 @@ protected void UpdateFieldIsAttached() if (isFieldAttached != attached) { - isFieldAttached = attached; if (attached) - { - ResetCachedValues(); - } + OnFieldAttached(); + else + OnFieldDetached(); } } else @@ -296,12 +305,11 @@ protected void UpdateFieldIsAttached() //we're not dealing with VisualElement if (m_Field != null && !isFieldAttached) { - isFieldAttached = true; - ResetCachedValues(); + OnFieldAttached(); } else { - isFieldAttached = false; + OnFieldDetached(); } } } diff --git a/Modules/UIElementsEditor/Bindings/SerializedObjectBindingToBaseField.cs b/Modules/UIElementsEditor/Bindings/SerializedObjectBindingToBaseField.cs index ead1eb3729..07e3d8605c 100644 --- a/Modules/UIElementsEditor/Bindings/SerializedObjectBindingToBaseField.cs +++ b/Modules/UIElementsEditor/Bindings/SerializedObjectBindingToBaseField.cs @@ -3,6 +3,7 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using System.Collections.Generic; using UnityEngine.UIElements; namespace UnityEditor.UIElements.Bindings; @@ -122,6 +123,21 @@ public override void OnPropertyValueChanged(SerializedProperty currentPropertyIt Unbind(); } + protected override void OnFieldAttached() + { + var previousValue = field.value; + + base.OnFieldAttached(); + + if (EqualityComparer.Default.Equals(previousValue, field.value) + && field is VisualElement handler) + { + using var evt = ChangeEvent.GetPooled(field.value, field.value); + evt.elementTarget = handler; + handler.SendEvent(evt); + } + } + public override void SyncValueWithoutNotify(object value) { if (value is TValue castValue) diff --git a/Modules/UIElementsEditor/Bindings/SerializedObjectStringConversionBinding.cs b/Modules/UIElementsEditor/Bindings/SerializedObjectStringConversionBinding.cs index ed116c0120..b3d3a7602b 100644 --- a/Modules/UIElementsEditor/Bindings/SerializedObjectStringConversionBinding.cs +++ b/Modules/UIElementsEditor/Bindings/SerializedObjectStringConversionBinding.cs @@ -45,24 +45,10 @@ private void SetBinding(INotifyValueChanged c, BindingsStyleHelpers.RegisterRightClickMenu(bf, property); } - var previousFieldValue = field.value; - // In this subclass implementation the lastFieldValue is in fact the propertyValue assigned to the field. // this is made to compare TValues instead of strings UpdateLastFieldValue(); AssignValueToField(lastFieldValue); - - if (previousFieldValue == field.value) //the value hasn't changed, but we want the binding to send an event no matter what - { - if (this.field is VisualElement handler) - { - using (ChangeEvent evt = ChangeEvent.GetPooled(previousFieldValue, previousFieldValue)) - { - evt.elementTarget = handler; - handler.SendEvent(evt); - } - } - } } protected override void UpdateLastFieldValue() diff --git a/Modules/UIElementsEditor/UIElementsEditorInitialization.cs b/Modules/UIElementsEditor/UIElementsEditorInitialization.cs index cebe018e05..32e73f2099 100644 --- a/Modules/UIElementsEditor/UIElementsEditorInitialization.cs +++ b/Modules/UIElementsEditor/UIElementsEditorInitialization.cs @@ -15,7 +15,7 @@ static class UIElementsEditorInitialization public static void InitializeUIElementsEditorManaged() { var jobHandle = PropertiesEditorInitialization.GetInitializationJobHandle(); - var handle = new InitializeUIElementsJob().Schedule(jobHandle); + new InitializeUIElementsJob().Schedule(jobHandle); JobHandle.ScheduleBatchedJobs(); } diff --git a/Modules/UIElementsEditor/UIElementsViewImporter.cs b/Modules/UIElementsEditor/UIElementsViewImporter.cs index 935672f690..81682279d0 100644 --- a/Modules/UIElementsEditor/UIElementsViewImporter.cs +++ b/Modules/UIElementsEditor/UIElementsViewImporter.cs @@ -24,7 +24,7 @@ namespace UnityEditor.UIElements { // Make sure UXML is imported after assets than can be addressed in USS [HelpURL("UIE-VisualTree-landing")] - [ScriptedImporter(version: 17, ext: "uxml", importQueueOffset: 1102)] + [ScriptedImporter(version: 18, ext: "uxml", importQueueOffset: 1102)] [ExcludeFromPreset] internal class UIElementsViewImporter : ScriptedImporter { @@ -858,6 +858,8 @@ void LoadAttributeOverridesNode(TemplateAsset templateAsset, XElement attributeO vta.FindElementsByNameInTemplate(templateAsset, elementNameAttr.Value, resolvedVisualElementAssetsInTemplate); } + UxmlSerializedDataDescription uxmlSerializedDataDescription = null; + foreach (var attribute in attributeOverridesElt.Attributes()) { var attributeName = attribute.Name.LocalName; @@ -872,18 +874,21 @@ void LoadAttributeOverridesNode(TemplateAsset templateAsset, XElement attributeO if (resolvedVisualElementAssetsInTemplate.Count > 0) { - if (s_UxmlAssetAttributeCache.GetAssetAttributeType(resolvedVisualElementAssetsInTemplate[0].fullTypeName, attributeName, out var assetType)) + Type assetType = null; + uxmlSerializedDataDescription ??= UxmlSerializedDataRegistry.GetDescription(resolvedVisualElementAssetsInTemplate[0].fullTypeName); + + // Extract the asset type from the UxmlSerializedData + if (uxmlSerializedDataDescription?.FindAttributeWithUxmlName(attributeName) is UxmlSerializedAttributeDescription attributeDescription && + attributeDescription.isUnityObject) + assetType = attributeDescription.type; + + if (assetType != null || s_UxmlAssetAttributeCache.GetAssetAttributeType(resolvedVisualElementAssetsInTemplate[0].fullTypeName, attributeName, out assetType)) { var (response, asset) = ValidateAndLoadResource(attributeOverridesElt, vta, attribute.Value, true); if (response.result == URIValidationResult.OK && !vta.AssetEntryExists(attribute.Value, assetType)) { - if (asset) - { - // Force loading using correct attribute type to support cases like Texture2D vs Sprite, - asset = AssetDatabase.LoadAssetAtPath(response.resolvedProjectRelativePath, assetType); - } - + asset = ExtractSubAssetFromParent(asset, assetType, response); vta.RegisterAssetEntry(attribute.Value, assetType, asset); } } @@ -1053,6 +1058,30 @@ bool EnsureValidUxmlObjectChild(XElement elt, UxmlAsset uxmlAsset, VisualTreeAss return (default, null); } + static Object ExtractSubAssetFromParent(Object parent, Type assetType, URIHelpers.URIValidationResponse response) + { + if (parent && !assetType.IsAssignableFrom(parent.GetType())) + { + // Force loading using correct attribute type to support cases like Texture2D vs Sprite, + if (string.IsNullOrEmpty(response.resolvedSubAssetPath)) + { + // Force loading using correct attribute type to support cases like Texture2D vs Sprite, + return AssetDatabase.LoadAssetAtPath(response.resolvedProjectRelativePath, assetType); + } + + // Force load the sub assets and find the asset by name and type + var subAssets = AssetDatabase.LoadAllAssetsAtPath(response.resolvedProjectRelativePath); + foreach (var subAsset in subAssets) + { + if (subAsset.name == response.resolvedSubAssetPath && assetType.IsAssignableFrom(subAsset.GetType())) + { + return subAsset; + } + } + } + return parent; + } + void ParseAttributes(XElement elt, UxmlAsset res, VisualTreeAsset vta, UxmlAsset parent) { // Since the import process depends on the existence of the type and any UXMLAssetAttributeDescription members @@ -1087,28 +1116,7 @@ void ParseAttributes(XElement elt, UxmlAsset res, VisualTreeAsset vta, UxmlAsset if (response.result == URIValidationResult.OK && !vta.AssetEntryExists(xattr.Value, assetType)) { - if (asset && !assetType.IsAssignableFrom(asset.GetType())) - { - if (string.IsNullOrEmpty(response.resolvedSubAssetPath)) - { - // Force loading using correct attribute type to support cases like Texture2D vs Sprite, - asset = AssetDatabase.LoadAssetAtPath(response.resolvedProjectRelativePath, assetType); - } - else - { - // Force load the sub assets and find the asset by name and type - var subAssets = AssetDatabase.LoadAllAssetsAtPath(response.resolvedProjectRelativePath); - foreach (var subAsset in subAssets) - { - if (subAsset.name == response.resolvedSubAssetPath && assetType.IsAssignableFrom(subAsset.GetType())) - { - asset = subAsset; - break; - } - } - } - } - + asset = ExtractSubAssetFromParent(asset, assetType, response); vta.RegisterAssetEntry(xattr.Value, assetType, asset); } } diff --git a/Modules/UIElementsSamplesEditor/UIElementsSamples.cs b/Modules/UIElementsSamplesEditor/UIElementsSamples.cs index 084987750c..4650da38ea 100644 --- a/Modules/UIElementsSamplesEditor/UIElementsSamples.cs +++ b/Modules/UIElementsSamplesEditor/UIElementsSamples.cs @@ -91,49 +91,49 @@ public void CreateGUI() new TreeViewItemData(nextId++, new SampleTreeItem("ToggleButtonGroup", ToggleButtonGroupSnippet.Create)), new TreeViewItemData(nextId++, new SampleTreeItem("RadioButton", RadioButtonSnippet.Create)), new TreeViewItemData(nextId++, new SampleTreeItem("Label", LabelSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Text Field", TextFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("TextField", TextFieldSnippet.Create)), new TreeViewItemData(nextId++, new SampleTreeItem("HelpBox", HelpBoxSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Object Field", ObjectFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("List View", ListViewSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Tree View", TreeViewSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Multi-Column List View", MultiColumnListViewSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Multi-Column Tree View", MultiColumnTreeViewSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Tab View", TabViewSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("ObjectField", ObjectFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("ListView", ListViewSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("TreeView", TreeViewSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("MultiColumnListView", MultiColumnListViewSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("MultiColumnTreeView", MultiColumnTreeViewSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("TabView", TabViewSnippet.Create)), new TreeViewItemData(nextId++, new SampleTreeItem("Numeric Fields", MakeNumericFieldsPanel), new List>() { - new TreeViewItemData(nextId++, new SampleTreeItem("Integer", IntegerFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Float", FloatFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Long", LongFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("IntegerField", IntegerFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("FloatField", FloatFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("LongField", LongFieldSnippet.Create)), new TreeViewItemData(nextId++, new SampleTreeItem("MinMaxSlider", MinMaxSliderSnippet.Create)), new TreeViewItemData(nextId++, new SampleTreeItem("Slider", SliderSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Vector2", Vector2FieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Vector3", Vector3FieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Vector4", Vector4FieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Rect", RectFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Bounds", BoundsFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("UnsignedInteger", UnsignedIntegerFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("UnsignedLong", UnsignedLongFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("Vector2Field", Vector2FieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("Vector3Field", Vector3FieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("Vector4Field", Vector4FieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("RectField", RectFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("BoundsField", BoundsFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("UnsignedIntegerField", UnsignedIntegerFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("UnsignedLongField", UnsignedLongFieldSnippet.Create)), new TreeViewItemData(nextId++, new SampleTreeItem("SliderInt", SliderIntSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Vector2Int", Vector2IntFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Vector3Int", Vector3IntFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("RectInt", RectIntFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("BoundsInt", BoundsIntFieldSnippet.Create)) + new TreeViewItemData(nextId++, new SampleTreeItem("Vector2IntField", Vector2IntFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("Vector3IntField", Vector3IntFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("RectIntField", RectIntFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("BoundsIntField", BoundsIntFieldSnippet.Create)) }), new TreeViewItemData(nextId++, new SampleTreeItem("Value Fields", MakeValueFieldsPanel), new List>() { - new TreeViewItemData(nextId++, new SampleTreeItem("Color", ColorFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Curve", CurveFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Gradient", GradientFieldSnippet.Create)) + new TreeViewItemData(nextId++, new SampleTreeItem("ColorField", ColorFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("CurveField", CurveFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("GradientField", GradientFieldSnippet.Create)) }), new TreeViewItemData(nextId++, new SampleTreeItem("Choice Fields", MakeChoiceFieldsPanel), new List>() { - new TreeViewItemData(nextId++, new SampleTreeItem("Enum", EnumFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("EnumFlags", EnumFlagsFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Popup", PopupFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Tag", TagFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Mask", MaskFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("Layer", LayerFieldSnippet.Create)), - new TreeViewItemData(nextId++, new SampleTreeItem("LayerMask", LayerMaskFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("EnumField", EnumFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("EnumFlagsField", EnumFlagsFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("PopupField", PopupFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("TagField", TagFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("MaskField", MaskFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("LayerField", LayerFieldSnippet.Create)), + new TreeViewItemData(nextId++, new SampleTreeItem("LayerMaskField", LayerMaskFieldSnippet.Create)), new TreeViewItemData(nextId++, new SampleTreeItem("DropdownField", DropdownFieldSnippet.Create)), new TreeViewItemData(nextId++, new SampleTreeItem("RadioButtonGroup", RadioButtonGroupSnippet.Create)), }), diff --git a/Modules/UnityWebRequestTexture/Public/DownloadHandlerTexture.bindings.cs b/Modules/UnityWebRequestTexture/Public/DownloadHandlerTexture.bindings.cs index 257c683190..a81f472679 100644 --- a/Modules/UnityWebRequestTexture/Public/DownloadHandlerTexture.bindings.cs +++ b/Modules/UnityWebRequestTexture/Public/DownloadHandlerTexture.bindings.cs @@ -10,29 +10,82 @@ namespace UnityEngine.Networking { + [Flags] + public enum DownloadedTextureFlags : uint + { + None = 0, + Readable = 1 << 0, + MipmapChain = 1 << 1, + LinearColorSpace = 1 << 2, + } + + [StructLayout(LayoutKind.Sequential)] + public struct DownloadedTextureParams + { + public DownloadedTextureFlags flags; + public int mipmapCount; + + public static DownloadedTextureParams Default => new DownloadedTextureParams() + { + flags = DownloadedTextureFlags.Readable | DownloadedTextureFlags.MipmapChain, + mipmapCount = -1, + }; + + public bool readable + { + get => flags.HasFlag(DownloadedTextureFlags.Readable); + set => SetFlags(DownloadedTextureFlags.Readable, value); + } + + public bool mipmapChain + { + get => flags.HasFlag(DownloadedTextureFlags.MipmapChain); + set => SetFlags(DownloadedTextureFlags.MipmapChain, value); + } + + public bool linearColorSpace + { + get => flags.HasFlag(DownloadedTextureFlags.LinearColorSpace); + set => SetFlags(DownloadedTextureFlags.LinearColorSpace, value); + } + + void SetFlags(DownloadedTextureFlags flgs, bool add) + { + if (add) + flags |= flgs; + else + flags &= ~flgs; + } + } + [StructLayout(LayoutKind.Sequential)] [NativeHeader("Modules/UnityWebRequestTexture/Public/DownloadHandlerTexture.h")] public sealed class DownloadHandlerTexture : DownloadHandler { private NativeArray m_NativeData; - private bool mNonReadable; - private static extern IntPtr Create([Unmarshalled] DownloadHandlerTexture obj, bool readable); + private static extern IntPtr Create([Unmarshalled] DownloadHandlerTexture obj, DownloadedTextureParams parameters); - private void InternalCreateTexture(bool readable) + private void InternalCreateTexture(DownloadedTextureParams parameters) { - m_Ptr = Create(this, readable); + m_Ptr = Create(this, parameters); } public DownloadHandlerTexture() + : this(true) { - InternalCreateTexture(true); } public DownloadHandlerTexture(bool readable) { - InternalCreateTexture(readable); - mNonReadable = !readable; + var parameters = DownloadedTextureParams.Default; + parameters.readable = readable; + InternalCreateTexture(parameters); + } + + public DownloadHandlerTexture(DownloadedTextureParams parameters) + { + InternalCreateTexture(parameters); } protected override NativeArray GetNativeData() diff --git a/Modules/UnityWebRequestTexture/UnityWebRequestTexture.cs b/Modules/UnityWebRequestTexture/UnityWebRequestTexture.cs index 8a9a730010..f385c2dd73 100644 --- a/Modules/UnityWebRequestTexture/UnityWebRequestTexture.cs +++ b/Modules/UnityWebRequestTexture/UnityWebRequestTexture.cs @@ -28,5 +28,15 @@ public static UnityWebRequest GetTexture(Uri uri, bool nonReadable) return new UnityWebRequest(uri, UnityWebRequest.kHttpVerbGET, new DownloadHandlerTexture(!nonReadable), null); } + public static UnityWebRequest GetTexture(string uri, DownloadedTextureParams parameters) + { + return new UnityWebRequest(uri, UnityWebRequest.kHttpVerbGET, new DownloadHandlerTexture(parameters), null); + } + + public static UnityWebRequest GetTexture(Uri uri, DownloadedTextureParams parameters) + { + return new UnityWebRequest(uri, UnityWebRequest.kHttpVerbGET, new DownloadHandlerTexture(parameters), null); + } + } } diff --git a/Projects/CSharp/UnityEditor.csproj b/Projects/CSharp/UnityEditor.csproj index cca75a3565..7c2c4b240b 100644 --- a/Projects/CSharp/UnityEditor.csproj +++ b/Projects/CSharp/UnityEditor.csproj @@ -2871,6 +2871,9 @@ Editor\Mono\PlayerSettingsSwitch.bindings.cs + + Editor\Mono\PlayerSettingsSwitch.deprecated.bindings.cs + Editor\Mono\PlayerSettingsTVOS.bindings.cs @@ -3879,6 +3882,9 @@ Editor\Mono\UIElements\StyleSheets\URIHelpers.cs + + Editor\Mono\UIElements\UIBuildAnalyticsEvent.cs + Editor\Mono\UIElements\UIElementsEditorUtility.cs @@ -4911,6 +4917,9 @@ Modules\Licensing\UI\Data\Events\Base\NotificationWithDetails.cs + + Modules\Licensing\UI\Data\Events\BorrowFeatureStatusNotification.cs + Modules\Licensing\UI\Data\Events\LicenseExpiredNotification.cs @@ -5385,9 +5394,6 @@ Modules\PackageManagerUI\Editor\Services\Packages\Actions\UpdateAction.cs - - Modules\PackageManagerUI\Editor\Services\Packages\PackageAndVersionIdPair.cs - Modules\PackageManagerUI\Editor\Services\Packages\PackageDatabase.cs diff --git a/Projects/CSharp/UnityEngine.csproj b/Projects/CSharp/UnityEngine.csproj index 4dae442502..6ea482049b 100644 --- a/Projects/CSharp/UnityEngine.csproj +++ b/Projects/CSharp/UnityEngine.csproj @@ -7,7 +7,7 @@ false true false - $(DefineConstants);ALLOW_IMPLICIT_INTERNAL_VISIBILITY;COMBINED_ASSEMBLIES;DEBUGGER_LISTENS_FIXED_PORT;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;ENABLE_ALTERNATIVE_LISTEN_PORT;ENABLE_AR;ENABLE_AUDIO;ENABLE_AUDIO_MANAGER_BASED_SCHEDULING;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_CLOUD_LICENSE;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_DUMMYTLS=1;ENABLE_EDITOR_GAME_SERVICES;ENABLE_EDITOR_HUB_LICENSE;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_HOLOLENS_MODULE_API;ENABLE_LZMA;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_UNITYTLS;ENABLE_MARSHALLING_TESTS;ENABLE_MBEDTLS=1;ENABLE_MICROPHONE;ENABLE_MOVIES;ENABLE_MULTIPLE_DISPLAYS;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_NETWORK;ENABLE_PHYSICS;ENABLE_SCRIPTING_GC_WBARRIERS;ENABLE_TEXTURE_STREAMING;ENABLE_UNITYEVENTS;ENABLE_UNITYWEBREQUEST;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_VERSION_CONTROL_INTEGRATION;ENABLE_VIDEO;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WEBSOCKET_CLIENT;ENABLE_WWW;GRAPHINE_BUILD_STATIC=1;GRAPHINE_BUILD_UNITY=1;HAVE_FREETYPE;ICU_NO_USER_DATA_OVERRIDE;INCLUDE_DYNAMIC_GI;MBEDTLS_PSK_MAX_LEN=64;MBEDTLS_USER_CONFIG=1;NV_CLOTH_IMPORT=;PLATFORM_SUPPORTS_MONO;PLAYERCONNECTION_LISTENS_FIXED_PORT;RENDER_SOFTWARE_CURSOR;TEXTCORE_1_0_OR_NEWER;TRACE;UCONFIG_NO_COLLATION;UCONFIG_NO_CONVERSION;UCONFIG_NO_FILE_IO;UCONFIG_NO_FORMATTING;UCONFIG_NO_IDNA;UCONFIG_NO_REGULAR_EXPRESSIONS;UCONFIG_NO_SERVICE;UCONFIG_NO_TRANSLITERATION;UMBRA_IS_TARGET=0;UMBRA_OS=UMBRA_LINUX;UNITY_ANDROID_API;UNITY_ASSEMBLIES_API;UNITY_ASSERTIONS;UNITY_CURL_BUILT_IN;UNITY_EDITOR;UNITY_EDITOR_API;UNITY_IPHONE_API;UNITY_METRO_API;UNITY_PS4_API;UNITY_PS5_API;UNITY_STANDALONE_LINUX_API;UNITY_STANDALONE_OSX_API;UNITY_STANDALONE_WIN_API;UNITY_TLS_INTERFACE_UNITY=1;UNITY_TVOS_API;UNITY_WEBGL_API;USE_PROPERTIES_MODULE;U_COMMON_IMPLEMENTATION;U_ENABLE_DYLOAD=0;U_STATIC_IMPLEMENTATION=1;VPX_MULTITHREAD;VPX_X86;VPX_X86_64;_HAS_EXCEPTIONS=0 + $(DefineConstants);ALLOW_IMPLICIT_INTERNAL_VISIBILITY;COMBINED_ASSEMBLIES;DEBUGGER_LISTENS_FIXED_PORT;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;ENABLE_ALTERNATIVE_LISTEN_PORT;ENABLE_AR;ENABLE_AUDIO;ENABLE_AUDIO_MANAGER_BASED_SCHEDULING;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_CLOUD_LICENSE;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_DUMMYTLS=1;ENABLE_EDITOR_GAME_SERVICES;ENABLE_EDITOR_HUB_LICENSE;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_HOLOLENS_MODULE_API;ENABLE_LZMA;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_UNITYTLS;ENABLE_MARSHALLING_TESTS;ENABLE_MBEDTLS=1;ENABLE_MICROPHONE;ENABLE_MOVIES;ENABLE_MULTIPLE_DISPLAYS;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_NETWORK;ENABLE_PHYSICS;ENABLE_SCRIPTING_GC_WBARRIERS;ENABLE_TEXTURE_STREAMING;ENABLE_UNITYEVENTS;ENABLE_UNITYWEBREQUEST;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_VERSION_CONTROL_INTEGRATION;ENABLE_VIDEO;ENABLE_VR;ENABLE_WEBCAM;ENABLE_WEBSOCKET_CLIENT;ENABLE_WWW;GRAPHINE_BUILD_STATIC=1;GRAPHINE_BUILD_UNITY=1;HAVE_FREETYPE;ICU_NO_USER_DATA_OVERRIDE;INCLUDE_DYNAMIC_GI;MBEDTLS_PSK_MAX_LEN=64;MBEDTLS_USER_CONFIG=1;NV_CLOTH_IMPORT=;PLATFORM_SUPPORTS_MONO;PLAYERCONNECTION_LISTENS_FIXED_PORT;RENDER_SOFTWARE_CURSOR;TEXTCORE_1_0_OR_NEWER;TRACE;UCONFIG_NO_COLLATION;UCONFIG_NO_CONVERSION;UCONFIG_NO_FILE_IO;UCONFIG_NO_FORMATTING;UCONFIG_NO_IDNA;UCONFIG_NO_REGULAR_EXPRESSIONS;UCONFIG_NO_SERVICE;UCONFIG_NO_TRANSLITERATION;UMBRA_IS_TARGET=0;UMBRA_OS=UMBRA_LINUX;UNITY_ANDROID_API;UNITY_ASSEMBLIES_API;UNITY_ASSERTIONS;UNITY_CURL_BUILT_IN;UNITY_EDITOR;UNITY_EDITOR_API;UNITY_IPHONE_API;UNITY_METRO_API;UNITY_MODULE_NAME=AI;UNITY_MODULE_NAME=AR;UNITY_MODULE_NAME=Accessibility;UNITY_MODULE_NAME=AndroidJNI;UNITY_MODULE_NAME=Animation;UNITY_MODULE_NAME=AssetBundle;UNITY_MODULE_NAME=Audio;UNITY_MODULE_NAME=Cloth;UNITY_MODULE_NAME=ClusterInput;UNITY_MODULE_NAME=ClusterRenderer;UNITY_MODULE_NAME=ContentLoad;UNITY_MODULE_NAME=CrashReporting;UNITY_MODULE_NAME=DSPGraph;UNITY_MODULE_NAME=Director;UNITY_MODULE_NAME=GI;UNITY_MODULE_NAME=GameCenter;UNITY_MODULE_NAME=Grid;UNITY_MODULE_NAME=HierarchyCore;UNITY_MODULE_NAME=HotReload;UNITY_MODULE_NAME=IMGUI;UNITY_MODULE_NAME=ImageConversion;UNITY_MODULE_NAME=Input;UNITY_MODULE_NAME=InputForUI;UNITY_MODULE_NAME=InputLegacy;UNITY_MODULE_NAME=JSONSerialize;UNITY_MODULE_NAME=Localization;UNITY_MODULE_NAME=Marshalling;UNITY_MODULE_NAME=Multiplayer;UNITY_MODULE_NAME=ParticleSystem;UNITY_MODULE_NAME=PerformanceReporting;UNITY_MODULE_NAME=Physics;UNITY_MODULE_NAME=Physics2D;UNITY_MODULE_NAME=Properties;UNITY_MODULE_NAME=RuntimeInitializeOnLoadManagerInitializer;UNITY_MODULE_NAME=ScreenCapture;UNITY_MODULE_NAME=SharedInternals;UNITY_MODULE_NAME=SpriteMask;UNITY_MODULE_NAME=SpriteShape;UNITY_MODULE_NAME=Streaming;UNITY_MODULE_NAME=Substance;UNITY_MODULE_NAME=Subsystems;UNITY_MODULE_NAME=TLS;UNITY_MODULE_NAME=Terrain;UNITY_MODULE_NAME=TerrainPhysics;UNITY_MODULE_NAME=TextCoreFontEngine;UNITY_MODULE_NAME=TextCoreTextEngine;UNITY_MODULE_NAME=TextRendering;UNITY_MODULE_NAME=Tilemap;UNITY_MODULE_NAME=UI;UNITY_MODULE_NAME=UIElements;UNITY_MODULE_NAME=Umbra;UNITY_MODULE_NAME=UnityAnalytics;UNITY_MODULE_NAME=UnityAnalyticsCommon;UNITY_MODULE_NAME=UnityConnect;UNITY_MODULE_NAME=UnityCurl;UNITY_MODULE_NAME=UnityTestProtocol;UNITY_MODULE_NAME=UnityWebRequest;UNITY_MODULE_NAME=UnityWebRequestAssetBundle;UNITY_MODULE_NAME=UnityWebRequestAudio;UNITY_MODULE_NAME=UnityWebRequestTexture;UNITY_MODULE_NAME=UnityWebRequestWWW;UNITY_MODULE_NAME=VFX;UNITY_MODULE_NAME=VR;UNITY_MODULE_NAME=Vehicles;UNITY_MODULE_NAME=Video;UNITY_MODULE_NAME=VirtualTexturing;UNITY_MODULE_NAME=Wind;UNITY_MODULE_NAME=XR;UNITY_PS4_API;UNITY_PS5_API;UNITY_STANDALONE_LINUX_API;UNITY_STANDALONE_OSX_API;UNITY_STANDALONE_WIN_API;UNITY_TLS_INTERFACE_UNITY=1;UNITY_TVOS_API;UNITY_WEBGL_API;USE_PROPERTIES_MODULE;U_COMMON_IMPLEMENTATION;U_ENABLE_DYLOAD=0;U_STATIC_IMPLEMENTATION=1;VPX_MULTITHREAD;VPX_X86;VPX_X86_64;_HAS_EXCEPTIONS=0 latest 1701;0626 @@ -1128,6 +1128,9 @@ Modules\Properties\Runtime\Reflection\Internal\ReflectedPropertyBagProvider.cs + + Modules\Properties\Runtime\Reflection\Internal\ReflectionUtilities.cs + Modules\Properties\Runtime\Utility\TypeConversion.cs diff --git a/README.md b/README.md index 2fd1237d67..d550559a82 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Unity 6000.0.0b11 C# reference source code +## Unity 6000.0.0b12 C# reference source code The C# part of the Unity engine and editor source code. May be used for reference purposes only. From 72b239b07bdd3893428c7e6a37ee0a09d0844040 Mon Sep 17 00:00:00 2001 From: Unity Technologies Date: Wed, 27 Mar 2024 01:28:00 +0000 Subject: [PATCH 03/89] Unity 6000.0.0b13 C# reference source code --- .../SpeedTree/SpeedTree9Importer.cs | 143 ++++--- .../SpeedTree9ImporterModelEditor.cs | 13 +- .../SpeedTree/SpeedTreeImporterCommon.cs | 42 -- Editor/Mono/GUI/Toolbars/EditorToolbar.cs | 9 - .../IHVImageFormatImporterInspector.cs | 4 +- .../TextureImporterInspector.cs | 138 ++++--- Editor/Mono/Inspector/CubemapInspector.cs | 6 +- .../PlayerSettingsEditor.cs | 4 +- .../Mono/Inspector/QualitySettingsEditor.cs | 16 +- Editor/Mono/Inspector/RenderTextureEditor.cs | 4 +- .../Inspector/StreamingControllerInspector.cs | 2 +- Editor/Mono/ObjectSelector.cs | 27 ++ Editor/Mono/Overlays/Overlay.cs | 47 +++ Editor/Mono/PlayerSettingsAndroid.bindings.cs | 2 +- Editor/Mono/SceneView/SceneView.cs | 3 +- Editor/Mono/Search/ObjectSelectorSearch.cs | 25 ++ Editor/Mono/Search/SearchService.cs | 2 +- Editor/Mono/UIElements/DefaultMainToolbar.cs | 7 +- Modules/AndroidJNI/AndroidGame.bindings.cs | 10 + .../BuildProfileEditor/BuildProfileEditor.cs | 2 +- .../BuildProfileEditor/BuildProfileWindow.cs | 370 +++++++----------- .../Elements/BuildProfileListEditableLabel.cs | 8 + .../Elements/BuildProfileSceneList.cs | 8 +- .../Elements/PlatformListView.cs | 249 ++++++++++++ .../Handlers/BuildProfileContextMenu.cs | 18 +- .../Handlers/BuildProfileDataSource.cs | 5 +- .../Handlers/BuildProfileWindowSelection.cs | 113 ++---- Modules/IMGUI/GUIStyle.bindings.cs | 1 + Modules/IMGUI/IMGUITextHandle.cs | 6 +- .../Editor/Providers/AdbProvider.cs | 2 + .../DefaultAdvancedObjectSelector.cs | 6 +- .../Editor/SearchEngines/SearchEngines.cs | 67 +++- Modules/QuickSearch/Editor/UI/Dispatcher.cs | 2 +- Modules/QuickSearch/Editor/UITK/GridView.cs | 127 ++++-- .../QuickSearch/Editor/UITK/SearchGridView.cs | 3 +- .../Editor/UITK/SearchTableView.cs | 27 +- .../QuickSearch/Editor/UITK/SearchWindow.cs | 14 +- .../Managed/TextAssets/FontAsset.cs | 5 + .../FontAsset/FontAssetAtlasPopulation.cs | 14 + .../TextGenerator/TextGeneratorInternal.cs | 233 ++++++----- Modules/UIElements/Core/AlignmentUtils.cs | 54 ++- .../UIElements/Core/Controls/BaseSlider.cs | 8 + .../Core/GameObjects/RuntimePanel.cs | 3 +- .../UIElements/Core/GameObjects/UIDocument.cs | 12 +- Modules/UIElements/Core/Panel.cs | 12 + Modules/UIElements/Core/VisualElement.cs | 7 +- .../Common/ProjectBindManager.cs | 19 +- Projects/CSharp/UnityEditor.csproj | 3 + README.md | 2 +- ...ayTracingAccelerationStructure.bindings.cs | 4 + Runtime/Export/ObjectPool/ObjectPools.cs | 1 + .../RenderPipeline/RenderPipelineAsset.cs | 2 + Runtime/Export/Scripting/WaitUntil.cs | 29 +- Runtime/Export/Scripting/WaitWhile.cs | 29 +- 54 files changed, 1256 insertions(+), 713 deletions(-) create mode 100644 Modules/BuildProfileEditor/Elements/PlatformListView.cs diff --git a/Editor/Mono/AssetPipeline/SpeedTree/SpeedTree9Importer.cs b/Editor/Mono/AssetPipeline/SpeedTree/SpeedTree9Importer.cs index 1820d3540b..7c3971e773 100644 --- a/Editor/Mono/AssetPipeline/SpeedTree/SpeedTree9Importer.cs +++ b/Editor/Mono/AssetPipeline/SpeedTree/SpeedTree9Importer.cs @@ -30,23 +30,16 @@ public class SpeedTree9Importer : ScriptedImporter internal static class ImporterSettings { internal const string kGameObjectName = "SpeedTree"; - internal const string kHDRPShaderName = "HDRP/Nature/SpeedTree9_HDRP"; - internal const string kURPShaderName = "Universal Render Pipeline/Nature/SpeedTree9_URP"; internal const string kLegacyShaderName = "Nature/SpeedTree9"; internal const string kWindAssetName = "SpeedTreeWind"; - internal const string kSRPDependencyName = "srp/default-pipeline"; + internal const string kSRPDependencyName = "SpeedTree9Importer_DefaultShader"; internal const string kMaterialSettingsDependencyname = "SpeedTree9Importer_MaterialSettings"; - - // In some very specific scenarios, the Shader cannot be found using "Shader.Find" (e.g project upgrade). - // Adding an extra-security is necessary to avoid that, by manually forcing the load of the Shader using - // "AssetDatabase.LoadAssetAtPath". It only happens for SRPs during project upgrades. - internal const string kHDRPShaderPath = "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Nature/SpeedTree9_HDRP.shadergraph"; - internal const string kURPShaderPath = "Packages/com.unity.render-pipelines.universal/Shaders/Nature/SpeedTree9_URP.shadergraph"; + internal const string kIconName = "UnityEditor/SpeedTree9Importer Icon"; } private static class Styles { - internal static readonly Texture2D kIcon = EditorGUIUtility.FindTexture("UnityEditor/SpeedTree9Importer Icon"); + internal static readonly Texture2D kIcon = EditorGUIUtility.FindTexture(ImporterSettings.kIconName); } private struct STMeshGeometry @@ -118,12 +111,15 @@ public STMeshGeometry(int vertexCount, int UVCount, int indexLod) [SerializeField] internal SpeedTreeImporterOutputData m_OutputImporterData; + private static ulong s_DefaultShaderHash; + private static readonly TimeSpan k_CheckDependencyFrequency = TimeSpan.FromSeconds(5); + private static DateTime s_LastCheck; + // Cache main objects, created during import process. private AssetImportContext m_Context; private SpeedTree9Reader m_Tree; private Shader m_Shader; private SpeedTreeWindAsset m_WindAsset; - private STRenderPipeline m_RenderPipeline; // Values cached at the begining of the import process. private bool m_HasFacingData; @@ -157,11 +153,9 @@ public override void OnImportAsset(AssetImportContext ctx) CacheTreeImporterValues(ctx.assetPath); - m_RenderPipeline = GetCurrentRenderPipelineType(); - ctx.DependsOnCustomDependency(ImporterSettings.kSRPDependencyName); - if (!TryGetShaderForCurrentRenderPipeline(m_RenderPipeline, out m_Shader)) + if (!TryGetShaderForCurrentRenderPipeline(out m_Shader)) { ctx.LogImportError("SpeedTree9 shader is invalid, cannot create Materials for this SpeedTree asset."); return; @@ -273,6 +267,61 @@ internal void RegenerateMaterials() } } + [InitializeOnLoadMethod] + static void InitializeEditorCallback() + { + EditorApplication.update += DirtyCustomDependencies; + s_DefaultShaderHash = ComputeDefaultShaderHash(); + AssetDatabase.RegisterCustomDependency(ImporterSettings.kSRPDependencyName, new Hash128(s_DefaultShaderHash, 0)); + } + + + static ulong CombineHash(ulong h1, ulong h2) + { + unchecked + { + return h1 ^ h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2); // Similar to c++ boost::hash_combine + } + } + + static ulong ComputeDefaultShaderHash() + { + ulong newDefaultShaderHash = 0UL; + if (GraphicsSettings.currentRenderPipeline == null || GraphicsSettings.currentRenderPipeline.defaultSpeedTree9Shader == null) + { + newDefaultShaderHash = 0; + } + else + { + if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(GraphicsSettings.currentRenderPipeline.defaultSpeedTree9Shader, out var guid, + out long fileId)) + { + newDefaultShaderHash = CombineHash((ulong)guid.GetHashCode(), (ulong)fileId); + } + } + + return newDefaultShaderHash; + } + + static void DirtyCustomDependencies() + { + DateTime now = DateTime.Now; + if (Application.isPlaying || now - s_LastCheck < k_CheckDependencyFrequency) + { + return; + } + + s_LastCheck = now; + + ulong newDefaultShaderHash = ComputeDefaultShaderHash(); + if (s_DefaultShaderHash != newDefaultShaderHash) + { + s_DefaultShaderHash = newDefaultShaderHash; + AssetDatabase.RegisterCustomDependency(ImporterSettings.kSRPDependencyName, new Hash128(s_DefaultShaderHash, 0)); + AssetDatabase.Refresh(); + } + } + #region Mesh Geometry & Renderers private Mesh CreateMeshAndGeometry(Lod lod, int lodIndex) { @@ -717,9 +766,7 @@ private void RegenerateAndPopulateExternalMaterials(string assetPath) CacheTreeImporterValues(assetPath); - m_RenderPipeline = GetCurrentRenderPipelineType(); - - if (!TryGetShaderForCurrentRenderPipeline(m_RenderPipeline, out m_Shader)) + if (!TryGetShaderForCurrentRenderPipeline(out m_Shader)) { Debug.LogError("SpeedTree9 shader is invalid, cannot create Materials for this SpeedTree asset."); return; @@ -999,22 +1046,24 @@ private void SetMaterialOtherProperties(STMaterial stMaterial, Material mat) } mat.SetFloat(MaterialProperties.LeafFacingKwToggleID, m_HasFacingData ? 1.0f : 0.0f); - if (m_RenderPipeline == STRenderPipeline.HDRP) - { + if (mat.HasFloat(MaterialProperties.DoubleSidedToggleID)) mat.SetFloat(MaterialProperties.DoubleSidedToggleID, stMaterial.TwoSided ? 1.0f : 0.0f); + + if (mat.HasFloat(MaterialProperties.DoubleSidedNormalModeID)) mat.SetFloat(MaterialProperties.DoubleSidedNormalModeID, stMaterial.FlipNormalsOnBackside ? 0.0f : 2.0f); + if (mat.HasVector(MaterialProperties.DiffusionProfileAssetID)) mat.SetVector(MaterialProperties.DiffusionProfileAssetID, m_MaterialSettings.diffusionProfileAssetID); + + if (mat.HasFloat(MaterialProperties.DiffusionProfileID)) mat.SetFloat(MaterialProperties.DiffusionProfileID, m_MaterialSettings.diffusionProfileID); - } - else if (m_RenderPipeline == STRenderPipeline.URP) - { + + if (mat.HasFloat(MaterialProperties.BackfaceNormalModeID)) mat.SetFloat(MaterialProperties.BackfaceNormalModeID, stMaterial.FlipNormalsOnBackside ? 0.0f : 2.0f); - } - else // legacy rendering pipeline - { + + if (mat.HasFloat(MaterialProperties.TwoSidedID)) mat.SetFloat(MaterialProperties.TwoSidedID, stMaterial.TwoSided ? 0.0f : 2.0f); // matches cull mode. 0: no cull - } + mat.enableInstancing = true; mat.doubleSidedGI = stMaterial.TwoSided; } @@ -1108,20 +1157,6 @@ internal string GetMaterialFolderPath() return FileUtil.DeleteLastPathNameComponent(assetPath) + "/"; } - internal string GetShaderNameFromPipeline(STRenderPipeline renderPipeline) - { - switch (renderPipeline) - { - case STRenderPipeline.HDRP: - return ImporterSettings.kHDRPShaderName; - case STRenderPipeline.URP: - return ImporterSettings.kURPShaderName; - case STRenderPipeline.Legacy: - default: - return ImporterSettings.kLegacyShaderName; - } - } - internal void SetMaterialsVersionToCurrent() { m_MaterialVersion = SPEEDTREE_9_MATERIAL_VERSION; @@ -1353,27 +1388,17 @@ private bool TreeHasFacingData() return false; } - private bool TryGetShaderForCurrentRenderPipeline(STRenderPipeline renderPipeline, out Shader shader) + internal static bool TryGetShaderForCurrentRenderPipeline(out Shader shader) { - switch (renderPipeline) + shader = null; + if (GraphicsSettings.currentRenderPipeline != null) { - case STRenderPipeline.URP: - shader = Shader.Find(ImporterSettings.kURPShaderName); - if (shader == null) - { - shader = m_Context.GetReferenceToAssetMainObject(ImporterSettings.kURPShaderPath) as Shader; - } - break; - case STRenderPipeline.HDRP: - shader = Shader.Find(ImporterSettings.kHDRPShaderName); - if (shader == null) - { - shader = m_Context.GetReferenceToAssetMainObject(ImporterSettings.kHDRPShaderPath) as Shader; - } - break; - default: - shader = Shader.Find(ImporterSettings.kLegacyShaderName); - break; + shader = GraphicsSettings.currentRenderPipeline.defaultSpeedTree9Shader; + } + + if (shader == null) + { + shader = Shader.Find(ImporterSettings.kLegacyShaderName); } return shader != null; diff --git a/Editor/Mono/AssetPipeline/SpeedTree/SpeedTree9ImporterModelEditor.cs b/Editor/Mono/AssetPipeline/SpeedTree/SpeedTree9ImporterModelEditor.cs index dc59855ba7..49eb05fb0e 100644 --- a/Editor/Mono/AssetPipeline/SpeedTree/SpeedTree9ImporterModelEditor.cs +++ b/Editor/Mono/AssetPipeline/SpeedTree/SpeedTree9ImporterModelEditor.cs @@ -280,14 +280,19 @@ internal bool DoMaterialsHaveDifferentShader() importerArray.Add(importer); } - var renderPipeline = SpeedTreeImporterCommon.GetCurrentRenderPipelineType(); + string defaultShaderName = String.Empty; + if (TryGetShaderForCurrentRenderPipeline(out var shader)) + { + defaultShaderName = shader.name; + } + else + { + Debug.LogWarning("SpeedTree9 shader is invalid, cannot create Materials for this SpeedTree asset."); + } // In tests assetTargets can become null for (int i = 0; i < Math.Min(importerArray.Count, prefabs?.Length ?? 0); ++i) { - var im = importerArray[i]; - var defaultShaderName = im.GetShaderNameFromPipeline(renderPipeline); - foreach (var mr in prefabs[i].transform.GetComponentsInChildren()) { foreach (var mat in mr.sharedMaterials) diff --git a/Editor/Mono/AssetPipeline/SpeedTree/SpeedTreeImporterCommon.cs b/Editor/Mono/AssetPipeline/SpeedTree/SpeedTreeImporterCommon.cs index 72373ac7b9..eb101547b0 100644 --- a/Editor/Mono/AssetPipeline/SpeedTree/SpeedTreeImporterCommon.cs +++ b/Editor/Mono/AssetPipeline/SpeedTree/SpeedTreeImporterCommon.cs @@ -20,13 +20,6 @@ class SpeedTreeConstants static class SpeedTreeImporterCommon { - internal enum STRenderPipeline - { - Legacy, - URP, - HDRP - } - internal enum STUnitConversion { kLeaveAsIs = 0, @@ -84,41 +77,6 @@ internal static class MaterialKeywords internal static readonly string VBSetupID = "VB_SETUP"; internal static readonly string BillboardID = "_BILLBOARD"; } - - internal static STRenderPipeline GetCurrentRenderPipelineType() - { - var renderPipelineAsset = GraphicsSettings.renderPipelineAsset; - if (renderPipelineAsset != null) - { - if (renderPipelineAsset.name.Contains("UniversalRP") || - renderPipelineAsset.name.Contains("URP")) - { - return STRenderPipeline.URP; - } - else if (renderPipelineAsset.name.Contains("HDRenderPipeline") || - renderPipelineAsset.name.Contains("HDRP")) - { - return STRenderPipeline.HDRP; - } - } - - renderPipelineAsset = QualitySettings.renderPipeline; - if (renderPipelineAsset != null) - { - if (renderPipelineAsset.name.Contains("UniversalRP") || - renderPipelineAsset.name.Contains("URP")) - { - return STRenderPipeline.URP; - } - else if (renderPipelineAsset.name.Contains("HDRenderPipeline") || - renderPipelineAsset.name.Contains("HDRP")) - { - return STRenderPipeline.HDRP; - } - } - - return STRenderPipeline.Legacy; - } } static class SpeedTreeImporterCommonEditor diff --git a/Editor/Mono/GUI/Toolbars/EditorToolbar.cs b/Editor/Mono/GUI/Toolbars/EditorToolbar.cs index f2889e04b5..e48eb369cd 100644 --- a/Editor/Mono/GUI/Toolbars/EditorToolbar.cs +++ b/Editor/Mono/GUI/Toolbars/EditorToolbar.cs @@ -18,11 +18,6 @@ sealed class EditorToolbar public const string elementLabelClassName = elementClassName + "__label"; public const string elementTextIconClassName = elementClassName + "__text-icon"; - static readonly string[] k_DeprecatedElements = new[] - { - "SceneView/Snap Increment" - }; - string[] m_ToolbarElements; readonly EditorWindow m_Context; VisualElement m_RootVisualElement; @@ -81,10 +76,6 @@ static bool TryCreateElement(string id, EditorWindow ctx, out VisualElement ve) return true; } - if(Array.IndexOf(k_DeprecatedElements, id) < 0) - Debug.LogError($"Failed to load EditorToolbar ID '{id}' for window '{ctx}'. " - + "No element with that ID and target toolbar was registered using the EditorToolbarElement attribute."); - return false; } } diff --git a/Editor/Mono/ImportSettings/IHVImageFormatImporterInspector.cs b/Editor/Mono/ImportSettings/IHVImageFormatImporterInspector.cs index 6735c17c46..3a9165ebf9 100644 --- a/Editor/Mono/ImportSettings/IHVImageFormatImporterInspector.cs +++ b/Editor/Mono/ImportSettings/IHVImageFormatImporterInspector.cs @@ -31,8 +31,8 @@ internal class Styles public static readonly GUIContent sRGBTexture = EditorGUIUtility.TrTextContent("sRGB (Color Texture)", "Texture content is stored in gamma space. Non-HDR color textures should enable this flag (except if used for IMGUI)."); public static readonly GUIContent wrapMode = EditorGUIUtility.TrTextContent("Wrap Mode"); public static readonly GUIContent filterMode = EditorGUIUtility.TrTextContent("Filter Mode"); - public static readonly GUIContent streamingMipmaps = EditorGUIUtility.TrTextContent("Streaming Mipmaps", "Only load larger mipmaps as needed to render the current game cameras."); - public static readonly GUIContent streamingMipmapsPriority = EditorGUIUtility.TrTextContent("Mip Map Priority", "Mip map streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127."); + public static readonly GUIContent streamingMipmaps = EditorGUIUtility.TrTextContent("Stream Mipmap Levels", "Only load larger mipmap levels as needed to render the current game cameras."); + public static readonly GUIContent streamingMipmapsPriority = EditorGUIUtility.TrTextContent("Priority", "Mipmap streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127."); public static readonly int[] filterModeValues = { (int)FilterMode.Point, (int)FilterMode.Bilinear, (int)FilterMode.Trilinear }; diff --git a/Editor/Mono/ImportSettings/TextureImporterInspector.cs b/Editor/Mono/ImportSettings/TextureImporterInspector.cs index b05f1579dc..2c7045c294 100644 --- a/Editor/Mono/ImportSettings/TextureImporterInspector.cs +++ b/Editor/Mono/ImportSettings/TextureImporterInspector.cs @@ -100,6 +100,7 @@ public override void OnDisable() base.OnDisable(); EditorPrefs.SetBool("TextureImporterShowAdvanced", m_ShowAdvanced); + EditorPrefs.SetBool("TextureImporterShowMipmapGenerationSettings", m_ShowMipmapGenerationSettings); } // Don't show the imported texture as a separate editor @@ -274,10 +275,10 @@ internal class Styles public readonly GUIContent mipmapFadeEndMip = EditorGUIUtility.TrTextContent("Fade End Mip"); public readonly GUIContent mipmapFadeOut = EditorGUIUtility.TrTextContent("Fade Range"); public readonly GUIContent readWrite = EditorGUIUtility.TrTextContent("Read/Write", "Enable to be able to access the raw pixel data from code."); - public readonly GUIContent useMipmapLimits = EditorGUIUtility.TrTextContent("Use Mipmap Limits", "Disable this if the number of mips to upload should not be limited by the quality settings. (effectively: always upload at full resolution, regardless of the global mipmap limit or mipmap limit groups)"); - public readonly GUIContent mipmapLimitGroupName = EditorGUIUtility.TrTextContent("Mipmap Limit Group", "Select a Mipmap Limit Group for this texture. If you do not add this texture to a Mipmap Limit Group, or Unity cannot find the group name you provide, Unity limits the number of mips it uploads to the maximum defined by the Global Texture Mipmap Limit (see Quality Settings). If Unity can find the Mipmap Limit Group you specify, it respects that group's limit."); + public readonly GUIContent useMipmapLimits = EditorGUIUtility.TrTextContent("Mipmap Limit", "Disable this if the number of mipmap levels to upload should not be limited by the quality settings. (effectively: always upload at full resolution, regardless of the global mipmap limit or mipmap limit groups)"); + public readonly GUIContent mipmapLimitGroupName = EditorGUIUtility.TrTextContent("Mipmap Limit Group", "Select a Mipmap Limit Group for this texture. If you do not add this texture to a Mipmap Limit Group, or Unity cannot find the group name you provide, Unity limits the number of mipmap levels it uploads to the maximum defined by the Global Texture Mipmap Limit (see Quality Settings). If Unity can find the Mipmap Limit Group you specify, it respects that group's limit."); public readonly GUIContent mipmapLimitGroupWarning = EditorGUIUtility.TrTextContent("This texture takes the default mipmap limit settings because Unity cannot find the mipmap limit group you have designated. Consult your project's Quality Settings for a list of mipmap limit groups."); - public readonly GUIContent streamingMipmaps = EditorGUIUtility.TrTextContent("Mip Streaming", "Only load larger mipmaps as needed to render the current game cameras. Requires texture streaming to be enabled in quality settings."); + public readonly GUIContent streamingMipmaps = EditorGUIUtility.TrTextContent("Stream Mipmap Levels", "Only load larger mipmap levels as needed to render the current game cameras. Requires Texture Mipmap Streamer to be enabled in quality settings."); public readonly GUIContent streamingMipmapsPriority = EditorGUIUtility.TrTextContent("Priority", "Mipmap streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127."); public readonly GUIContent vtOnly = EditorGUIUtility.TrTextContent("Virtual Texture Only", "Texture is optimized for use as a virtual texture and can only be used as a virtual texture."); @@ -307,7 +308,8 @@ internal class Styles (int)TextureImporterSingleChannelComponent.Red, }; - public readonly GUIContent generateMipMaps = EditorGUIUtility.TrTextContent("Generate Mipmaps", "Create progressively smaller versions of the texture, for reduced texture shimmering and better GPU performance when the texture is viewed at a distance."); + public readonly GUIContent generateMipMaps = EditorGUIUtility.TrTextContent("Generate Mipmap", "Create progressively smaller versions of the texture, for reduced texture shimmering and better GPU performance when the texture is viewed at a distance."); + public readonly GUIContent showMipmapGenerationSettings = EditorGUIUtility.TrTextContent("Generation Settings", "Set up how the mipmap levels are generated from the imported image."); public readonly GUIContent sRGBTexture = EditorGUIUtility.TrTextContent("sRGB (Color Texture)", "Texture content is stored in gamma space. Non-HDR color textures should enable this flag (except if used for IMGUI)."); public readonly GUIContent sRGBForEtc1Warning = EditorGUIUtility.TrTextContent("Unity does not support importing textures as ETC when that texture is in the sRGB color space and the project is set to use a Linear color space. One or more of the textures you have selected are imported as ETC2 instead."); public readonly GUIContent borderMipMaps = EditorGUIUtility.TrTextContent("Replicate Border", "Replicate pixel values from texture borders into smaller mipmap levels. Mostly used for Cookie texture types."); @@ -488,6 +490,7 @@ internal SpriteImportMode spriteImportMode } bool m_ShowAdvanced = false; + bool m_ShowMipmapGenerationSettings = true; int m_TextureWidth = 0; int m_TextureHeight = 0; @@ -660,6 +663,7 @@ public override void OnEnable() s_DefaultPlatformName = TextureImporter.defaultPlatformName; // Can't be called everywhere so we save it here for later use. m_ShowAdvanced = EditorPrefs.GetBool("TextureImporterShowAdvanced", m_ShowAdvanced); + m_ShowMipmapGenerationSettings = EditorPrefs.GetBool("TextureImporterShowMipmapGenerationSettings", m_ShowMipmapGenerationSettings); CacheSerializedProperties(); @@ -1055,6 +1059,64 @@ void ReadableGUI(TextureInspectorGUIElement guiElements) } } + void MipmapGenerationGUI() + { + EditorGUILayout.Popup(m_MipMapMode, s_Styles.mipMapFilterOptions, s_Styles.mipMapFilter); + + ToggleFromInt(m_MipMapsPreserveCoverage, s_Styles.mipMapsPreserveCoverage); + if (m_MipMapsPreserveCoverage.intValue != 0 && !m_MipMapsPreserveCoverage.hasMultipleDifferentValues) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_AlphaTestReferenceValue, s_Styles.alphaTestReferenceValue); + EditorGUI.indentLevel--; + } + + ToggleFromInt(m_BorderMipMap, s_Styles.borderMipMaps); + + // Mipmap fadeout + ToggleFromInt(m_FadeOut, s_Styles.mipmapFadeOutToggle); + if (m_FadeOut.intValue > 0) + { + const int minLimit = 0; + const int maxLimit = 10; + + // For presets, we need two separate controls as we have 2 separate SerializedProperties. + EditorGUI.indentLevel++; + if (Presets.Preset.IsEditorTargetAPreset(target)) + { + // Fade Start + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_MipMapFadeDistanceStart, s_Styles.mipmapFadeStartMip); + if (EditorGUI.EndChangeCheck()) + { + m_MipMapFadeDistanceStart.intValue = Math.Clamp(m_MipMapFadeDistanceStart.intValue, minLimit, m_MipMapFadeDistanceEnd.intValue); + } + + // Fade End + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_MipMapFadeDistanceEnd, s_Styles.mipmapFadeEndMip); + if (EditorGUI.EndChangeCheck()) + { + m_MipMapFadeDistanceEnd.intValue = Math.Clamp(m_MipMapFadeDistanceEnd.intValue, m_MipMapFadeDistanceStart.intValue, maxLimit); + } + } + else + { + // Fade Range + EditorGUI.BeginChangeCheck(); + float min = m_MipMapFadeDistanceStart.intValue; + float max = m_MipMapFadeDistanceEnd.intValue; + EditorGUILayout.MinMaxSlider(s_Styles.mipmapFadeOut, ref min, ref max, minLimit, maxLimit); + if (EditorGUI.EndChangeCheck()) + { + m_MipMapFadeDistanceStart.intValue = Mathf.RoundToInt(min); + m_MipMapFadeDistanceEnd.intValue = Mathf.RoundToInt(max); + } + } + EditorGUI.indentLevel--; + } + } + void StreamingMipmapsGUI() { // only 2D & Cubemap shapes support streaming mipmaps right now @@ -1208,8 +1270,8 @@ internal static void DoMipmapLimitsGUI(SerializedProperty ignoreMipmapLimitProp, s_Styles = new Styles(); // The property itself is "ignoreMipmapLimit". However, in the UI, we display it - // as "Use Mipmap Limits" as it makes more sense to hide the group names dropdown - // when "Use Mipmap Limits" is toggled off rather than when "Ignore Mipmap Limit" + // as "use" Mipmap Limit as it makes more sense to hide the group names dropdown + // when "Mipmap Limit" is toggled off rather than when "Ignore Mipmap Limit" // is toggled on. Rect rect = EditorGUILayout.GetControlRect(true, EditorGUI.kSingleLineHeight); GUIContent label = EditorGUI.BeginProperty(rect, s_Styles.useMipmapLimits, ignoreMipmapLimitProp); @@ -1288,7 +1350,15 @@ void MipMapGUI(TextureInspectorGUIElement guiElements) if (EditorGUILayout.BeginFadeGroup(m_ShowMipMapSettings.faded)) { EditorGUI.indentLevel++; - + + m_ShowMipmapGenerationSettings = EditorGUILayout.Foldout(m_ShowMipmapGenerationSettings, s_Styles.showMipmapGenerationSettings, true); + if (m_ShowMipmapGenerationSettings) + { + EditorGUI.indentLevel++; + MipmapGenerationGUI(); + EditorGUI.indentLevel--; + } + bool supportsMipmapLimits = ((TextureImporterShape)m_TextureShape.intValue == TextureImporterShape.Texture2D && !m_VTOnly.boolValue) // If VTOnly, then we don't show the MipmapLimits GUI since its values are ignored anyway || (TextureImporterShape)m_TextureShape.intValue == TextureImporterShape.Texture2DArray; @@ -1300,60 +1370,6 @@ void MipMapGUI(TextureInspectorGUIElement guiElements) StreamingMipmapsGUI(); - EditorGUILayout.Popup(m_MipMapMode, s_Styles.mipMapFilterOptions, s_Styles.mipMapFilter); - - ToggleFromInt(m_MipMapsPreserveCoverage, s_Styles.mipMapsPreserveCoverage); - if (m_MipMapsPreserveCoverage.intValue != 0 && !m_MipMapsPreserveCoverage.hasMultipleDifferentValues) - { - EditorGUI.indentLevel++; - EditorGUILayout.PropertyField(m_AlphaTestReferenceValue, s_Styles.alphaTestReferenceValue); - EditorGUI.indentLevel--; - } - - ToggleFromInt(m_BorderMipMap, s_Styles.borderMipMaps); - - // Mipmap fadeout - ToggleFromInt(m_FadeOut, s_Styles.mipmapFadeOutToggle); - if (m_FadeOut.intValue > 0) - { - const int minLimit = 0; - const int maxLimit = 10; - - // For presets, we need two separate controls as we have 2 separate SerializedProperties. - EditorGUI.indentLevel++; - if (Presets.Preset.IsEditorTargetAPreset(target)) - { - // Fade Start - EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(m_MipMapFadeDistanceStart, s_Styles.mipmapFadeStartMip); - if (EditorGUI.EndChangeCheck()) - { - m_MipMapFadeDistanceStart.intValue = Math.Clamp(m_MipMapFadeDistanceStart.intValue, minLimit, m_MipMapFadeDistanceEnd.intValue); - } - - // Fade End - EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(m_MipMapFadeDistanceEnd, s_Styles.mipmapFadeEndMip); - if (EditorGUI.EndChangeCheck()) - { - m_MipMapFadeDistanceEnd.intValue = Math.Clamp(m_MipMapFadeDistanceEnd.intValue, m_MipMapFadeDistanceStart.intValue, maxLimit); - } - } - else - { - // Fade Range - EditorGUI.BeginChangeCheck(); - float min = m_MipMapFadeDistanceStart.intValue; - float max = m_MipMapFadeDistanceEnd.intValue; - EditorGUILayout.MinMaxSlider(s_Styles.mipmapFadeOut, ref min, ref max, minLimit, maxLimit); - if (EditorGUI.EndChangeCheck()) - { - m_MipMapFadeDistanceStart.intValue = Mathf.RoundToInt(min); - m_MipMapFadeDistanceEnd.intValue = Mathf.RoundToInt(max); - } - } - EditorGUI.indentLevel--; - } EditorGUI.indentLevel--; } EditorGUILayout.EndFadeGroup(); diff --git a/Editor/Mono/Inspector/CubemapInspector.cs b/Editor/Mono/Inspector/CubemapInspector.cs index ec70c78f7e..9669c12a37 100644 --- a/Editor/Mono/Inspector/CubemapInspector.cs +++ b/Editor/Mono/Inspector/CubemapInspector.cs @@ -124,12 +124,14 @@ public override void OnInspectorGUI() faceSize = EditorGUILayout.IntPopup("Face size", faceSize, kSizes, kSizesValues); int mipMaps = TextureUtil.GetMipmapCount(c); - bool useMipMap = EditorGUILayout.Toggle("MipMaps", mipMaps > 1); + bool useMipMap = EditorGUILayout.Toggle("Generate Mipmap", mipMaps > 1); bool streamingMipmaps = TextureUtil.GetCubemapStreamingMipmaps(c); if (useMipMap) { - streamingMipmaps = EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Streaming Mipmaps", "Don't load image data immediately but wait till image data is requested from script."), streamingMipmaps); + EditorGUI.indentLevel++; + streamingMipmaps = EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Stream Mipmap Levels", "Don't load image data immediately but wait till image data is requested from script."), streamingMipmaps); + EditorGUI.indentLevel--; } bool linear = TextureUtil.GetLinearSampled(c); diff --git a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs index b30e5fde9d..ff586f3a8f 100644 --- a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs +++ b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs @@ -99,7 +99,7 @@ class SettingsContent public static readonly GUIContent enableInternalProfiler = EditorGUIUtility.TrTextContent("Enable Internal Profiler* (Deprecated)", "Internal profiler counters should be accessed by scripts using UnityEngine.Profiling::Profiler API."); public static readonly GUIContent stripUnusedMeshComponents = EditorGUIUtility.TrTextContent("Optimize Mesh Data*", "Remove unused mesh components"); public static readonly GUIContent strictShaderVariantMatching = EditorGUIUtility.TrTextContent("Strict shader variant matching*", "When enabled, if a shader variant is missing, Unity uses the error shader and displays an error in the Console."); - public static readonly GUIContent mipStripping = EditorGUIUtility.TrTextContent("Texture MipMap Stripping*", "Remove unused texture levels from package builds, reducing package size on disk. Limits the texture quality settings to the highest mip that was included during the build."); + public static readonly GUIContent mipStripping = EditorGUIUtility.TrTextContent("Texture Mipmap Stripping*", "Remove unused texture mipmap levels from package builds, reducing package size on disk. Limits the texture quality settings to the highest mipmap level that was included during the build."); public static readonly GUIContent enableFrameTimingStats = EditorGUIUtility.TrTextContent("Frame Timing Stats", "Enable gathering of CPU/GPU frame timing statistics."); public static readonly GUIContent enableOpenGLProfilerGPURecorders = EditorGUIUtility.TrTextContent("OpenGL: Profiler GPU Recorders", "Enable Profiler Recorders when rendering with OpenGL. Always enabled with other rendering APIs. Optional on OpenGL due to potential incompatibility with Frame Timing Stats and the GPU Profiler."); public static readonly GUIContent openGLFrameTimingStatsOnGPURecordersOnWarning = EditorGUIUtility.TrTextContent("On OpenGL, Frame Timing Stats may disable Profiler GPU Recorders and the GPU Profiler."); @@ -234,7 +234,7 @@ class SettingsContent public static readonly GUIContent[] lightmapEncodingNames = { EditorGUIUtility.TrTextContent("Low Quality"), EditorGUIUtility.TrTextContent("Normal Quality"), EditorGUIUtility.TrTextContent("High Quality") }; public static readonly GUIContent hdrCubemapEncodingLabel = EditorGUIUtility.TrTextContent("HDR Cubemap Encoding", "Determines which encoding scheme Unity uses to encode HDR cubemaps."); public static readonly GUIContent[] hdrCubemapEncodingNames = { EditorGUIUtility.TrTextContent("Low Quality"), EditorGUIUtility.TrTextContent("Normal Quality"), EditorGUIUtility.TrTextContent("High Quality") }; - public static readonly GUIContent lightmapStreamingEnabled = EditorGUIUtility.TrTextContent("Lightmap Streaming", "Only load larger lightmap mipmaps as needed to render the current game cameras. Requires texture streaming to be enabled in quality settings. This value is applied to the light map textures as they are generated."); + public static readonly GUIContent lightmapStreamingEnabled = EditorGUIUtility.TrTextContent("Lightmap Streaming", "Only load larger lightmap mipmap levels as needed to render the current game cameras. Requires texture streaming to be enabled in quality settings. This value is applied to the light map textures as they are generated."); public static readonly GUIContent lightmapStreamingPriority = EditorGUIUtility.TrTextContent("Streaming Priority", "Lightmap mipmap streaming priority when there's contention for resources. Positive numbers represent higher priority. Valid range is -128 to 127. This value is applied to the light map textures as they are generated."); public static readonly GUIContent legacyClampBlendShapeWeights = EditorGUIUtility.TrTextContent("Clamp BlendShapes (Deprecated)*", "If set, the range of BlendShape weights in SkinnedMeshRenderers will be clamped."); public static readonly GUIContent virtualTexturingSupportEnabled = EditorGUIUtility.TrTextContent("Virtual Texturing (Experimental)*", "Enable Virtual Texturing. This feature is experimental and not ready for production use. Changing this value requires an Editor restart."); diff --git a/Editor/Mono/Inspector/QualitySettingsEditor.cs b/Editor/Mono/Inspector/QualitySettingsEditor.cs index f96a3d3795..6d19adc414 100644 --- a/Editor/Mono/Inspector/QualitySettingsEditor.cs +++ b/Editor/Mono/Inspector/QualitySettingsEditor.cs @@ -32,13 +32,13 @@ private class Content }; public static readonly GUIContent[] kTextureMipmapLimitGroupsOffsetModeItems = { - EditorGUIUtility.TrTextContent("Offset Global Mipmap Limit: -3", "Upload 3 mips extra compared to the Global Mipmap Limit."), - EditorGUIUtility.TrTextContent("Offset Global Mipmap Limit: -2", "Upload 2 mips extra compared to the Global Mipmap Limit."), - EditorGUIUtility.TrTextContent("Offset Global Mipmap Limit: -1", "Upload 1 mip extra compared to the Global Mipmap Limit."), + EditorGUIUtility.TrTextContent("Offset Global Mipmap Limit: -3", "Upload 3 mipmap levels extra compared to the Global Mipmap Limit."), + EditorGUIUtility.TrTextContent("Offset Global Mipmap Limit: -2", "Upload 2 mipmap levels extra compared to the Global Mipmap Limit."), + EditorGUIUtility.TrTextContent("Offset Global Mipmap Limit: -1", "Upload 1 mipmap level extra compared to the Global Mipmap Limit."), EditorGUIUtility.TrTextContent("Use Global Mipmap Limit", "No offset or override occurs, simply use the Global Mipmap Limit. (Default)"), - EditorGUIUtility.TrTextContent("Offset Global Mipmap Limit: +1", "Upload 1 mip less compared to the Global Mipmap Limit."), - EditorGUIUtility.TrTextContent("Offset Global Mipmap Limit: +2", "Upload 2 mips less compared to the Global Mipmap Limit."), - EditorGUIUtility.TrTextContent("Offset Global Mipmap Limit: +3", "Upload 3 mips less compared to the Global Mipmap Limit.") + EditorGUIUtility.TrTextContent("Offset Global Mipmap Limit: +1", "Upload 1 mipmap level less compared to the Global Mipmap Limit."), + EditorGUIUtility.TrTextContent("Offset Global Mipmap Limit: +2", "Upload 2 mipmap levels less compared to the Global Mipmap Limit."), + EditorGUIUtility.TrTextContent("Offset Global Mipmap Limit: +3", "Upload 3 mipmap levels less compared to the Global Mipmap Limit.") }; public static readonly GUIContent kTextureMipmapLimitGroupsOptions = EditorGUIUtility.TrIconContent("_Menu", "Show additional options"); public static readonly GUIContent kTextureMipmapLimitGroupsOptionsIdentify = EditorGUIUtility.TrTextContent("Identify textures"); @@ -55,7 +55,7 @@ private class Content public static readonly string kTextureMipmapLimitGroupsDialogMessageOnUpdateAssetsError = L10n.Tr("An error occured while updating texture assets: {0}"); public static readonly string kTextureMipmapLimitGroupsDialogMessageOnIdentifyFail = L10n.Tr("No textures are linked to the mipmap limit group '{0}'."); - public static readonly GUIContent kStreamingMipmapsActive = EditorGUIUtility.TrTextContent("Texture Streaming", "When enabled, Unity only streams texture mipmaps relevant to the current Camera's position in a Scene. This reduces the total amount of memory Unity needs for textures. Individual textures must also have 'Streaming Mip Maps' enabled in their Import Settings."); + public static readonly GUIContent kStreamingMipmapsActive = EditorGUIUtility.TrTextContent("Texture Streaming", "When enabled, Unity only streams texture mipmap levels relevant to the current Camera's position in a Scene. This reduces the total amount of memory Unity needs for textures. Individual textures must also have 'Stream Mipmap Levels' enabled in their Import Settings."); public static readonly GUIContent kStreamingMipmapsMemoryBudget = EditorGUIUtility.TrTextContent("Memory Budget", "The amount of memory (in megabytes) to allocate for all loaded textures."); public static readonly GUIContent kStreamingMipmapsRenderersPerFrame = EditorGUIUtility.TrTextContent("Renderers Per Frame", "The number of renderers to process each frame. A lower number decreases the CPU load but delays mipmap loading."); public static readonly GUIContent kStreamingMipmapsAddAllCameras = EditorGUIUtility.TrTextContent("Add All Cameras", "When enabled, Unity uses texture streaming for every Camera in the Scene. Otherwise, Unity only uses texture streaming for Cameras that have an attached Streaming Controller component."); @@ -71,7 +71,7 @@ private class Content public static readonly GUIContent kLODBiasLabel = EditorGUIUtility.TrTextContent("LOD Bias", "The bias Unity uses to determine which model to render when a GameObject’s on-screen size is between two LOD levels. Values between 0 and 1 favor the less detailed model. Values greater than 1 favor the more detailed model."); public static readonly GUIContent kMaximumLODLevelLabel = EditorGUIUtility.TrTextContent("Maximum LOD Level", "The highest LOD to use in the application."); public static readonly GUIContent kEnableLODCrossFadeLabel = EditorGUIUtility.TrTextContent("LOD Cross Fade", "Enables or disables LOD Cross Fade."); - public static readonly GUIContent kMipStrippingHint = EditorGUIUtility.TrTextContent("Detected platforms with textures that never use their highest resolution mips. Enable Texture Mipmap Stripping in the Player Settings to reduce the package size of those platforms."); + public static readonly GUIContent kMipStrippingHint = EditorGUIUtility.TrTextContent("Detected platforms with textures that never use their highest resolution mipmap levels. Enable Texture Mipmap Stripping in the Player Settings to reduce the package size of those platforms."); public static readonly GUIContent kAsyncUploadTimeSlice = EditorGUIUtility.TrTextContent("Time Slice", "The amount of time (in milliseconds) Unity spends uploading Texture and Mesh data to the GPU per frame."); public static readonly GUIContent kAsyncUploadBufferSize = EditorGUIUtility.TrTextContent("Buffer Size", "The size (in megabytes) of the upload buffer Unity uses to stream Texture and Mesh data to GPU."); diff --git a/Editor/Mono/Inspector/RenderTextureEditor.cs b/Editor/Mono/Inspector/RenderTextureEditor.cs index b206995461..5fceea276c 100644 --- a/Editor/Mono/Inspector/RenderTextureEditor.cs +++ b/Editor/Mono/Inspector/RenderTextureEditor.cs @@ -24,8 +24,8 @@ private class Styles public readonly GUIContent depthStencilFormat = EditorGUIUtility.TrTextContent("Depth Stencil Format", "Format of the depth stencil buffer."); public readonly GUIContent enableCompatibleFormat = EditorGUIUtility.TrTextContent("Enable Compatible Format", "Lets the color and depth stencil formats be changed to compatible and supported formats for the target platform automatically, if the target platform doesn't support the input format."); public readonly GUIContent dimension = EditorGUIUtility.TrTextContent("Dimension", "Is the texture 2D, Cube or 3D?"); - public readonly GUIContent enableMipmaps = EditorGUIUtility.TrTextContent("Enable Mip Maps", "This render texture will have Mip Maps."); - public readonly GUIContent autoGeneratesMipmaps = EditorGUIUtility.TrTextContent("Auto generate Mip Maps", "This render texture automatically generates its Mip Maps."); + public readonly GUIContent enableMipmaps = EditorGUIUtility.TrTextContent("Mipmap", "This render texture will have a mipmap."); + public readonly GUIContent autoGeneratesMipmaps = EditorGUIUtility.TrTextContent("Auto-generate", "This render texture automatically generate its mipmap."); public readonly GUIContent useDynamicScale = EditorGUIUtility.TrTextContent("Dynamic Scaling", "Allow the texture to be automatically resized by ScalableBufferManager, to support dynamic resolution."); public readonly GUIContent enableRandomWrite = EditorGUIUtility.TrTextContent("Random Write", "Enable/disable random access write into the color buffer of this render texture."); public readonly GUIContent shadowSamplingMode = EditorGUIUtility.TrTextContent("Shadow Sampling Mode", "Enable/disable shadow depth-compare sampling and percentage closer filtering."); diff --git a/Editor/Mono/Inspector/StreamingControllerInspector.cs b/Editor/Mono/Inspector/StreamingControllerInspector.cs index 9c89c948e6..7f71b3f658 100644 --- a/Editor/Mono/Inspector/StreamingControllerInspector.cs +++ b/Editor/Mono/Inspector/StreamingControllerInspector.cs @@ -15,7 +15,7 @@ internal class StreamingControllerEditor : Editor internal static class Styles { - public static GUIContent streamingMipmapBias = EditorGUIUtility.TrTextContent("Mip Map Bias", "When texture streaming is active, Unity loads mipmap levels for textures based on their distance from all active cameras. This bias is added to all textures visible from this camera and allows you to force smaller or larger mipmap levels to be loaded for textures visible from this camera."); + public static GUIContent streamingMipmapBias = EditorGUIUtility.TrTextContent("Mipmap Bias", "When texture streaming is active, Unity loads mipmap levels for textures based on their distance from all active cameras. This bias is added to all textures visible from this camera and allows you to force smaller or larger mipmap levels to be loaded for textures visible from this camera."); } public void OnEnable() diff --git a/Editor/Mono/ObjectSelector.cs b/Editor/Mono/ObjectSelector.cs index e147b1a26b..a8f3f3489e 100644 --- a/Editor/Mono/ObjectSelector.cs +++ b/Editor/Mono/ObjectSelector.cs @@ -442,6 +442,11 @@ internal void Show(UnityObject obj, Type requiredType, UnityObject objectBeingEd internal void Show(UnityObject obj, Type[] requiredTypes, UnityObject objectBeingEdited, bool allowSceneObjects, List allowedInstanceIDs = null, Action onObjectSelectorClosed = null, Action onObjectSelectedUpdated = null, bool showNoneItem = true) { + // We can't rely on the fact that the window will always be closed when we call Show. For example, + // if a user clicks on multiple object fields without closing the window first, there is no guarantee + // that the auxiliary window will close before the click event is processed. And since closing the window + // cleans up the undo state, we have to force close the window if it wasn't already closed. + CloseOpenedWindow(); m_ObjectSelectorReceiver = null; m_AllowSceneObjects = allowSceneObjects; m_IsShowingAssets = true; @@ -602,6 +607,24 @@ internal void Show(UnityObject obj, Type[] requiredTypes, UnityObject objectBein } } + void CloseOpenedWindow() + { + // We check m_ModalUndoGroup as it is the only value that will be reliably set when the window is open + // and unset when the window is closed. Checking m_OnObjectSelectorClosed or m_ObjectSelectorReceiver is not enough + // as they are not always set. + if (m_ModalUndoGroup >= 0) + { + if (ObjectSelectorSearch.HasEngineOverride()) + { + m_SearchSessionHandler.CloseSelector(); + } + else + { + NotifySelectorClosed(false); + } + } + } + internal static string GenerateTitleContent(Type[] requiredTypes, string[] requiredTypeStrings) { var typeName = requiredTypes[0] == null ? requiredTypeStrings[0] : requiredTypes[0].Name; @@ -1114,12 +1137,16 @@ internal void Internal_NotifySelectorClosed(UnityObject selectedObject, bool exi if (m_ObjectSelectorReceiver != null) { m_ObjectSelectorReceiver.OnSelectionClosed(selectedObject); + m_ObjectSelectorReceiver = null; } m_OnObjectSelectorClosed?.Invoke(selectedObject); + m_OnObjectSelectorClosed = null; + m_OnObjectSelectorUpdated = null; SendEvent(ObjectSelectorClosedCommand, exitGUI); Undo.CollapseUndoOperations(m_ModalUndoGroup); + m_ModalUndoGroup = -1; } } } diff --git a/Editor/Mono/Overlays/Overlay.cs b/Editor/Mono/Overlays/Overlay.cs index 831d9c87a6..bbe2447b1d 100644 --- a/Editor/Mono/Overlays/Overlay.cs +++ b/Editor/Mono/Overlays/Overlay.cs @@ -303,6 +303,52 @@ protected internal virtual Layout supportedLayouts } } + sealed class GlobalMouseBehaviourForOverlays : MouseManipulator + { + Overlay m_Overlay; + + public GlobalMouseBehaviourForOverlays(Overlay overlay) + { + m_Overlay = overlay; + } + + protected override void RegisterCallbacksOnTarget() + { + target.RegisterCallback(OnMouseDownTrickleDown, TrickleDown.TrickleDown); + target.RegisterCallback(OnMouseDownBubbleUp, TrickleDown.NoTrickleDown); + target.RegisterCallback(OnMouseUp); + target.RegisterCallback(OnMouseMove); + } + + protected override void UnregisterCallbacksFromTarget() + { + target.UnregisterCallback(OnMouseDownTrickleDown, TrickleDown.TrickleDown); + target.UnregisterCallback(OnMouseDownBubbleUp, TrickleDown.NoTrickleDown); + target.UnregisterCallback(OnMouseUp); + target.UnregisterCallback(OnMouseMove); + } + + void OnMouseDownTrickleDown(MouseDownEvent e) + { + m_Overlay.BringToFront(); + } + + void OnMouseDownBubbleUp(MouseDownEvent e) + { + e.StopPropagation(); + } + + void OnMouseUp(MouseUpEvent e) + { + e.StopPropagation(); + } + + void OnMouseMove(MouseMoveEvent e) + { + e.StopPropagation(); + } + } + public VisualElement rootVisualElement { get @@ -316,6 +362,7 @@ public VisualElement rootVisualElement m_RootVisualElement.name = m_RootVisualElementName; m_RootVisualElement.usageHints = UsageHints.DynamicTransform; m_RootVisualElement.AddToClassList(ussClassName); + m_RootVisualElement.AddManipulator(new GlobalMouseBehaviourForOverlays(this)); var dragger = new OverlayDragger(this); var contextClick = new ContextualMenuManipulator(BuildContextMenu); diff --git a/Editor/Mono/PlayerSettingsAndroid.bindings.cs b/Editor/Mono/PlayerSettingsAndroid.bindings.cs index e9059ff0f4..15d2b01f49 100644 --- a/Editor/Mono/PlayerSettingsAndroid.bindings.cs +++ b/Editor/Mono/PlayerSettingsAndroid.bindings.cs @@ -555,7 +555,7 @@ private static void SetAndroidMaxAspectRatioInternal(float value) if (value < 1.86f) { Debug.LogWarning($"Maximum Aspect Ratio must be greater or equal to 1.86. {value} is too small, setting to 1.86 instead."); - SetAndroidMinAspectRatio(1.86f); + SetAndroidMaxAspectRatio(1.86f); } else { diff --git a/Editor/Mono/SceneView/SceneView.cs b/Editor/Mono/SceneView/SceneView.cs index 4e94a3f1f5..1c6b34996f 100644 --- a/Editor/Mono/SceneView/SceneView.cs +++ b/Editor/Mono/SceneView/SceneView.cs @@ -2744,7 +2744,8 @@ static void OpenActionMenu(ShortcutArguments args) if (ve == context.cameraViewVisualElement) { ContextMenuUtility.ShowActionMenu(); - context.Repaint(); + // UUM-61727 - Force an InputEvent in IMGUI so the ContextMenu will actually open on all platforms + context.SendEvent(new Event { type = EventType.Layout }); } } diff --git a/Editor/Mono/Search/ObjectSelectorSearch.cs b/Editor/Mono/Search/ObjectSelectorSearch.cs index 1897045acb..9ea7fe817c 100644 --- a/Editor/Mono/Search/ObjectSelectorSearch.cs +++ b/Editor/Mono/Search/ObjectSelectorSearch.cs @@ -21,6 +21,13 @@ public enum VisibleObjects All = Assets | Scene } + [Flags] + public enum ObjectSelectorSearchEndSessionModes + { + None = 0, + CloseSelector = 1 + } + public partial class ObjectSelectorSearchContext : ISearchContext { public Guid guid { get; } = Guid.NewGuid(); @@ -31,6 +38,7 @@ public partial class ObjectSelectorSearchContext : ISearchContext public IEnumerable requiredTypeNames { get; set; } public VisibleObjects visibleObjects { get; set; } public IEnumerable allowedInstanceIds { get; set; } + public ObjectSelectorSearchEndSessionModes endSessionModes { get; set; } internal SearchFilter searchFilter { get; set; } } @@ -134,6 +142,23 @@ class ObjectSelectorSearchSessionHandler : SearchSessionHandler public ObjectSelectorSearchSessionHandler() : base(SearchEngineScope.ObjectSelector) {} + protected override void OnActiveEngineChanged(string newSearchEngineName) + { + CloseSelector(); + } + + public void CloseSelector() + { + if (context is ObjectSelectorSearchContext selectorContext) + { + // Context is set to null after EndSession, so no need to set the + // endSessionModes back to its original value. It is also valid that context + // is null when calling CloseSelector/EndSession if no session was started before. + selectorContext.endSessionModes |= ObjectSelectorSearchEndSessionModes.CloseSelector; + } + EndSession(); + } + public bool SelectObject(Action onObjectSelectorClosed, Action onObjectSelectedUpdated) { using (new SearchSessionOptionsApplicator(m_Api, m_Options)) diff --git a/Editor/Mono/Search/SearchService.cs b/Editor/Mono/Search/SearchService.cs index 3292b92801..4a1e53143c 100644 --- a/Editor/Mono/Search/SearchService.cs +++ b/Editor/Mono/Search/SearchService.cs @@ -133,7 +133,7 @@ void PullEngines() } } - void OnActiveEngineChanged(string newSearchEngineName) + protected virtual void OnActiveEngineChanged(string newSearchEngineName) { EndSession(); } diff --git a/Editor/Mono/UIElements/DefaultMainToolbar.cs b/Editor/Mono/UIElements/DefaultMainToolbar.cs index e2491cdf77..690d8b1724 100644 --- a/Editor/Mono/UIElements/DefaultMainToolbar.cs +++ b/Editor/Mono/UIElements/DefaultMainToolbar.cs @@ -14,9 +14,14 @@ static IEnumerable leftToolbar { get { + //Modules/EditorToolbar/ToolbarElements/*.cs yield return "Services/Account"; yield return "Services/Cloud"; + //com.unity.collab-proxy/Editor/PlasticSCM/Toolbar/ToolbarButton.cs + yield return "Services/Version Control"; + //Modules/EditorToolbar/ToolbarElements/*.cs yield return "Editor Utility/Store"; + //Editor/Mono/GUI/Toolbars/MainToolbarImguiContainer.cs yield return "Editor Utility/Imgui Subtoolbars"; } } @@ -41,7 +46,7 @@ static IEnumerable rightToolbar yield return "Editor Utility/Modes"; yield return "Package Manager/PreviewPackagesInUse"; yield return "Editor Utility/Undo"; - // Modules/Multiplayer/MultiplayerRoleDrwopdown.cs + // Modules/Multiplayer/MultiplayerRoleDropdown.cs yield return "Multiplayer/MultiplayerRole"; } } diff --git a/Modules/AndroidJNI/AndroidGame.bindings.cs b/Modules/AndroidJNI/AndroidGame.bindings.cs index 83eb80b34b..abeff940a4 100644 --- a/Modules/AndroidJNI/AndroidGame.bindings.cs +++ b/Modules/AndroidJNI/AndroidGame.bindings.cs @@ -58,6 +58,16 @@ internal enum GameStateLabel [StaticAccessor("GameStateHelper::Get()", StaticAccessorType.Dot)] public static partial class AndroidGame { + [StaticAccessor("GameStateHelper::Get()", StaticAccessorType.Dot)] + public static partial class Automatic + { + /// + /// Set current GameState mode which will be used for automated GameState hinting. + /// + /// GameState mode value. + [NativeMethod("SetGameStateMode")] + public static extern void SetGameState(AndroidGameState mode); + } // Required for automated SetGameState calls, indicates to the operating system when the application is in loading state, level is the type of loading internal static extern void StartLoading(int label); // Required for automated SetGameState calls, indicates to the operating system when loading state is ended, level is the type of loading diff --git a/Modules/BuildProfileEditor/BuildProfileEditor.cs b/Modules/BuildProfileEditor/BuildProfileEditor.cs index 9b54ad5bcf..2e35d111b0 100644 --- a/Modules/BuildProfileEditor/BuildProfileEditor.cs +++ b/Modules/BuildProfileEditor/BuildProfileEditor.cs @@ -226,7 +226,7 @@ void AddSceneList(VisualElement root, BuildProfile profile = null) ? new BuildProfileSceneList() : new BuildProfileSceneList(profile); Undo.undoRedoEvent += m_SceneList.OnUndoRedo; - var container = m_SceneList.GetSceneListGUI(sceneListFoldout, isEnable); + var container = m_SceneList.GetSceneListGUI(isEnable); container.SetEnabled(isEnable); root.Q(k_SceneListFoldoutRoot).Add(container); diff --git a/Modules/BuildProfileEditor/BuildProfileWindow.cs b/Modules/BuildProfileEditor/BuildProfileWindow.cs index 8e195308ec..9a7d5edfbb 100644 --- a/Modules/BuildProfileEditor/BuildProfileWindow.cs +++ b/Modules/BuildProfileEditor/BuildProfileWindow.cs @@ -11,7 +11,6 @@ using UnityEngine; using UnityEngine.Scripting; using UnityEngine.UIElements; -using static UnityEditor.Build.Profile.Handlers.BuildProfileWindowSelection; namespace UnityEditor.Build.Profile { @@ -26,16 +25,12 @@ internal class BuildProfileWindow : EditorWindow const string k_Uxml = "BuildProfile/UXML/BuildProfileWindow.uxml"; const string k_PlayerSettingsWindow = "Project/Player"; - internal const string buildProfileClassicPlatformVisualElement = "build-profile-classic-platforms"; - internal const string buildProfileClassicPlatformMissingVisualElement = "build-profile-classic-platforms-missing"; internal const string buildProfileInspectorVisualElement = "build-profile-editor-inspector"; - internal const string buildProfilesVisualElement = "custom-build-profiles"; internal BuildProfileEditor buildProfileEditor; BuildProfileWorkflowState m_WindowState; bool m_ShouldAskForBuildLocation = true; - int m_ActiveProfileListIndex; BuildProfileDataSource m_BuildProfileDataSource; BuildProfileContextMenu m_BuildProfileContextMenu; @@ -44,13 +39,7 @@ internal class BuildProfileWindow : EditorWindow /// /// Left column classic profile list view. /// - ListView m_BuildProfileClassicPlatformListView; - ListView m_MissingClassicPlatformListView; - - /// - /// Left column custom build profile list view. - /// - ListView m_BuildProfilesListView; + PlatformListView m_ProfileListViews; VisualElement m_WelcomeMessageElement; VisualElement m_InspectorHeader; @@ -67,7 +56,6 @@ internal class BuildProfileWindow : EditorWindow ToolbarButton m_AssetImportButton; Button m_BuildAndRunButton; Button m_ActivateButton; - Button m_ClassicSceneListButton; AssetImportOverridesWindow m_AssetImportWindow; Background m_WarningIcon; @@ -96,12 +84,9 @@ public void CreateGUI() m_BuildButton = CreateBuildDropdownButton(); rootVisualElement.Q("build-dropdown-button").Add(m_BuildButton); m_BuildProfileInspectorElement = rootVisualElement.Q(buildProfileInspectorVisualElement); - m_BuildProfileClassicPlatformListView = rootVisualElement.Q(buildProfileClassicPlatformVisualElement); - m_BuildProfilesListView = rootVisualElement.Q(buildProfilesVisualElement); m_BuildAndRunButton = rootVisualElement.Q