From c3cf7076574ca470291e6b2fce269819befa9d50 Mon Sep 17 00:00:00 2001 From: Unity Technologies Date: Thu, 20 Jun 2024 16:04:46 +0000 Subject: [PATCH] Unity 6000.0.7f1 C# reference source code --- .../AssetPipeline/TextureImporter.bindings.cs | 21 + .../Mono/Audio/AudioContainerWindowState.cs | 5 + Editor/Mono/BuildPipeline/NamedBuildTarget.cs | 3 + Editor/Mono/BuildPlayerWindow.cs | 3 +- .../Mono/BuildProfile/BuildProfileContext.cs | 18 +- Editor/Mono/BuildTarget.cs | 1 + Editor/Mono/BuildTargetDiscovery.bindings.cs | 13 + Editor/Mono/BuildTargetGroup.cs | 1 + Editor/Mono/ContainerWindow.cs | 4 +- Editor/Mono/EditorGUI.cs | 2 +- Editor/Mono/EditorGUIUtility.cs | 44 ++ Editor/Mono/EditorUserSettings.bindings.cs | 3 + Editor/Mono/GI/InputExtraction.bindings.cs | 12 +- Editor/Mono/GI/InputExtraction.cs | 30 +- Editor/Mono/GI/LightBaker.bindings.cs | 181 +++++-- Editor/Mono/GI/Lightmapping.bindings.cs | 8 +- Editor/Mono/GI/ProgressState.bindings.cs | 9 + .../Mono/GI/RadeonRaysLightBaker.bindings.cs | 2 +- Editor/Mono/GI/UnityComputeBake.cs | 39 +- .../Mono/GI/WintermuteLightBaker.bindings.cs | 2 +- Editor/Mono/GUI/DockArea.cs | 11 +- Editor/Mono/GUI/MainView.cs | 2 +- Editor/Mono/GUI/PackageExport.cs | 30 +- Editor/Mono/GUI/PackageExportTreeView.cs | 26 +- Editor/Mono/GUI/PackageImport.cs | 6 + Editor/Mono/GUI/PackageImportTreeView.cs | 33 +- Editor/Mono/GUI/PaneDragTab.cs | 2 +- .../GUI/Toolbars/MainToolbarImguiContainer.cs | 6 + Editor/Mono/GUI/Toolbars/Toolbar.cs | 9 +- Editor/Mono/GUI/TreeView/TreeViewItem.cs | 21 +- Editor/Mono/Graphics/ShaderCompilerData.cs | 1 + Editor/Mono/Inspector/Core/InspectorWindow.cs | 62 ++- Editor/Mono/Inspector/Core/PropertyEditor.cs | 12 +- .../Implementations/PropertyDrawers.cs | 133 +++++ .../ScriptAttributeGUI/PropertyHandler.cs | 18 +- .../GraphicsSettingsInspectorUtility.cs | 10 + Editor/Mono/Inspector/LightEditor.cs | 5 + Editor/Mono/Inspector/MaskFieldDropdown.cs | 16 +- .../PlayerSettingsEditor.cs | 104 ++-- .../VersionControlSettingsInspector.cs | 5 + .../DefaultPlayerSettingsEditorExtension.cs | 24 +- Editor/Mono/Modules/PlatformSupportModule.cs | 8 + Editor/Mono/ObjectFactory.bindings.cs | 3 + Editor/Mono/Overlays/OverlayCanvas.cs | 69 ++- Editor/Mono/PlayerSettingsIOS.bindings.cs | 45 +- .../Mono/ProjectBrowser/ProjectWindowUtil.cs | 7 +- .../Mono/SceneView/SceneOrientationGizmo.cs | 12 - Editor/Mono/SceneView/SceneView.cs | 5 + Editor/Mono/SceneView/SceneViewMotion.cs | 8 +- Editor/Mono/Tools/EditorToolCache.cs | 7 +- Editor/Mono/Tools/EditorToolManager.cs | 2 +- Editor/Mono/Tools/EditorToolUtility.cs | 8 + Editor/Mono/Tools/ToolManager.cs | 2 + Editor/Mono/UIElements/DefaultMainToolbar.cs | 2 +- External/NiceIO/NiceIO.cs | 48 +- .../Baselib_ErrorState.gen.binding.cs | 2 +- Modules/AndroidJNI/AndroidApp.bindings.cs | 64 --- .../AndroidJNI/AndroidApplication.bindings.cs | 80 +++ Modules/AndroidJNI/AndroidJNI.bindings.cs | 8 +- Modules/AndroidJNI/AndroidJava.cs | 25 +- .../Configuration/AndroidColorModeHdr.cs | 13 + .../AndroidColorModeWideColorGamut.cs | 13 + .../Configuration/AndroidConfiguration.cs | 114 ++++ .../AndroidHardwareKeyboardHidden.cs | 13 + .../Configuration/AndroidKeyboard.cs | 14 + .../Configuration/AndroidKeyboardHidden.cs | 13 + .../Configuration/AndroidNavigation.cs | 15 + .../Configuration/AndroidNavigationHidden.cs | 13 + .../Configuration/AndroidOrientation.cs | 13 + .../AndroidScreenLayoutDirection.cs | 14 + .../Configuration/AndroidScreenLayoutLong.cs | 15 + .../Configuration/AndroidScreenLayoutRound.cs | 15 + .../Configuration/AndroidScreenLayoutSize.cs | 17 + .../Configuration/AndroidTouchScreen.cs | 13 + .../Configuration/AndroidUiModeNight.cs | 15 + .../Configuration/AndroidUiModeType.cs | 20 + .../BuildProfilePlayerSettingsEditor.cs | 11 +- Modules/EditorToolbar/Controls/ToolButton.cs | 14 +- .../ToolbarElements/CloudButton.cs | 4 +- .../ToolbarElements/LayoutDropdown.cs | 2 + .../ToolbarElements/OverlayMenu.cs | 14 +- .../ToolbarElements/UndoButton.cs | 3 +- Modules/EmbreeEditor/Embree.bindings.cs | 44 ++ .../Editor/Managed/ResolutionStrategy.cs | 13 + .../Editor/Managed/SemVersionHelper.cs | 63 +++ .../AssetStore/AssetStoreDownloadManager.cs | 2 +- .../AssetStore/AssetStoreDownloadOperation.cs | 2 +- .../Editor/Services/Common/Package.cs | 17 +- .../Editor/Services/Interfaces/IPackage.cs | 3 +- .../Services/Packages/Actions/AddAction.cs | 6 +- .../Packages/Actions/GitUpdateAction.cs | 5 +- .../Services/Packages/Actions/UpdateAction.cs | 6 +- .../Packages/PackageOperationDispatcher.cs | 42 +- .../Editor/Services/Packages/PackageState.cs | 5 +- .../Editor/Services/Pages/SimplePage.cs | 3 +- .../Editor/Services/Upm/UpmPackageFactory.cs | 14 +- .../PackageManagerUserSettingsProvider.cs | 2 +- .../Editor/UI/AddPackageByNameDropdown.cs | 15 +- .../Editor/UI/Common/BaseDropdownButton.cs | 232 ++++++++ .../Editor/UI/Common/DropdownButton.cs | 214 +------- .../Editor/UI/Common/UIUtils.cs | 13 + .../UI/MultiSelect/MultiSelectFoldout.cs | 4 +- .../PackageDetailsVersionHistoryItem.cs | 4 +- .../PackageManagerUI/Editor/UI/PackageItem.cs | 64 +-- .../Editor/UI/PackageManagerToolbar.cs | 15 +- .../Editor/UI/PackageManagerWindow.cs | 3 +- .../Editor/UI/PackageManagerWindowRoot.cs | 12 +- .../Editor/UI/PackageSelectionEditor.cs | 19 +- .../PackageTagLabel/PackageDynamicTagLabel.cs | 7 + .../UI/SelectionWindow/SelectionWindowData.cs | 7 +- .../SelectionWindow/SelectionWindowFooter.cs | 20 +- .../UI/SelectionWindow/SelectionWindowRoot.cs | 2 +- .../SelectionWindowTreeView.cs | 2 +- .../Interfaces/IPackageToolBarButton.cs | 18 + .../UI/ToolBar/LegacyFormatDropdownButton.cs | 45 +- .../Editor/UI/ToolBar/PackageToolBar.cs | 12 +- ...cs => PackageToolBarButtonSingleAction.cs} | 18 +- .../ScriptBindings/Physics.bindings.cs | 3 +- .../PhysicsEditor/PhysicsManagerInspector.cs | 68 ++- .../Editor/Providers/AssetProvider.cs | 2 +- .../TextGenerator/TextGeneratorParsing.cs | 54 +- .../TextGeneratorPreferredValues.cs | 28 +- .../Editor/Builder/BuilderSelection.cs | 10 + .../Builder/Explorer/BuilderExplorerItem.cs | 67 ++- .../Builder/Utilities/BuilderConstants.cs | 2 +- .../BuilderUxmlAttributesView.cs | 7 + .../ElementHierarchyView.cs | 8 + .../VisualTreeAssetLinkedCloneTree.cs | 8 +- .../VisualTreeAssetUtilities.cs | 4 +- .../Core/BackgroundPropertyHelper.cs | 30 +- .../Core/Bindings/DataBindingManager.cs | 19 +- .../Controls/BaseVerticalCollectionView.cs | 23 + .../UIElements/Core/Controls/MinMaxSlider.cs | 69 +-- .../MultiColumn/MultiColumnController.cs | 4 +- .../UIElements/Core/Controls/ProgressBar.cs | 2 +- .../ToggleButtonGroupState.cs | 2 +- .../Renderer/UIRMeshBuilder.bindings.cs | 2 + .../Core/Renderer/UIRElementBuilder.cs | 59 ++- .../Core/Renderer/UIREntryProcessor.cs | 12 +- .../UIElements/Core/Renderer/UIRLinkedPool.cs | 9 +- .../Core/Renderer/UIRMeshGenerator.cs | 30 +- .../Core/Renderer/UIRRenderChain.cs | 8 +- .../UIElements/Core/Text/TextEventHandler.cs | 322 +++++++++++ Modules/UIElements/Core/Text/TextUtilities.cs | 196 +++++++ .../UIElements/Core/Text/UITKTextHandle.cs | 498 +----------------- Modules/UIElements/Core/TextElementEdition.cs | 1 + .../UIElements/Core/UXML/VisualTreeAsset.cs | 29 +- .../UIElementsViewImporter.cs | 12 +- .../UIElementsEditor/UXML/UxmlSerializer.cs | 3 +- Projects/CSharp/UnityEditor.csproj | 19 +- Projects/CSharp/UnityEngine.csproj | 64 ++- README.md | 2 +- Runtime/Export/BaseClass.cs | 1 + Runtime/Export/Graphics/GraphicsEnums.cs | 3 +- .../Export/Misc/ObjectDispatcher.bindings.cs | 1 + .../PropertyDrawer/PropertyAttribute.cs | 11 + .../Scripting/Awaitable.AsyncMethodBuilder.cs | 9 +- .../Awaitable.AsyncMethodBuilderT.cs | 9 +- .../Export/Scripting/Awaitable.Bindings.cs | 16 +- .../Scripting/Awaitable.Synchronization.cs | 41 -- .../Awaitable.ThreadSafeObjectPool.cs | 51 -- Runtime/Export/Scripting/Awaitable.cs | 68 ++- Runtime/Export/Scripting/AwaitableT.cs | 10 +- .../Scripting/UnityEngineObject.bindings.cs | 2 +- .../BeeDriver2/Bee.BeeDriver2.dll | Bin 119808 -> 119296 bytes 165 files changed, 2975 insertions(+), 1596 deletions(-) delete mode 100644 Modules/AndroidJNI/AndroidApp.bindings.cs create mode 100644 Modules/AndroidJNI/AndroidApplication.bindings.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidColorModeHdr.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidColorModeWideColorGamut.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidConfiguration.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidHardwareKeyboardHidden.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidKeyboard.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidKeyboardHidden.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidNavigation.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidNavigationHidden.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidOrientation.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidScreenLayoutDirection.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidScreenLayoutLong.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidScreenLayoutRound.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidScreenLayoutSize.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidTouchScreen.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidUiModeNight.cs create mode 100644 Modules/AndroidJNI/Configuration/AndroidUiModeType.cs create mode 100644 Modules/EmbreeEditor/Embree.bindings.cs create mode 100644 Modules/PackageManager/Editor/Managed/ResolutionStrategy.cs create mode 100644 Modules/PackageManager/Editor/Managed/SemVersionHelper.cs create mode 100644 Modules/PackageManagerUI/Editor/UI/Common/BaseDropdownButton.cs create mode 100644 Modules/PackageManagerUI/Editor/UI/ToolBar/Interfaces/IPackageToolBarButton.cs rename Modules/PackageManagerUI/Editor/UI/ToolBar/{PackageToolBarButton.cs => PackageToolBarButtonSingleAction.cs} (89%) create mode 100644 Modules/UIElements/Core/Text/TextEventHandler.cs create mode 100644 Modules/UIElements/Core/Text/TextUtilities.cs delete mode 100644 Runtime/Export/Scripting/Awaitable.Synchronization.cs delete mode 100644 Runtime/Export/Scripting/Awaitable.ThreadSafeObjectPool.cs diff --git a/Editor/Mono/AssetPipeline/TextureImporter.bindings.cs b/Editor/Mono/AssetPipeline/TextureImporter.bindings.cs index e6788fee09..0a377b32a6 100644 --- a/Editor/Mono/AssetPipeline/TextureImporter.bindings.cs +++ b/Editor/Mono/AssetPipeline/TextureImporter.bindings.cs @@ -452,9 +452,30 @@ public void ReadTextureSettings(TextureImporterSettings dest) // Set texture importers settings from [[TextureImporterSettings]] class. public void SetTextureSettings(TextureImporterSettings src) { + ValidateAndCorrectTextureImporterSettings(src); settings = src; } + private void ValidateAndCorrectTextureImporterSettings(TextureImporterSettings m_Settings) + { + switch (m_Settings.textureType) + { + case TextureImporterType.Sprite: + m_Settings.npotScale = ValidateAndCorrectSetting(m_Settings.npotScale, TextureImporterNPOTScale.None, nameof(m_Settings.npotScale)); + break; + } + } + + private T ValidateAndCorrectSetting(T actual, T expected, string settingName) + { + if (!actual.Equals(expected)) + { + Debug.LogWarning($"You cannot set {settingName} to {actual} for this texture type. It has been reset to {expected}."); + return expected; + } + return actual; + } + private extern TextureImporterSettings settings { get; set; } [NativeName("GetImportInspectorWarning")] diff --git a/Editor/Mono/Audio/AudioContainerWindowState.cs b/Editor/Mono/Audio/AudioContainerWindowState.cs index bf5e30fc62..df5c740271 100644 --- a/Editor/Mono/Audio/AudioContainerWindowState.cs +++ b/Editor/Mono/Audio/AudioContainerWindowState.cs @@ -341,6 +341,11 @@ void OnEditorPlayModeStateChanged(PlayModeStateChange state) void OnEditorPauseStateChanged(PauseState state) { + if (m_AudioContainer == null || m_IsSuspended) + { + return; + } + EditorPauseStateChanged?.Invoke(this, EventArgs.Empty); } diff --git a/Editor/Mono/BuildPipeline/NamedBuildTarget.cs b/Editor/Mono/BuildPipeline/NamedBuildTarget.cs index c27727ca51..f6f5eca0f8 100644 --- a/Editor/Mono/BuildPipeline/NamedBuildTarget.cs +++ b/Editor/Mono/BuildPipeline/NamedBuildTarget.cs @@ -34,6 +34,7 @@ namespace UnityEditor.Build "PS5", "EmbeddedLinux", "QNX", + "ReservedCFE" }; public static readonly NamedBuildTarget Unknown = new NamedBuildTarget(""); @@ -121,6 +122,8 @@ public static NamedBuildTarget FromBuildTargetGroup(BuildTargetGroup buildTarget return new NamedBuildTarget("GameCoreXboxOne"); case BuildTargetGroup.PS5: return new NamedBuildTarget("PS5"); + case BuildTargetGroup.ReservedCFE: + return new NamedBuildTarget("ReservedCFE"); } throw new ArgumentException($"There is no a valid NamedBuildTarget for BuildTargetGroup '{buildTargetGroup}'"); diff --git a/Editor/Mono/BuildPlayerWindow.cs b/Editor/Mono/BuildPlayerWindow.cs index 53f8908576..87cb4b8770 100644 --- a/Editor/Mono/BuildPlayerWindow.cs +++ b/Editor/Mono/BuildPlayerWindow.cs @@ -157,8 +157,7 @@ static Styles() [UsedImplicitly, RequiredByNativeCode] public static void ShowBuildPlayerWindow() { - EditorUserBuildSettings.selectedBuildTargetGroup = EditorUserBuildSettings.activeBuildTargetGroup; - GetWindow(false, "Build Settings"); + BuildPipeline.ShowBuildProfileWindow(); } internal static bool WillDrawMultiplayerBuildOptions() => drawingMultiplayerBuildOptions != null; diff --git a/Editor/Mono/BuildProfile/BuildProfileContext.cs b/Editor/Mono/BuildProfile/BuildProfileContext.cs index ff788e5525..6cd928dfc6 100644 --- a/Editor/Mono/BuildProfile/BuildProfileContext.cs +++ b/Editor/Mono/BuildProfile/BuildProfileContext.cs @@ -89,6 +89,7 @@ internal BuildProfile activeProfile Save(); EditorUserBuildSettings.SetBuildProfilePath(string.Empty); activeProfileChanged?.Invoke(prev, m_ActiveProfile); + OnActiveProfileChangedForSettingExtension(prev, null); BuildProfileModuleUtil.RequestScriptCompilation(null); return; } @@ -104,11 +105,22 @@ internal BuildProfile activeProfile Save(); EditorUserBuildSettings.SetBuildProfilePath(AssetDatabase.GetAssetPath(m_ActiveProfile)); activeProfileChanged?.Invoke(prev, m_ActiveProfile); + OnActiveProfileChangedForSettingExtension(prev, m_ActiveProfile); m_ActiveProfile.UpdateGlobalManagerPlayerSettings(); BuildProfileModuleUtil.RequestScriptCompilation(m_ActiveProfile); } } + void OnActiveProfileChangedForSettingExtension(BuildProfile previous, BuildProfile newProfile) + { + BuildTargetDiscovery.TryGetBuildTarget(EditorUserBuildSettings.activeBuildTarget, out IBuildTarget iBuildTarget); + if (iBuildTarget == null) + return; + + var settingsExtension = ModuleManager.GetEditorSettingsExtension(iBuildTarget.TargetName); + settingsExtension?.OnActiveProfileChanged(previous, newProfile); + } + internal static void HandlePendingChangesBeforeEnterPlaymode() { if (!EditorUserBuildSettings.isBuildProfileAvailable) @@ -466,8 +478,6 @@ BuildProfile GetOrCreateClassicPlatformBuildProfile(string platformId) Debug.LogError($"Build profile extension is null for module {module} and build profile {buildProfile.name}"); } - SaveBuildProfileInProject(buildProfile); - return buildProfile; } @@ -491,8 +501,6 @@ BuildProfile GetOrCreateSharedBuildProfile() // when copying the settings. EditorUserBuildSettings.CopyToBuildProfile(buildProfile); - SaveBuildProfileInProject(buildProfile); - return buildProfile; } @@ -569,6 +577,8 @@ static void CreateOrLoad() s_Instance.cachedEditorScriptingDefines = BuildDefines.GetBuildProfileScriptDefines(); BuildProfileModuleUtil.DeleteLastRunnableBuildKeyForDeletedProfiles(); + + s_Instance.OnActiveProfileChangedForSettingExtension(null, s_Instance.m_ActiveProfile); } [RequiredByNativeCode, UsedImplicitly] diff --git a/Editor/Mono/BuildTarget.cs b/Editor/Mono/BuildTarget.cs index 6a32457d95..f4d1d0f602 100644 --- a/Editor/Mono/BuildTarget.cs +++ b/Editor/Mono/BuildTarget.cs @@ -141,6 +141,7 @@ public enum BuildTarget QNX = 46, VisionOS = 47, + ReservedCFE = 48, // obsolete identifiers. We're using different values so that ToString() works. [System.Obsolete("Use iOS instead (UnityUpgradable) -> iOS", true)] diff --git a/Editor/Mono/BuildTargetDiscovery.bindings.cs b/Editor/Mono/BuildTargetDiscovery.bindings.cs index 8b670e459a..f670e2bcc6 100644 --- a/Editor/Mono/BuildTargetDiscovery.bindings.cs +++ b/Editor/Mono/BuildTargetDiscovery.bindings.cs @@ -206,6 +206,7 @@ internal static bool DoesBuildTargetSupportSinglePassStereoRendering(BuildTarget static readonly GUID s_platform_45 = new("f1d7bec2fd7f42f481c66ef512f47845"); static readonly GUID s_platform_46 = new("99ef95e1e9b048fa9628d7eed27a8646"); static readonly GUID s_platform_47 = new("53916e6f1f7240d992977ffa2322b047"); + static readonly GUID s_platform_48 = new("25a09d2ed10c42f789b61d99b4d9bf83"); static readonly GUID s_platform_100 = new("8d1e1bca926649cba89d37a4c66e8b3d"); static readonly GUID s_platform_101 = new("91d938b35f6f4798811e41f2acf9377f"); static readonly GUID s_platform_102 = new("8659dec1db6b4fac86149f99f2fa4291"); @@ -232,6 +233,7 @@ internal static bool DoesBuildTargetSupportSinglePassStereoRendering(BuildTarget s_platform_42, s_platform_43, s_platform_38, + s_platform_48, // then others s_platform_20, s_platform_21, @@ -261,6 +263,7 @@ internal static bool DoesBuildTargetSupportSinglePassStereoRendering(BuildTarget s_platform_45, s_platform_46, s_platform_47, + s_platform_48, s_platform_100, s_platform_101, s_platform_102, @@ -325,6 +328,7 @@ internal static bool DoesBuildTargetSupportSinglePassStereoRendering(BuildTarget s_platform_31, s_platform_44, s_platform_38, + s_platform_48, }; static GUID[] ExternalDownloadForBuildTarget { get; } = new GUID[] @@ -332,6 +336,7 @@ internal static bool DoesBuildTargetSupportSinglePassStereoRendering(BuildTarget s_platform_31, s_platform_43, s_platform_44, + s_platform_48, }; // Changes here should be synced with the usage of @@ -345,6 +350,7 @@ internal static bool DoesBuildTargetSupportSinglePassStereoRendering(BuildTarget s_platform_45, s_platform_46, s_platform_47, + s_platform_48, }; static Dictionary s_PlatformGUIDData = new() @@ -367,6 +373,7 @@ internal static bool DoesBuildTargetSupportSinglePassStereoRendering(BuildTarget { BuildTarget.EmbeddedLinux, s_platform_45 }, { BuildTarget.QNX, s_platform_46 }, { BuildTarget.VisionOS, s_platform_47 }, + { BuildTarget.ReservedCFE, s_platform_48 }, }; static readonly Dictionary k_PlatformBuildTargetAndSubtargetGUIDData = new() @@ -388,6 +395,7 @@ internal static bool DoesBuildTargetSupportSinglePassStereoRendering(BuildTarget { s_platform_45, (BuildTarget.EmbeddedLinux, StandaloneBuildSubtarget.Default) }, { s_platform_46, (BuildTarget.QNX, StandaloneBuildSubtarget.Default) }, { s_platform_47, (BuildTarget.VisionOS, StandaloneBuildSubtarget.Default) }, + { s_platform_48, (BuildTarget.ReservedCFE, StandaloneBuildSubtarget.Default) }, { s_platform_101, (BuildTarget.StandaloneLinux64, StandaloneBuildSubtarget.Server) }, { s_platform_100, (BuildTarget.StandaloneWindows64, StandaloneBuildSubtarget.Server) }, { s_platform_102, (BuildTarget.StandaloneOSX, StandaloneBuildSubtarget.Server) }, @@ -421,6 +429,7 @@ internal static bool DoesBuildTargetSupportSinglePassStereoRendering(BuildTarget { s_platform_44, L10n.Tr("Create your game with a comprehensive game development platform for PlayStation®5. Discover powerful creation tools to take your PlayStation game development to the next level.") }, { s_platform_45, L10n.Tr("Choose Embedded Linux, a compact version of Linux, if you are planning to build applications for embedded devices and appliances.") }, { s_platform_46, L10n.Tr("Deploy the Unity runtime to automotive and other embedded systems utilizing the Blackberry® QNX® real-time operating system.") }, + { s_platform_48, L10n.Tr("Benefit from Unity’s support for developing games and applications on this platform") }, { s_platform_100, L10n.Tr("Benefit from Unity’s support for developing games and applications on the Dedicated Windows Server platform, including publishing multiplayer games.") }, { s_platform_101, L10n.Tr("Benefit from Unity’s support for developing games and applications on the Dedicated Linux Server platform, including publishing multiplayer games.") }, { s_platform_102, L10n.Tr("Benefit from Unity’s support for developing games and applications on the Dedicated Mac Server platform, including publishing multiplayer games.") }, @@ -434,6 +443,7 @@ internal static bool DoesBuildTargetSupportSinglePassStereoRendering(BuildTarget { s_platform_42, L10n.Tr("Register as an Xbox developer / https://www.xbox.com/en-US/developers/id ") }, { s_platform_43, L10n.Tr("Register as an Xbox developer / https://www.xbox.com/en-US/developers/id ") }, { s_platform_44, L10n.Tr("Register as a PlayStation developer / https://partners.playstation.net/ ") }, + { s_platform_48, L10n.Tr("More details coming soon") }, }; static Dictionary s_PlatformInstructions = new() @@ -455,6 +465,7 @@ internal static bool DoesBuildTargetSupportSinglePassStereoRendering(BuildTarget { s_platform_45, L10n.Tr("As the Embedded Linux platform for Unity is not yet available to download from the Unity website, contact your Account Manager or the Unity Sales team to get access.") }, { s_platform_46, L10n.Tr("As the QNX platform for Unity is not yet available to download from the Unity website, contact your Account Manager or the Unity Sales team to get access.") }, { s_platform_47, L10n.Tr("*standard install form hub") }, + { s_platform_48, L10n.Tr("This platform is not available to download from the Unity website, contact the platform holder directly to learn more.") }, { s_platform_100, L10n.Tr("*standard install form hub") }, { s_platform_101, L10n.Tr("*standard install form hub") }, { s_platform_102, L10n.Tr("*standard install form hub") }, @@ -480,6 +491,7 @@ internal static bool DoesBuildTargetSupportSinglePassStereoRendering(BuildTarget { s_platform_45, "Embedded Linux" }, { s_platform_46, "QNX®" }, { s_platform_47, "visionOS" }, + { s_platform_48, "ReservedCFE" }, { s_platform_100, "Windows Server" }, { s_platform_101, "Linux Server" }, { s_platform_102, "macOS Server" }, @@ -505,6 +517,7 @@ internal static bool DoesBuildTargetSupportSinglePassStereoRendering(BuildTarget { s_platform_45, "BuildSettings.EmbeddedLinux" }, { s_platform_46, "BuildSettings.QNX" }, { s_platform_47, "BuildSettings.visionOS" }, + { s_platform_48, "BuildSettings.DedicatedServer" }, { s_platform_100, "BuildSettings.DedicatedServer" }, { s_platform_101, "BuildSettings.DedicatedServer" }, { s_platform_102, "BuildSettings.DedicatedServer" }, diff --git a/Editor/Mono/BuildTargetGroup.cs b/Editor/Mono/BuildTargetGroup.cs index 97955a23e8..0ed966e2bb 100644 --- a/Editor/Mono/BuildTargetGroup.cs +++ b/Editor/Mono/BuildTargetGroup.cs @@ -117,5 +117,6 @@ public enum BuildTargetGroup QNX = 35, VisionOS = 36, + ReservedCFE = 37, } } diff --git a/Editor/Mono/ContainerWindow.cs b/Editor/Mono/ContainerWindow.cs index 33ab287277..2b30bbef67 100644 --- a/Editor/Mono/ContainerWindow.cs +++ b/Editor/Mono/ContainerWindow.cs @@ -160,8 +160,8 @@ internal void ShowPopupWithMode(ShowMode mode, bool giveFocus) } } - private static readonly Color lightSkinColor = new Color(0.541f, 0.541f, 0.541f, 1.0f); - private static readonly Color darkSkinColor = new Color(0.098f, 0.098f, 0.098f, 1.0f); + private static readonly Color lightSkinColor = new Color(0.941f, 0.941f, 0.941f, 1.0f); + private static readonly Color darkSkinColor = new Color(0.078f, 0.0784f, 0.0784f, 1.0f); static Color skinBackgroundColor => EditorGUIUtility.isProSkin ? darkSkinColor : lightSkinColor; // Show the editor window. diff --git a/Editor/Mono/EditorGUI.cs b/Editor/Mono/EditorGUI.cs index 8f506043f6..931eb190e4 100644 --- a/Editor/Mono/EditorGUI.cs +++ b/Editor/Mono/EditorGUI.cs @@ -5639,7 +5639,7 @@ private static Color DoColorField(Rect position, int id, Color value, bool showE ColorPicker.Show(GUIView.current, value, showAlpha, hdr); GUIUtility.ExitGUI(); } - else if (evt.modifiers == EventModifiers.Control) + else if (evt.modifiers == EventModifiers.Control && GUIUtility.keyboardControl == id) { if (evt.keyCode == KeyCode.C) { diff --git a/Editor/Mono/EditorGUIUtility.cs b/Editor/Mono/EditorGUIUtility.cs index 80f1beb142..f9a5feb143 100644 --- a/Editor/Mono/EditorGUIUtility.cs +++ b/Editor/Mono/EditorGUIUtility.cs @@ -351,6 +351,50 @@ 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. /// diff --git a/Editor/Mono/EditorUserSettings.bindings.cs b/Editor/Mono/EditorUserSettings.bindings.cs index 5535c80a7b..90e2543a46 100644 --- a/Editor/Mono/EditorUserSettings.bindings.cs +++ b/Editor/Mono/EditorUserSettings.bindings.cs @@ -61,6 +61,9 @@ public static string GetConfigValue(string name) [NativeProperty("VCAllowAsyncUpdate")] public static extern bool allowAsyncStatusUpdate { get; set; } + [NativeProperty("VCScanLocalPackagesOnConnect")] + public static extern bool scanLocalPackagesOnConnect { get; set; } + [NativeProperty("VCDebugCmd")] internal static extern bool DebugCmd { get; set; } diff --git a/Editor/Mono/GI/InputExtraction.bindings.cs b/Editor/Mono/GI/InputExtraction.bindings.cs index 3ba0f4c29f..25132d0436 100644 --- a/Editor/Mono/GI/InputExtraction.bindings.cs +++ b/Editor/Mono/GI/InputExtraction.bindings.cs @@ -68,7 +68,7 @@ internal static class BindingsMarshaller } } - public static extern bool ExtractFromScene(string outputFolderPath, LightBaker.BakeInput input, SourceMap map); + public static extern bool ExtractFromScene(string outputFolderPath, LightBaker.BakeInput input, LightBaker.LightmapRequests lightmapRequests, LightBaker.LightProbeRequests lightProbeRequests, SourceMap map); public static extern int[] ComputeOcclusionLightIndicesFromBakeInput(LightBaker.BakeInput bakeInput, UnityEngine.Vector3[] probePositions, uint maxLightsPerProbe); @@ -227,7 +227,7 @@ public static string LogSceneSettings(LightBaker.BakeInput bakeInput) return message; } - public static string LogScene(LightBaker.BakeInput bakeInput, SourceMap map) + public static string LogScene(LightBaker.BakeInput bakeInput, LightBaker.LightmapRequests lightmapRequests, LightBaker.LightProbeRequests lightProbeRequests, SourceMap map) { if (bakeInput is null) return string.Empty; @@ -259,12 +259,12 @@ public static string LogScene(LightBaker.BakeInput bakeInput, SourceMap map) } message += LogSceneCookies(bakeInput); message += LogSceneLights(bakeInput); - message += $" lightmap count\t: {bakeInput.lightmapCount}\n"; - for (int i = 0; i < bakeInput.lightmapCount; ++i) + message += $" lightmap count\t: {lightmapRequests.lightmapCount}\n"; + for (int i = 0; i < lightmapRequests.lightmapCount; ++i) { message += $" Lightmap [{i}]:\n"; - message += $" resolution\t\t: {bakeInput.lightmapResolution((uint)i).width} x {bakeInput.lightmapResolution((uint)i).height}\n"; - message += $" instance count\t: {bakeInput.lightmapInstanceCount((uint)i)}\n"; + message += $" resolution\t\t: {lightmapRequests.lightmapResolution((uint)i).width} x {lightmapRequests.lightmapResolution((uint)i).height}\n"; + message += $" instance count\t: {lightmapRequests.lightmapInstanceCount((uint)i)}\n"; } return message; } diff --git a/Editor/Mono/GI/InputExtraction.cs b/Editor/Mono/GI/InputExtraction.cs index 2ac3896869..6c6f1b5add 100644 --- a/Editor/Mono/GI/InputExtraction.cs +++ b/Editor/Mono/GI/InputExtraction.cs @@ -3,39 +3,53 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using UnityEditor.LightBaking; +using static UnityEditor.LightBaking.LightBaker; namespace UnityEngine.LightTransport { public static class InputExtraction { - // Completely opaque object in the public API. + // Completely opaque in the public API, this effectively hides internal LightBaker details. public class BakeInput { - internal BakeInput(UnityEditor.LightBaking.LightBaker.BakeInput editorBakeInput) + internal BakeInput(LightBaker.BakeInput editorBakeInput) { bakeInput = editorBakeInput; } - internal UnityEditor.LightBaking.LightBaker.BakeInput bakeInput { get; } + internal LightBaker.BakeInput bakeInput { get; } + + // Requests are not exposed in the public API, but we need them in LightBaker.PopulateWorld(). Going forward, requests will be split from the bake input in the public API as well. + internal LightmapRequests lightmapRequests { get; set; } + internal LightProbeRequests lightProbeRequests { get; set; } } public static bool ExtractFromScene(out BakeInput bakeInput) { const string outputFolderPath = "unused"; // We are not using disk IO. - UnityEditor.LightBaking.LightBaker.BakeInput input = new(); + LightBaker.BakeInput lightBakerBakeInput = new(); + LightBaker.LightmapRequests lightBakerLightmapRequests = new(); + LightBaker.LightProbeRequests lightBakerlightProbeRequests = new(); UnityEditor.LightBaking.InputExtraction.SourceMap map = new(); - bool result = UnityEditor.LightBaking.InputExtraction.ExtractFromScene(outputFolderPath, input, map); - bakeInput = new BakeInput(input); + bool result = UnityEditor.LightBaking.InputExtraction.ExtractFromScene(outputFolderPath, lightBakerBakeInput, lightBakerLightmapRequests, lightBakerlightProbeRequests, map); + bakeInput = new BakeInput(lightBakerBakeInput) + { + lightmapRequests = lightBakerLightmapRequests, + lightProbeRequests = lightBakerlightProbeRequests + }; + return result; } public static bool PopulateWorld(BakeInput bakeInput, BakeProgressState progress, IDeviceContext context, IWorld world) { - UnityEditor.LightBaking.LightBaker.Result result = UnityEditor.LightBaking.LightBaker.PopulateWorld(bakeInput.bakeInput, progress, context, world); - return result.type == UnityEditor.LightBaking.LightBaker.ResultType.Success; + LightBaker.Result result = LightBaker.PopulateWorld(bakeInput.bakeInput, bakeInput.lightmapRequests, bakeInput.lightProbeRequests, progress, context, world); + return result.type == LightBaker.ResultType.Success; } + // Note that in the non-public API, serialization of bake input does not imply serialization of requests. internal static bool SerializeBakeInput(string path, InputExtraction.BakeInput bakeInput) => LightBaker.Serialize(path, bakeInput.bakeInput); + // Note that in the non-public API, deserialization of bake input does not imply deserialization of requests. internal static bool DeserializeBakeInput(string path, out InputExtraction.BakeInput bakeInput) { UnityEditor.LightBaking.LightBaker.BakeInput lightBakerBakeInput = new(); diff --git a/Editor/Mono/GI/LightBaker.bindings.cs b/Editor/Mono/GI/LightBaker.bindings.cs index 535883fb65..e8a3797e51 100644 --- a/Editor/Mono/GI/LightBaker.bindings.cs +++ b/Editor/Mono/GI/LightBaker.bindings.cs @@ -148,6 +148,7 @@ public struct LightmapRequest public uint lightmapCount; public TilingMode tilingMode; public string outputFolderPath; + public float pushoff; }; public struct Resolution { @@ -438,10 +439,6 @@ public void SetLightingSettings(LightingSettings lightingSettings) Internal_SetLightingSettings(lightingSettings); } - extern uint Internal_LightmapWidth(uint index); - extern uint Internal_LightmapHeight(uint index); - extern uint Internal_InstanceCount(uint lightmapIndex); - public extern uint instanceCount { get; } extern Instance Internal_Instance(uint index); public Instance instance(uint index) @@ -469,13 +466,6 @@ public Terrain GetTerrain(uint index) return terrain; } - public uint lightmapInstanceCount(uint index) - { - if (index >= lightmapCount) - throw new ArgumentException($"index must be between 0 and {lightmapCount - 1}, but was {index}"); - return Internal_InstanceCount(index); - } - public extern Vector2[] GetUV1VertexData(uint meshIndex); public extern uint meshCount { get; } @@ -613,6 +603,13 @@ public TextureProperties GetTransmissiveTextureProperties(uint index) throw new ArgumentException($"index must be between 0 and {transmissiveTexturePropertiesCount - 1}, but was {index}"); return Internal_GetTransmissiveTextureProperties(index); } + extern void Internal_SetTransmissiveTextureProperties(uint index, TextureProperties textureProperties); + public void SetTransmissiveTextureProperties(uint index, TextureProperties textureProperties) + { + if (index >= transmissiveTexturePropertiesCount) + throw new ArgumentException($"index must be between 0 and {transmissiveTexturePropertiesCount - 1}, but was {index}"); + Internal_SetTransmissiveTextureProperties(index, textureProperties); + } public extern uint GetCookieCount(); extern CookieData Internal_GetCookieData(uint index); @@ -629,47 +626,147 @@ public void SetCookieData(uint index, CookieData cookieData) throw new ArgumentException($"index must be between 0 and {GetCookieCount() - 1}, but was {index}"); Internal_SetCookieData(index, cookieData); } + public extern void SetEnvironment(Vector4 color); + public extern void SetEnvironmentFromTextures(TextureData posX, TextureData negX, TextureData posY, TextureData negY, TextureData posZ, TextureData negZ); + public extern TextureData GetEnvironmentCubeTexture(); - public extern uint lightmapCount { get; } - public Resolution lightmapResolution(uint index) + internal static class BindingsMarshaller { - if (index >= lightmapCount) - throw new ArgumentException($"index must be between 0 and {lightmapCount - 1}, but was {index}"); - Resolution resolution; - resolution.width = Internal_LightmapWidth(index); - resolution.height = Internal_LightmapHeight(index); - return resolution; + public static IntPtr ConvertToNative(BakeInput bakeInput) => bakeInput._ptr; } - public extern uint lightProbeCount { get; } + public extern bool CheckIntegrity(); + } - public extern void SetLightmapResolution(Resolution resolution); - public extern void SetEnvironment(Vector4 color); - public extern void SetEnvironmentFromTextures(TextureData posX, TextureData negX, TextureData posY, TextureData negY, TextureData posZ, TextureData negZ); - public extern TextureData GetEnvironmentCubeTexture(); + [RequiredByNativeCode] + [StructLayout(LayoutKind.Sequential)] + public class LightProbeRequests : IDisposable + { + private IntPtr _ptr; + private readonly bool _ownsPtr; - public extern ProbeRequest[] GetProbeRequests(); - public extern void SetLightProbeRequests(ProbeRequest[] requests); - public extern LightmapRequest[] GetLightmapRequests(); - public extern void SetLightmapRequests(LightmapRequest[] requests); + public LightProbeRequests() + { + _ptr = Internal_Create(); + _ownsPtr = true; + } + public LightProbeRequests(IntPtr ptr) + { + _ptr = ptr; + _ownsPtr = false; + } + ~LightProbeRequests() + { + Destroy(); + } - public void SetProbePositions(Vector3[] positions) + public void Dispose() { - SetProbePositions(positions.AsSpan()); + Destroy(); + GC.SuppressFinalize(this); + } + + void Destroy() + { + if (_ownsPtr && _ptr != IntPtr.Zero) + { + Internal_Destroy(_ptr); + _ptr = IntPtr.Zero; + } } - public extern void SetProbePositions(ReadOnlySpan positions); + + public extern ulong GetByteSize(); + static extern IntPtr Internal_Create(); + [NativeMethod(IsThreadSafe = true)] + static extern void Internal_Destroy(IntPtr ptr); public void SetIntegrationRadii(float[] positions) { SetIntegrationRadii(positions.AsSpan()); } public extern void SetIntegrationRadii(ReadOnlySpan positions); - public extern Vector3[] GetProbePositions(); public extern float[] GetIntegrationRadii(); + public extern uint lightProbeCount { get; } + public extern ProbeRequest[] GetProbeRequests(); + public extern void SetLightProbeRequests(ProbeRequest[] requests); internal static class BindingsMarshaller { - public static IntPtr ConvertToNative(BakeInput bakeInput) => bakeInput._ptr; + public static IntPtr ConvertToNative(LightProbeRequests lightProbeRequests) => lightProbeRequests._ptr; + } + public extern bool CheckIntegrity(); + } + + [RequiredByNativeCode] + [StructLayout(LayoutKind.Sequential)] + public class LightmapRequests : IDisposable + { + private IntPtr _ptr; + private readonly bool _ownsPtr; + + public LightmapRequests() + { + _ptr = Internal_Create(); + _ownsPtr = true; + } + public LightmapRequests(IntPtr ptr) + { + _ptr = ptr; + _ownsPtr = false; + } + ~LightmapRequests() + { + Destroy(); + } + + public void Dispose() + { + Destroy(); + GC.SuppressFinalize(this); + } + + void Destroy() + { + if (_ownsPtr && _ptr != IntPtr.Zero) + { + Internal_Destroy(_ptr); + _ptr = IntPtr.Zero; + } + } + + public extern ulong GetByteSize(); + static extern IntPtr Internal_Create(); + [NativeMethod(IsThreadSafe = true)] + static extern void Internal_Destroy(IntPtr ptr); + + public extern LightmapRequest[] GetLightmapRequests(); + public extern void SetLightmapRequests(LightmapRequest[] requests); + + public uint lightmapInstanceCount(uint index) + { + if (index >= lightmapCount) + throw new ArgumentException($"index must be between 0 and {lightmapCount - 1}, but was {index}"); + return Internal_InstanceCount(index); + } + + public extern uint lightmapCount { get; } + extern uint Internal_LightmapWidth(uint index); + extern uint Internal_LightmapHeight(uint index); + extern uint Internal_InstanceCount(uint lightmapIndex); + public extern void SetLightmapResolution(Resolution resolution); + public Resolution lightmapResolution(uint index) + { + if (index >= lightmapCount) + throw new ArgumentException($"index must be between 0 and {lightmapCount - 1}, but was {index}"); + Resolution resolution; + resolution.width = Internal_LightmapWidth(index); + resolution.height = Internal_LightmapHeight(index); + return resolution; + } + + internal static class BindingsMarshaller + { + public static IntPtr ConvertToNative(LightmapRequests lightmapRequests) => lightmapRequests._ptr; } public extern bool CheckIntegrity(); } @@ -734,14 +831,14 @@ internal static class BindingsMarshaller } } - public static Result PopulateWorld(BakeInput bakeInput, BakeProgressState progress, + public static Result PopulateWorld(BakeInput bakeInput, LightmapRequests lightmapRequests, LightProbeRequests lightProbeRequests, BakeProgressState progress, UnityEngine.LightTransport.IDeviceContext context, UnityEngine.LightTransport.IWorld world) { Result result = new (); if (context is RadeonRaysContext radeonRaysContext) { IntegrationContext integrationContext = new (); - result = PopulateWorldRadeonRays(bakeInput, progress, radeonRaysContext, integrationContext); + result = PopulateWorldRadeonRays(bakeInput, lightmapRequests, lightProbeRequests, progress, radeonRaysContext, integrationContext); Debug.Assert(world is RadeonRaysWorld); var rrWorld = world as RadeonRaysWorld; rrWorld.SetIntegrationContext(integrationContext); @@ -749,7 +846,7 @@ public static Result PopulateWorld(BakeInput bakeInput, BakeProgressState progre else if (context is WintermuteContext wintermuteContext) { IntegrationContext integrationContext = new (); - result = PopulateWorldWintermute(bakeInput, progress, wintermuteContext, integrationContext); + result = PopulateWorldWintermute(bakeInput, lightmapRequests, lightProbeRequests, progress, wintermuteContext, integrationContext); Debug.Assert(world is WintermuteWorld); var wmWorld = world as WintermuteWorld; wmWorld.SetIntegrationContext(integrationContext); @@ -758,14 +855,18 @@ public static Result PopulateWorld(BakeInput bakeInput, BakeProgressState progre } public static extern bool Serialize(string path, BakeInput input); + public static extern bool SerializeLightmapRequests(string path, LightmapRequests lightmapRequests); + public static extern bool SerializeLightProbeRequests(string path, LightProbeRequests lightProbeRequests); public static extern bool Deserialize(string path, BakeInput input); + public static extern bool DeserializeLightmapRequests(string path, LightmapRequests lightmapRequests); + public static extern bool DeserializeLightProbeRequests(string path, LightProbeRequests lightProbeRequests); - public static extern Result Bake(BakeInput input, DeviceSettings deviceSettings); - public static extern Result BakeOutOfProcess(BakeInput input, DeviceSettings deviceSettings); - public static extern Result BakeInEditorWorkerProcess(BakeInput input, DeviceSettings deviceSettings); + public static extern Result Bake(BakeInput input, LightmapRequests lightmapRequest, LightProbeRequests lightProbeRequests, DeviceSettings deviceSettings); + public static extern Result BakeOutOfProcess(BakeInput input, LightmapRequests lightmapRequest, LightProbeRequests lightProbeRequests, DeviceSettings deviceSettings); + public static extern Result BakeInEditorWorkerProcess(BakeInput input, LightmapRequests lightmapRequest, LightProbeRequests lightProbeRequests, DeviceSettings deviceSettings); public static extern bool ReportResultToParentProcess(Result result, ExternalProcessConnection connection); [NativeMethod(IsThreadSafe = true)] public static extern bool ReportProgressToParentProcess(float progress, ExternalProcessConnection connection); - public static extern ulong ConvertExpectedWorkToWorkSteps(BakeInput bakeInput, ulong sampleCountPerLightmapTexel, ulong sampleCountPerProbe); + public static extern ulong ConvertExpectedWorkToWorkSteps(BakeInput bakeInput, LightmapRequests lightmapRequests, LightProbeRequests lightProbeRequests, ulong sampleCountPerLightmapTexel, ulong sampleCountPerProbe); } } diff --git a/Editor/Mono/GI/Lightmapping.bindings.cs b/Editor/Mono/GI/Lightmapping.bindings.cs index 210abf029b..d0c549a00d 100644 --- a/Editor/Mono/GI/Lightmapping.bindings.cs +++ b/Editor/Mono/GI/Lightmapping.bindings.cs @@ -346,15 +346,17 @@ internal static void Internal_CallOnWroteLightingDataAsset() // This event is fired when BakeInput has been populated, but before passing it to Bake(). // Do not store and access BakeInput beyond the call-back. - internal static event Action createdBakeInput; + internal static event Action createdBakeInput; - internal static void Internal_CallOnCreatedBakeInput(IntPtr p_BakeInput, IntPtr p_SourceMap) + internal static void Internal_CallOnCreatedBakeInput(IntPtr p_BakeInput, IntPtr p_LightmapRequests, IntPtr LightProbeRequests, IntPtr p_SourceMap) { if (createdBakeInput != null) { using var bakeInput = new LightBaker.BakeInput(p_BakeInput); + using var lightmapRequests = new LightBaker.LightmapRequests(p_LightmapRequests); + using var lightProbeRequests = new LightBaker.LightProbeRequests(LightProbeRequests); using var sourceMap = new InputExtraction.SourceMap(p_SourceMap); - createdBakeInput(bakeInput, sourceMap); + createdBakeInput(bakeInput, lightmapRequests, lightProbeRequests, sourceMap); } } diff --git a/Editor/Mono/GI/ProgressState.bindings.cs b/Editor/Mono/GI/ProgressState.bindings.cs index a7bfbff527..eb7ddb8c9e 100644 --- a/Editor/Mono/GI/ProgressState.bindings.cs +++ b/Editor/Mono/GI/ProgressState.bindings.cs @@ -57,5 +57,14 @@ internal static class BindingsMarshaller [NativeMethod(IsThreadSafe = true)] public extern float Progress(); + + [NativeMethod(IsThreadSafe = true)] + public extern void SetTotalWorkSteps(UInt64 total); + + [NativeMethod(IsThreadSafe = true)] + public extern void IncrementCompletedWorkSteps(UInt64 steps); + + [NativeMethod(IsThreadSafe = true)] + public extern bool WasCancelled(); } } diff --git a/Editor/Mono/GI/RadeonRaysLightBaker.bindings.cs b/Editor/Mono/GI/RadeonRaysLightBaker.bindings.cs index 1b8d4933d8..4f4769cadc 100644 --- a/Editor/Mono/GI/RadeonRaysLightBaker.bindings.cs +++ b/Editor/Mono/GI/RadeonRaysLightBaker.bindings.cs @@ -10,7 +10,7 @@ namespace UnityEditor.LightBaking internal static partial class LightBaker { [NativeMethod(IsThreadSafe = true)] - internal static extern Result PopulateWorldRadeonRays(BakeInput bakeInput, UnityEngine.LightTransport.BakeProgressState progress, + internal static extern Result PopulateWorldRadeonRays(BakeInput bakeInput, LightmapRequests lightmapRequests, LightProbeRequests lightProbeRequests, UnityEngine.LightTransport.BakeProgressState progress, UnityEngine.LightTransport.RadeonRaysContext context, UnityEngine.LightTransport.IntegrationContext world); [NativeMethod(IsThreadSafe = true)] diff --git a/Editor/Mono/GI/UnityComputeBake.cs b/Editor/Mono/GI/UnityComputeBake.cs index 0ff334a6c5..5d8ff17e3a 100644 --- a/Editor/Mono/GI/UnityComputeBake.cs +++ b/Editor/Mono/GI/UnityComputeBake.cs @@ -15,9 +15,17 @@ namespace UnityEditor.LightBaking { internal static class UnityComputeBake { - // TODO(pema.malling): Handle reporting back progress https://jira.unity3d.com/browse/LIGHT-1754 [RequiredByNativeCode] - internal static bool Bake(string bakeInputPath, string bakeOutputFolderPath) + internal static bool BakeWithDummyProgress(string bakeInputPath, string lightmapRequestsPath, string lightProbeRequestsPath, string bakeOutputFolderPath) + { + using BakeProgressState dummyProgressState = new(); + bool success = Bake(bakeInputPath, lightmapRequestsPath, lightProbeRequestsPath, bakeOutputFolderPath, dummyProgressState); + + return success; + } + + [RequiredByNativeCode] + internal static bool Bake(string bakeInputPath, string lightmapRequestsPath, string lightProbeRequestsPath, string bakeOutputFolderPath, BakeProgressState progressState) { Type strangler = Type.GetType("UnityEngine.PathTracing.LightBakerBridge.LightBakerStrangler, Unity.PathTracing.Runtime"); if (strangler == null) @@ -27,7 +35,8 @@ internal static bool Bake(string bakeInputPath, string bakeOutputFolderPath) if (bakeMethod == null) return false; - return (bool)bakeMethod.Invoke(null, new object[] { bakeInputPath, bakeOutputFolderPath }); + var bakeFunc = (Func)Delegate.CreateDelegate(typeof(Func), bakeMethod); + return bakeFunc(bakeInputPath, lightmapRequestsPath, lightProbeRequestsPath, bakeOutputFolderPath, progressState); } [RequiredByNativeCode] @@ -36,11 +45,7 @@ internal static bool BakeViaCommandLineParameters() const string lightBakerWorkerProcess = "[LightBaker worker process] "; using ExternalProcessConnection bakeResultConnection = CreateConnectionToParentProcess("-bakePortNumber"); - if (bakeResultConnection == default(ExternalProcessConnection)) - return false; using ExternalProcessConnection progressConnection = CreateConnectionToParentProcess("-progressPortNumber"); - if (progressConnection == default(ExternalProcessConnection)) - return false; try { @@ -51,21 +56,29 @@ internal static bool BakeViaCommandLineParameters() if (string.IsNullOrEmpty(bakeInputPath)) return ReportResult(new Result { type = ResultType.InvalidInput, message = "No bake input path was passed as an argument." }, bakeResultConnection); + string lightmapRequestsPath = TryFindArgument("-lightmapRequests"); + if (string.IsNullOrEmpty(lightmapRequestsPath)) + return ReportResult(new Result { type = ResultType.InvalidInput, message = "No lightmap requests path was passed as an argument." }, bakeResultConnection); + + string lightProbeRequestsPath = TryFindArgument("-lightProbeRequests"); + if (string.IsNullOrEmpty(lightProbeRequestsPath)) + return ReportResult(new Result { type = ResultType.InvalidInput, message = "No light probe requests path was passed as an argument." }, bakeResultConnection); + string bakeOutputFolderPath = TryFindArgument("-bakeOutputFolderPath"); if (string.IsNullOrEmpty(bakeOutputFolderPath)) return ReportResult(new Result { type = ResultType.InvalidInput, message = "No bake output folder path was passed as an argument." }, bakeResultConnection); // Prepare to capture progress work steps. - BakeProgressState progress = new (); + using BakeProgressState progressState = new (); // Prepare to report progress. using CancellationTokenSource progressReporterTokenSource = new CancellationTokenSource(); - Thread progressReporterThread = new (() => ProgressReporterThreadFunction(progress, progressReporterTokenSource.Token, progressConnection)); + Thread progressReporterThread = new (() => ProgressReporterThreadFunction(progressState, progressReporterTokenSource.Token, progressConnection)); progressReporterThread.Start(); Result result = new () { - type = Bake(bakeInputPath, bakeOutputFolderPath) ? ResultType.Success : ResultType.JobFailed + type = Bake(bakeInputPath, lightmapRequestsPath, lightProbeRequestsPath, bakeOutputFolderPath, progressState) ? ResultType.Success : ResultType.JobFailed }; // Report the result after cancel of the progress reporter when we are finished baking. @@ -88,7 +101,7 @@ static ExternalProcessConnection CreateConnectionToParentProcess(string portNumb { string portNumberArgumentValue = TryFindArgument(portNumberArgument); bool portNumberWasPassed = !string.IsNullOrEmpty(portNumberArgumentValue); - Assert.IsTrue(portNumberWasPassed, $"{lightBakerWorkerProcess}No '{portNumberArgument}' was passed as an argument, cannot report to the parent process."); + Debug.Log($"{lightBakerWorkerProcess}No '{portNumberArgument}' was passed as an argument, will not report to the parent process."); if (!portNumberWasPassed) return null; bool portNumberWasParsed = int.TryParse(portNumberArgumentValue, out int portNumber); @@ -105,6 +118,8 @@ static ExternalProcessConnection CreateConnectionToParentProcess(string portNumb static void ProgressReporterThreadFunction(BakeProgressState bakeProgressState, CancellationToken cancelToken, ExternalProcessConnection connection) { + if (connection == null) + return; const int waitBetweenProgressReportsMs = 100; while (!cancelToken.IsCancellationRequested) { @@ -127,6 +142,8 @@ static string TryFindArgument(string argument) static bool ReportResult(Result result, ExternalProcessConnection connection) { + if (connection == null) + return true; if (result.type == ResultType.Success) if (string.IsNullOrEmpty(result.message)) result.message = "Success."; diff --git a/Editor/Mono/GI/WintermuteLightBaker.bindings.cs b/Editor/Mono/GI/WintermuteLightBaker.bindings.cs index 2e0e0f7586..f12229a2e0 100644 --- a/Editor/Mono/GI/WintermuteLightBaker.bindings.cs +++ b/Editor/Mono/GI/WintermuteLightBaker.bindings.cs @@ -10,7 +10,7 @@ namespace UnityEditor.LightBaking internal static partial class LightBaker { [NativeMethod(IsThreadSafe = true)] - internal static extern Result PopulateWorldWintermute(BakeInput bakeInput, UnityEngine.LightTransport.BakeProgressState progress, + internal static extern Result PopulateWorldWintermute(BakeInput bakeInput, LightmapRequests lightmapRequests, LightProbeRequests lightProbeRequests, UnityEngine.LightTransport.BakeProgressState progress, UnityEngine.LightTransport.WintermuteContext context, UnityEngine.LightTransport.IntegrationContext world); [NativeMethod(IsThreadSafe = true)] diff --git a/Editor/Mono/GUI/DockArea.cs b/Editor/Mono/GUI/DockArea.cs index 93f1f7f0fa..27c18c4f0b 100644 --- a/Editor/Mono/GUI/DockArea.cs +++ b/Editor/Mono/GUI/DockArea.cs @@ -37,8 +37,6 @@ private static class Styles public static readonly GUIStyle background = "dockarea"; public static readonly float tabMinWidth = tab.GetFloat(StyleCatalogKeyword.minWidth, 50.0f); public static readonly float tabMaxWidth = tab.GetFloat(StyleCatalogKeyword.maxWidth, 150.0f); - public static readonly float tabWidthPadding = tab.GetFloat(StyleCatalogKeyword.paddingRight); - public static readonly float tabDragWidth = EditorResources.GetStyle("tab-drag").GetFloat(StyleCatalogKeyword.width, 100.0f); public static readonly GUIStyle tabScrollerPrevButton = new GUIStyle("dragtab scroller prev"); @@ -54,7 +52,7 @@ private static class Styles } internal const int kFloatingWindowTopBorderWidth = 2; - internal const float kTabHeight = 19; // This constant is duplicated in native code. See ContainerWindow.cpp. + internal const float kTabHeight = 25 - 1; // This constant is duplicated in native code. See ContainerWindow.cpp. (Tab height -1) internal const float kDockHeight = 39; internal const float kSideBorders = 1.0f; internal const float kBottomBorders = 2.0f; @@ -725,9 +723,10 @@ void AddTabToHere(object userData) private float GetTabWidth(GUIStyle tabStyle, EditorWindow tabWindow) { - float minWidth, expectedWidth; - tabStyle.CalcMinMaxWidth(tabWindow.titleContent, out minWidth, out expectedWidth); - return Mathf.Max(Mathf.Min(expectedWidth, Styles.tabMaxWidth), Styles.tabMinWidth) + Styles.tabWidthPadding; + var expectedWidth = tabStyle.CalcSize(tabWindow.titleContent).x; + + return Mathf.Max(Mathf.Min(expectedWidth, Styles.tabMaxWidth), + Styles.tabMinWidth); } private float GetTabWidth(GUIStyle tabStyle, int tabIndex) diff --git a/Editor/Mono/GUI/MainView.cs b/Editor/Mono/GUI/MainView.cs index 99fdd37241..3ae01fa8b8 100644 --- a/Editor/Mono/GUI/MainView.cs +++ b/Editor/Mono/GUI/MainView.cs @@ -8,7 +8,7 @@ namespace UnityEditor { internal class MainView : View, ICleanuppable { - internal const float kToolbarHeight = 30; + internal const float kToolbarHeight = Toolbar.k_ToolbarHeight; internal const float kStatusbarHeight = 20; private static readonly Vector2 kMinSize = new Vector2(875, 300); diff --git a/Editor/Mono/GUI/PackageExport.cs b/Editor/Mono/GUI/PackageExport.cs index 11ec805cf2..d9e72fa2e4 100644 --- a/Editor/Mono/GUI/PackageExport.cs +++ b/Editor/Mono/GUI/PackageExport.cs @@ -15,24 +15,24 @@ namespace UnityEditor { internal class PackageExport : EditorWindow { - [SerializeField] private ExportPackageItem[] m_ExportPackageItems; - [SerializeField] private bool m_IncludeDependencies = true; - [SerializeField] private TreeViewState m_TreeViewState; - [NonSerialized] private PackageExportTreeView m_Tree; - [NonSerialized] private bool m_DidScheduleUpdate = false; + [SerializeField] private ExportPackageItem[] m_ExportPackageItems; + [SerializeField] private bool m_IncludeDependencies = true; + [SerializeField] private TreeViewState m_TreeViewState; + [NonSerialized] private PackageExportTreeView m_Tree; + [NonSerialized] private bool m_DidScheduleUpdate = false; public ExportPackageItem[] items { get { return m_ExportPackageItems; } } internal static class Styles { - public static GUIStyle title = "LargeBoldLabel"; - public static GUIStyle bottomBarBg = "ProjectBrowserBottomBarBg"; - public static GUIStyle topBarBg = "OT TopBar"; - public static GUIStyle loadingTextStyle = "CenteredLabel"; - public static GUIContent allText = EditorGUIUtility.TrTextContent("All"); - public static GUIContent noneText = EditorGUIUtility.TrTextContent("None"); + public static GUIStyle title = "LargeBoldLabel"; + public static GUIStyle bottomBarBg = "ProjectBrowserBottomBarBg"; + public static GUIStyle topBarBg = "OT TopBar"; + public static GUIStyle loadingTextStyle = "CenteredLabel"; + public static GUIContent allText = EditorGUIUtility.TrTextContent("All"); + public static GUIContent noneText = EditorGUIUtility.TrTextContent("None"); public static GUIContent includeDependenciesText = EditorGUIUtility.TrTextContent("Include dependencies"); - public static GUIContent header = EditorGUIUtility.TrTextContent("Items to Export"); + public static GUIContent header = EditorGUIUtility.TrTextContent("Items to Export"); } public PackageExport() @@ -158,17 +158,21 @@ void TopButtonsArea() GUILayout.BeginHorizontal(); GUILayout.Space(10); + GUI.enabled = m_Tree != null ? !m_Tree.isAllItemsEnabled : true; if (GUILayout.Button(Styles.allText, GUILayout.Width(50))) { m_Tree.SetAllEnabled(PackageExportTreeView.EnabledState.All); SendAnalyticsEvent("selectAll"); } + GUI.enabled = true; + GUI.enabled = m_Tree != null ? m_Tree.isAnyItemEnabled : true; if (GUILayout.Button(Styles.noneText, GUILayout.Width(50))) { m_Tree.SetAllEnabled(PackageExportTreeView.EnabledState.None); SendAnalyticsEvent("selectNone"); } + GUI.enabled = true; GUILayout.Space(10); GUILayout.EndHorizontal(); @@ -199,6 +203,7 @@ void BottomArea() GUILayout.FlexibleSpace(); + GUI.enabled = m_Tree?.isAnyItemEnabled == true; if (GUILayout.Button(EditorGUIUtility.TrTextContent("Export..."))) { string invalidChars = EditorUtility.GetInvalidFilenameChars(); @@ -213,6 +218,7 @@ void BottomArea() Export(); GUIUtility.ExitGUI(); } + GUI.enabled = true; GUILayout.Space(10); GUILayout.EndHorizontal(); diff --git a/Editor/Mono/GUI/PackageExportTreeView.cs b/Editor/Mono/GUI/PackageExportTreeView.cs index 14d8a223c6..af69826ed1 100644 --- a/Editor/Mono/GUI/PackageExportTreeView.cs +++ b/Editor/Mono/GUI/PackageExportTreeView.cs @@ -31,13 +31,16 @@ public enum EnabledState public ExportPackageItem[] items { get { return m_PackageExport.items; } } + public bool isAllItemsEnabled { get; private set; } + public bool isAnyItemEnabled { get; private set; } + public PackageExportTreeView(PackageExport packageExport, TreeViewState treeViewState, Rect startRect) { m_PackageExport = packageExport; - m_TreeView = new TreeViewController(m_PackageExport, treeViewState); + m_TreeView = new TreeViewController(m_PackageExport, treeViewState); var dataSource = new PackageExportTreeViewDataSource(m_TreeView, this); - var gui = new PackageExportTreeViewGUI(m_TreeView, this); + var gui = new PackageExportTreeViewGUI(m_TreeView, this); m_TreeView.Init(startRect, dataSource, gui, null); m_TreeView.ReloadData(); @@ -45,6 +48,8 @@ public PackageExportTreeView(PackageExport packageExport, TreeViewState treeView gui.itemWasToggled += ItemWasToggled; ComputeEnabledStateForFolders(); + + RefreshEnabledProperties(); } void ComputeEnabledStateForFolders() @@ -162,6 +167,7 @@ public void SetAllEnabled(EnabledState enabled) { EnableChildrenRecursive(m_TreeView.data.root, enabled); ComputeEnabledStateForFolders(); + RefreshEnabledProperties(); } void ItemWasToggled(PackageExportTreeViewItem pitem) @@ -177,6 +183,7 @@ void ItemWasToggled(PackageExportTreeViewItem pitem) } ComputeEnabledStateForFolders(); + RefreshEnabledProperties(); } void EnableChildrenRecursive(TreeViewItem parentItem, EnabledState enabled) @@ -192,6 +199,13 @@ void EnableChildrenRecursive(TreeViewItem parentItem, EnabledState enabled) } } + private void RefreshEnabledProperties() + { + isAllItemsEnabled = !m_TreeView.data.root.Exists(item => ((PackageExportTreeViewItem)item).enabledState != EnabledState.All); + isAnyItemEnabled = m_TreeView.data.root.Exists(item => ((PackageExportTreeViewItem)item).enabledState == EnabledState.All || + ((PackageExportTreeViewItem)item).enabledState == EnabledState.Mixed); + } + // Item private class PackageExportTreeViewItem : TreeViewItem { @@ -223,7 +237,7 @@ private class PackageExportTreeViewGUI : TreeViewGUI { internal static class Constants { - public static Texture2D folderIcon = EditorGUIUtility.FindTexture(EditorResources.folderIconName); + public static Texture2D folderIcon = EditorGUIUtility.FindTexture(EditorResources.folderIconName); } public Action itemWasToggled; @@ -283,7 +297,7 @@ static void Toggle(ExportPackageItem[] items, PackageExportTreeViewItem pitem, R if (setMixed) style = EditorStyles.toggleMixed; - bool newEnabled = GUI.Toggle(toggleRect, enabled, GUIContent.none, style); + bool newEnabled = GUI.Toggle(toggleRect, enabled, GUIContent.none, style); if (newEnabled != enabled) pitem.enabledState = newEnabled ? EnabledState.All : EnabledState.None; } @@ -321,7 +335,7 @@ void DoIconAndText(PackageExportTreeViewItem item, Rect contentRect, bool select protected override Texture GetIconForItem(TreeViewItem tItem) { var pItem = tItem as PackageExportTreeViewItem; - var item = pItem.item; + var item = pItem.item; // Undefined items are always folders. if (item == null || item.isFolder) @@ -391,7 +405,7 @@ public override void FetchData() if (PackageImport.HasInvalidCharInFilePath(item.assetPath)) continue; // Do not add invalid paths (we already warn the user with a dialog in PackageImport.cs) - string filename = Path.GetFileName(item.assetPath).ConvertSeparatorsToUnity(); + string filename = Path.GetFileName(item.assetPath).ConvertSeparatorsToUnity(); string folderPath = Path.GetDirectoryName(item.assetPath).ConvertSeparatorsToUnity(); // Ensure folders. This is for when installed packages have been moved to other folders. diff --git a/Editor/Mono/GUI/PackageImport.cs b/Editor/Mono/GUI/PackageImport.cs index 8642b984a8..1f5710cfe6 100644 --- a/Editor/Mono/GUI/PackageImport.cs +++ b/Editor/Mono/GUI/PackageImport.cs @@ -215,15 +215,19 @@ void TopButtonsArea() GUILayout.BeginHorizontal(); GUILayout.Space(10); + GUI.enabled = !m_Tree.isAllItemsEnabled; if (GUILayout.Button(EditorGUIUtility.TrTextContent("All"), GUILayout.Width(50))) { m_Tree.SetAllEnabled(PackageImportTreeView.EnabledState.All); } + GUI.enabled = true; + GUI.enabled = m_Tree.isAnyItemEnabled; if (GUILayout.Button(EditorGUIUtility.TrTextContent("None"), GUILayout.Width(50))) { m_Tree.SetAllEnabled(PackageImportTreeView.EnabledState.None); } + GUI.enabled = true; GUILayout.Space(10); GUILayout.EndHorizontal(); @@ -252,6 +256,7 @@ void BottomArea() PackageImportWizard.instance.DoPreviousStep(m_ImportPackageItems); } var buttonText = isSecondStep || !PackageImportWizard.instance.IsMultiStepWizard ? "Import" : "Next"; + GUI.enabled = m_Tree.isAnyItemEnabled; if (GUILayout.Button(EditorGUIUtility.TrTextContent(buttonText))) { if (m_ImportPackageItems != null) @@ -259,6 +264,7 @@ void BottomArea() else PackageImportWizard.instance.CloseImportWindow(); } + GUI.enabled = true; GUILayout.Space(10); GUILayout.EndHorizontal(); diff --git a/Editor/Mono/GUI/PackageImportTreeView.cs b/Editor/Mono/GUI/PackageImportTreeView.cs index 45225ed672..3aae22adb0 100644 --- a/Editor/Mono/GUI/PackageImportTreeView.cs +++ b/Editor/Mono/GUI/PackageImportTreeView.cs @@ -31,6 +31,8 @@ public enum EnabledState public ImportPackageItem[] packageItems { get { return m_PackageImport.packageItems; } } + public bool isAllItemsEnabled { get; private set; } + public bool isAnyItemEnabled { get; private set; } public PackageImportTreeView(PackageImport packageImport, TreeViewState treeViewState, Rect startRect) { @@ -38,7 +40,7 @@ public PackageImportTreeView(PackageImport packageImport, TreeViewState treeView m_TreeView = new TreeViewController(m_PackageImport, treeViewState); var dataSource = new PackageImportTreeViewDataSource(m_TreeView, this); - var gui = new PackageImportTreeViewGUI(m_TreeView, this); + var gui = new PackageImportTreeViewGUI(m_TreeView, this); m_TreeView.Init(startRect, dataSource, gui, null); m_TreeView.ReloadData(); @@ -46,6 +48,8 @@ public PackageImportTreeView(PackageImport packageImport, TreeViewState treeView gui.itemWasToggled += ItemWasToggled; ComputeEnabledStateForFolders(); + + RefreshEnabledProperties(); } void ComputeEnabledStateForFolders() @@ -230,6 +234,7 @@ public void SetAllEnabled(EnabledState state) { EnableChildrenRecursive(m_TreeView.data.root, state); ComputeEnabledStateForFolders(); + RefreshEnabledProperties(); } void ItemWasToggled(PackageImportTreeViewItem pitem) @@ -247,8 +252,8 @@ void ItemWasToggled(PackageImportTreeViewItem pitem) } ComputeEnabledStateForFolders(); + RefreshEnabledProperties(); } - void EnableChildrenRecursive(TreeViewItem parentItem, EnabledState state) { if (!parentItem.hasChildren) @@ -263,6 +268,13 @@ void EnableChildrenRecursive(TreeViewItem parentItem, EnabledState state) } } + private void RefreshEnabledProperties() + { + isAllItemsEnabled = !m_TreeView.data.root.Exists(item => ((PackageImportTreeViewItem)item).enableState != EnabledState.All); + isAnyItemEnabled = m_TreeView.data.root.Exists(item => ((PackageImportTreeViewItem)item).enableState == EnabledState.All || + ((PackageImportTreeViewItem)item).enableState == EnabledState.Mixed); + } + // Item private class PackageImportTreeViewItem : TreeViewItem @@ -351,13 +363,13 @@ override public void OnRowGUI(Rect rowRect, TreeViewItem tvItem, int row, bool s if (selected && repainting) selectionStyle.Draw(rowRect, false, false, true, focused); - bool validItem = (item != null); - bool isDisabled = (item != null) ? item.enabledStatus == (int)EnabledState.Disabled : false; - bool isFolder = (item != null) ? item.isFolder : true; + bool validItem = (item != null); + bool isDisabled = (item != null) ? item.enabledStatus == (int)EnabledState.Disabled : false; + bool isFolder = (item != null) ? item.isFolder : true; bool assetChanged = (item != null) ? item.assetChanged : false; bool pathConflict = (item != null) ? item.pathConflict : false; bool GUIDOverride = (item != null) ? item.existingAssetPath != string.Empty && item.existingAssetPath != item.destinationAssetPath : false; - bool exists = (item != null) ? item.exists : true; + bool exists = (item != null) ? item.exists : true; bool projectAsset = (item != null) ? item.projectAsset : false; // 1. Foldout @@ -440,7 +452,7 @@ static void Toggle(ImportPackageItem[] items, PackageImportTreeViewItem pitem, R if (isFolder && (pitem.enableState == EnabledState.Disabled)) GUI.enabled = false; - bool newEnabled = GUI.Toggle(toggleRect, enabled, GUIContent.none, style); + bool newEnabled = GUI.Toggle(toggleRect, enabled, GUIContent.none, style); if (newEnabled != enabled) pitem.enableState = newEnabled ? EnabledState.All : EnabledState.None; @@ -504,8 +516,8 @@ void DoIconAndText(TreeViewItem item, Rect contentRect, bool selected, bool focu protected override Texture GetIconForItem(TreeViewItem tvItem) { - var ourItem = tvItem as PackageImportTreeViewItem; - var item = ourItem.item; + var ourItem = tvItem as PackageImportTreeViewItem; + var item = ourItem.item; // Indefined items are always folders. if (item == null || item.isFolder) @@ -567,7 +579,6 @@ public override void FetchData() m_TreeView.state.expandedIDs.Add(m_RootItem.id); ImportPackageItem[] items = m_PackageImportView.packageItems; - Dictionary treeViewFolders = new Dictionary(); for (int i = 0; i < items.Length; i++) { @@ -576,7 +587,7 @@ public override void FetchData() if (PackageImport.HasInvalidCharInFilePath(item.destinationAssetPath)) continue; // Do not add invalid paths (we already warn the user with a dialog in PackageImport.cs) - string filename = Path.GetFileName(item.destinationAssetPath).ConvertSeparatorsToUnity(); + string filename = Path.GetFileName(item.destinationAssetPath).ConvertSeparatorsToUnity(); string folderPath = Path.GetDirectoryName(item.destinationAssetPath).ConvertSeparatorsToUnity(); // Ensure folders. This is for when installed packages have been moved to other folders. diff --git a/Editor/Mono/GUI/PaneDragTab.cs b/Editor/Mono/GUI/PaneDragTab.cs index 449c99a154..cc0fe8e034 100644 --- a/Editor/Mono/GUI/PaneDragTab.cs +++ b/Editor/Mono/GUI/PaneDragTab.cs @@ -37,7 +37,7 @@ private static class Styles public static GUIStyle view = "TabWindowBackground"; public static readonly GUIStyle tabLabel = new GUIStyle("dragtab") { name = "dragtab-label" }; - public static readonly SVC backgroundColor = new SVC("--theme-background-color"); + public static readonly SVC backgroundColor = new SVC("--unity-colors-app_toolbar-background"); } static public PaneDragTab get diff --git a/Editor/Mono/GUI/Toolbars/MainToolbarImguiContainer.cs b/Editor/Mono/GUI/Toolbars/MainToolbarImguiContainer.cs index 89f7351eb2..695a111bc1 100644 --- a/Editor/Mono/GUI/Toolbars/MainToolbarImguiContainer.cs +++ b/Editor/Mono/GUI/Toolbars/MainToolbarImguiContainer.cs @@ -12,6 +12,7 @@ namespace UnityEditor.Toolbars sealed class MainToolbarImguiContainer : IMGUIContainer { const float k_PaddingBetweenSubToolbar = 4; + const string k_USSClassName = "unity-editor-toolbar-imgui-container"; static readonly List s_SubToolbars = new List(1); float m_CurrentWidth; @@ -22,6 +23,7 @@ public static void AddDeprecatedSubToolbar(SubToolbar subToolbar) public MainToolbarImguiContainer() { + AddToClassList(k_USSClassName); onGUIHandler = OnGUI; } @@ -52,6 +54,10 @@ void UpdateContainerWidth() { m_CurrentWidth = targetWidth; style.width = m_CurrentWidth; + // Set the min and max to ensure the specified width is respected as it does not seem to be always the case + // for some reason. + style.minWidth = m_CurrentWidth; + style.maxWidth = m_CurrentWidth; } } } diff --git a/Editor/Mono/GUI/Toolbars/Toolbar.cs b/Editor/Mono/GUI/Toolbars/Toolbar.cs index 5b63f801b9..5c2bdb29de 100644 --- a/Editor/Mono/GUI/Toolbars/Toolbar.cs +++ b/Editor/Mono/GUI/Toolbars/Toolbar.cs @@ -33,7 +33,8 @@ public VisualElement root // The main toolbar class Toolbar : GUIView { - const float k_ToolbarHeight = 30f; + public const float k_ToolbarHeight = 36f; + private const string k_MainToolbarUSSClassName = "unity-editor-main-toolbar"; static class Styles { @@ -115,9 +116,6 @@ protected override void OldOnGUI() { if (Event.current.type == EventType.Repaint) Styles.appToolbar.Draw(new Rect(0, 0, position.width, position.height), false, false, false, false); - - //BeginOffsetArea(GetToolbarPosition(), GUIContent.none, GUIStyle.none); - //EndOffsetArea(); } static VisualElement CreateRoot() @@ -131,7 +129,10 @@ static VisualElement CreateRoot() renderHints = RenderHints.ClipWithScissors }; root.pseudoStates |= PseudoStates.Root; + root.AddToClassList(k_MainToolbarUSSClassName); + UIElementsEditorUtility.AddDefaultEditorStyleSheets(root); + root.StretchToParentSize(); root.style.overflow = Overflow.Hidden; return root; } diff --git a/Editor/Mono/GUI/TreeView/TreeViewItem.cs b/Editor/Mono/GUI/TreeView/TreeViewItem.cs index 5b0b507282..4bee6c86ab 100644 --- a/Editor/Mono/GUI/TreeView/TreeViewItem.cs +++ b/Editor/Mono/GUI/TreeView/TreeViewItem.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.Collections.Generic; using UnityEngine; @@ -16,7 +17,7 @@ public class TreeViewItem : System.IComparable string m_DisplayName; Texture2D m_Icon; - public TreeViewItem() {} + public TreeViewItem() { } public TreeViewItem(int id) { @@ -44,7 +45,7 @@ internal TreeViewItem(int id, int depth, TreeViewItem parent, string displayName m_DisplayName = displayName; } - public virtual int id { get { return m_ID; } set { m_ID = value; }} + public virtual int id { get { return m_ID; } set { m_ID = value; } } public virtual string displayName { get { return m_DisplayName; } set { m_DisplayName = value; } } public virtual int depth { get { return m_Depth; } set { m_Depth = value; } } public virtual bool hasChildren { get { return m_Children != null && m_Children.Count > 0; } } @@ -74,6 +75,22 @@ public override string ToString() } } + internal static class TreeViewItemExtension + { + internal static bool Exists(this TreeViewItem parentItem, Func condition) + { + foreach (TreeViewItem tvitem in parentItem.hasChildren ? parentItem.children : new List()) + { + if (condition(tvitem)) + return true; + + if (tvitem.Exists(condition)) + return true; + } + return false; + } + } + class TreeViewItemAlphaNumericSort : IComparer { public int Compare(TreeViewItem lhs, TreeViewItem rhs) diff --git a/Editor/Mono/Graphics/ShaderCompilerData.cs b/Editor/Mono/Graphics/ShaderCompilerData.cs index 89579215a1..3ba2dc3789 100644 --- a/Editor/Mono/Graphics/ShaderCompilerData.cs +++ b/Editor/Mono/Graphics/ShaderCompilerData.cs @@ -86,6 +86,7 @@ public enum ShaderCompilerPlatform [System.Obsolete(@"GameCore is deprecated, please use GameCoreXboxOne (UnityUpgradable) -> GameCoreXboxOne ", true)] GameCore = 25, // Game Core deprecated as single platform WebGPU = 26, // WebGPU + ReservedCFE = 27, } public enum ShaderCompilerMessageSeverity diff --git a/Editor/Mono/Inspector/Core/InspectorWindow.cs b/Editor/Mono/Inspector/Core/InspectorWindow.cs index dfb2b2c5eb..6230a7263c 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.EditorLockTracker m_LockTracker = new EditorGUIUtility.EditorLockTracker(); + [SerializeField] EditorGUIUtility.EditorLockTrackerWithActiveEditorTracker m_LockTracker = new EditorGUIUtility.EditorLockTrackerWithActiveEditorTracker(); [SerializeField] PreviewWindow m_PreviewWindow; readonly HashSet m_UserSupportedDataModes = new(4); @@ -33,10 +33,14 @@ 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; } } @@ -82,8 +86,11 @@ protected override void OnEnable() RestoreLockStateFromSerializedData(); if (m_LockTracker == null) - m_LockTracker = new EditorGUIUtility.EditorLockTracker(); + { + m_LockTracker = new EditorGUIUtility.EditorLockTrackerWithActiveEditorTracker(); + } + m_LockTracker.tracker = tracker; m_LockTracker.lockStateChanged.AddListener(LockStateChanged); m_Tracker.dataMode = GetDataModeController_Internal().dataMode; @@ -237,24 +244,30 @@ 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 && m_Tracker.inspectorMode == m_InspectorMode) + 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; return; + } - EnsureAppropriateTrackerIsInUse(); + m_Tracker = sharedTrackerInUse ? new ActiveEditorTracker() : ActiveEditorTracker.sharedTracker; 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); @@ -262,25 +275,16 @@ protected virtual void ShowButton(Rect r) private void LockStateChanged(bool lockState) { - EnsureAppropriateTrackerIsInUse(); - - m_Tracker.isLocked = lockState; // Update the lock state of the ActiveEditorTracker in use - if (m_Tracker.isLocked != lockState) - { - // 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(); + } - if (lockState) - tracker.RebuildIfNecessary(); - else - tracker.ForceRebuild(); + tracker.RebuildIfNecessary(); } protected override bool CloseIfEmpty() @@ -477,7 +481,9 @@ 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) @@ -503,11 +509,9 @@ private void RestoreLockStateFromSerializedData() } } - // set the tracker to the serialized list. if it contains nulls or is empty, the tracker will be set to unlocked + // set the tracker to the serialized list. if it contains nulls or is empty, the tracker won't lock // 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/PropertyEditor.cs b/Editor/Mono/Inspector/Core/PropertyEditor.cs index f9fc4a6e58..ce1cf29020 100644 --- a/Editor/Mono/Inspector/Core/PropertyEditor.cs +++ b/Editor/Mono/Inspector/Core/PropertyEditor.cs @@ -498,11 +498,6 @@ internal static IEnumerable GetPropertyEditors() return m_AllPropertyEditors.AsEnumerable(); } - protected virtual void EnsureAppropriateTrackerIsInUse() - { - // By default PropertyEditor are locked on their inspected object and won't change tracker because the Inspector Mode has changed. - } - protected void SetMode(InspectorMode mode) { if (m_InspectorMode != mode) @@ -512,12 +507,7 @@ protected void SetMode(InspectorMode mode) // Clear the editors Element so that a real rebuild is done editorsElement.Clear(); m_EditorElementUpdater.Clear(); - - EnsureAppropriateTrackerIsInUse(); - - m_Tracker.inspectorMode = m_InspectorMode; - m_Tracker.ForceRebuild(); - + tracker.inspectorMode = mode; m_ResetKeyboardControl = true; SceneView.SetActiveEditorsDirty(true); } diff --git a/Editor/Mono/Inspector/Core/ScriptAttributeGUI/Implementations/PropertyDrawers.cs b/Editor/Mono/Inspector/Core/ScriptAttributeGUI/Implementations/PropertyDrawers.cs index 38279a7c6d..19c409ea51 100644 --- a/Editor/Mono/Inspector/Core/ScriptAttributeGUI/Implementations/PropertyDrawers.cs +++ b/Editor/Mono/Inspector/Core/ScriptAttributeGUI/Implementations/PropertyDrawers.cs @@ -3,9 +3,11 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; +using System.Reflection; using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements; +using static UnityEngine.EnumDataUtility; namespace UnityEditor { @@ -520,4 +522,135 @@ public override VisualElement CreatePropertyGUI(SerializedProperty property) return new Label(s_InvalidTypeMessage); } } + + [CustomPropertyDrawer(typeof(EnumButtonsAttribute))] + internal sealed class EnumButtonsDrawer : PropertyDrawer + { + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var toggleButtonGroup = new ToggleButtonGroup + { + label = property.localizedDisplayName, + tooltip = property.tooltip + }; + + var fieldInfo = ScriptAttributeUtility.GetFieldInfoFromProperty(property, out var enumType); + if (enumType == null) + return null; + + var toggleButtonsAttribute = fieldInfo.GetCustomAttribute(false); + var cachedType = toggleButtonsAttribute?.includeObsolete == true ? CachedType.IncludeAllObsolete : CachedType.ExcludeObsolete; + var enumData = EnumDataUtility.GetCachedEnumData(enumType, cachedType); + + toggleButtonGroup.isMultipleSelection = enumData.flags; + toggleButtonGroup.allowEmptySelection = enumData.flags; + toggleButtonGroup.label = property.localizedDisplayName; + toggleButtonGroup.tooltip = property.tooltip; + toggleButtonGroup.AddToClassList(ToggleButtonGroup.alignedFieldUssClassName); + + // Create buttons + for (int i = 0; i < enumData.values.Length; ++i) + { + var button = new Button { text = enumData.displayNames[i], name = enumData.names[i], tooltip = enumData.tooltip[i] }; + toggleButtonGroup.Add(button); + } + + toggleButtonGroup.RegisterValueChangedCallback(evt => + { + SyncFieldChangeToProperty(evt, enumData, toggleButtonGroup, property); + }); + + toggleButtonGroup.TrackPropertyValue(property, p => + { + SyncPropertyToField(p, enumData, toggleButtonGroup); + }); + + SyncPropertyToField(property, enumData, toggleButtonGroup); + return toggleButtonGroup; + } + + static void SyncFieldChangeToProperty(ChangeEvent evt, in EnumData enumData, ToggleButtonGroup toggleButtonGroup, SerializedProperty property) + { + // Calculate the new value by checking what buttons have changed. + // When the value has multiple different values, we calculate from 0. + var value = property.hasMultipleDifferentValues ? 0 : property.intValue; + if (enumData.flags) + { + for (int i = 0; i < enumData.values.Length; i++) + { + // The button state didn't change, so skip it + if (evt.previousValue[i] == evt.newValue[i]) + continue; + + // It was toggled on, enable the bits + if (evt.newValue[i]) + { + // Special handling for 0 which is usually a None flag. + if (enumData.flagValues[i] == 0) + { + value = 0; + break; + } + else + { + value |= enumData.flagValues[i]; + } + } + else // It was toggled off, disable the bits + { + value &= ~enumData.flagValues[i]; + } + } + } + else + { + for (int i = 0; i < enumData.values.Length; i++) + { + if (evt.newValue[i]) + { + value = enumData.flagValues[i]; + break; + } + } + } + + property.intValue = value; + property.serializedObject.ApplyModifiedProperties(); + SyncPropertyToField(property, enumData, toggleButtonGroup); + } + + static void SyncPropertyToField(SerializedProperty property, in EnumData enumData, ToggleButtonGroup toggleButtonGroup) + { + // EnumData limits us to ints. + var state = new ToggleButtonGroupState(0, 32); + + // We leave the state at 0 when we have mixed values + if (!property.hasMultipleDifferentValues) + { + var value = property.intValue; + + if (enumData.flags) + { + for (int i = 0; i < enumData.values.Length; i++) + { + // Special handling for 0 which is usually a None flag. + if (enumData.flagValues[i] == 0) + state[i] = value == 0; + else + state[i] = (enumData.flagValues[i] & value) == enumData.flagValues[i]; + } + } + else + { + for (int i = 0; i < enumData.values.Length; i++) + { + state[i] = value == enumData.flagValues[i]; + } + } + } + + toggleButtonGroup.SetValueWithoutNotify(state); + toggleButtonGroup.showMixedValue = property.hasMultipleDifferentValues; + } + } } diff --git a/Editor/Mono/Inspector/Core/ScriptAttributeGUI/PropertyHandler.cs b/Editor/Mono/Inspector/Core/ScriptAttributeGUI/PropertyHandler.cs index 8a519915e1..482faf6175 100644 --- a/Editor/Mono/Inspector/Core/ScriptAttributeGUI/PropertyHandler.cs +++ b/Editor/Mono/Inspector/Core/ScriptAttributeGUI/PropertyHandler.cs @@ -96,20 +96,10 @@ public void HandleAttribute(SerializedProperty property, PropertyAttribute attri return; } - if (attribute.applyToCollection) - { - // Do not apply this to array elements - if (!property.isArray) - return; - - if (!propertyType.IsArrayOrList()) - { - throw new NotSupportedException($"Cannot apply {nameof(attribute)} on a field of type {propertyType.Name}." + - $"\nPlease use this attribute on a collection."); - } - } - - + // When `attribute.applyToCollection` is set to true, we need to early return for any non-collection fields within a collection. + // Collections and fields that are not part of a collection should comply with the attribute. + if (attribute.applyToCollection && !propertyType.IsArrayOrList() && property.propertyPath.Contains("[")) + return; // Look for its drawer type of this attribute HandleDrawnType(property, attribute.GetType(), propertyType, field, attribute); diff --git a/Editor/Mono/Inspector/GraphicsSettingsInspectors/GraphicsSettingsInspectorUtility.cs b/Editor/Mono/Inspector/GraphicsSettingsInspectors/GraphicsSettingsInspectorUtility.cs index dab455e738..0d401dbd9c 100644 --- a/Editor/Mono/Inspector/GraphicsSettingsInspectors/GraphicsSettingsInspectorUtility.cs +++ b/Editor/Mono/Inspector/GraphicsSettingsInspectors/GraphicsSettingsInspectorUtility.cs @@ -7,6 +7,8 @@ using System.ComponentModel; using System.Reflection; using System.Text; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; using UnityEditor.Rendering; using UnityEditor.Rendering.Settings; using UnityEditor.UIElements; @@ -295,6 +297,14 @@ internal static Type GetRenderPipelineAssetTypeForSelectedTab(VisualElement root } internal static void ReloadGraphicsSettingsEditorIfNeeded() + { + if (BuildPipeline.isBuildingPlayer) + return; + + ReloadGraphicsSettingsEditorIfOpened(); + } + + private static void ReloadGraphicsSettingsEditorIfOpened() { if (!EditorWindow.HasOpenInstances()) return; diff --git a/Editor/Mono/Inspector/LightEditor.cs b/Editor/Mono/Inspector/LightEditor.cs index c8590f7695..3b91023cc1 100644 --- a/Editor/Mono/Inspector/LightEditor.cs +++ b/Editor/Mono/Inspector/LightEditor.cs @@ -123,6 +123,7 @@ private static class Styles public static readonly GUIContent CookiePointCubemapTextureWarning = EditorGUIUtility.TrTextContent("Cookie support for baked lights is not enabled. Please enable it in Project Settings > Editor > Enable baked cookies support"); public static readonly GUIContent MixedUnsupportedWarning = EditorGUIUtility.TrTextContent("Light mode is currently overridden to Realtime mode. The current render pipeline doesn't support Mixed mode and/or any of the lighting modes."); public static readonly GUIContent BakedUnsupportedWarning = EditorGUIUtility.TrTextContent("Light mode is currently overridden to Realtime mode. The current render pipeline doesn't support Baked mode."); + public static readonly GUIContent ShadowMaskConvertedToBakedWarning = EditorGUIUtility.TrTextContent("Light mode is currently overridden to Baked mode because too many lights overlap in the scene. Shadowmask mode only supports a maximum of 4 overlapping lights."); public static readonly GUIContent[] LightmapBakeTypeTitles = { EditorGUIUtility.TrTextContent("Realtime"), EditorGUIUtility.TrTextContent("Mixed"), EditorGUIUtility.TrTextContent("Baked") }; public static readonly int[] LightmapBakeTypeValues = { (int)LightmapBakeType.Realtime, (int)LightmapBakeType.Mixed, (int)LightmapBakeType.Baked }; @@ -171,6 +172,8 @@ internal bool showBounceWarning } internal bool showBakingWarning { get { return !isPrefabAsset && !Lightmapping.GetLightingSettingsOrDefaultsFallback().bakedGI && lightmappingTypeIsSame && isBakedOrMixed; } } + internal bool showShadowMaskConvertedToBakedWarning { get { return isMixed && Lightmapping.GetLightingSettingsOrDefaultsFallback().mixedBakeMode == MixedLightingMode.Shadowmask && light.bakingOutput.occlusionMaskChannel == -1; } } + internal bool showCookieSpotRepeatWarning { get @@ -471,6 +474,8 @@ public void DrawLightmapping() EditorGUILayout.HelpBox(Styles.BakedUnsupportedWarning.text, MessageType.Warning); else if (showBakingWarning) EditorGUILayout.HelpBox(Styles.BakingWarning.text, MessageType.Warning); + else if(showShadowMaskConvertedToBakedWarning) + EditorGUILayout.HelpBox(Styles.ShadowMaskConvertedToBakedWarning.text, MessageType.Warning); } internal void CheckLightmappingConsistency() diff --git a/Editor/Mono/Inspector/MaskFieldDropdown.cs b/Editor/Mono/Inspector/MaskFieldDropdown.cs index ca762509ec..1a7d6f0a02 100644 --- a/Editor/Mono/Inspector/MaskFieldDropdown.cs +++ b/Editor/Mono/Inspector/MaskFieldDropdown.cs @@ -5,10 +5,10 @@ using System; using System.Collections.Generic; using System.Linq; -using UnityEditorInternal; +using System.Reflection; using UnityEngine; using static UnityEditor.MaskDropDownUtils; -using System.Reflection; +using Object = UnityEngine.Object; namespace UnityEditor { @@ -18,6 +18,10 @@ internal class MaskFieldDropDown : PopupWindowContent SerializedProperty m_SerializedProperty; + // Keep a reference to the targets so we can recreate the serialized property if it becomes invalid. (UUM-72761) + Object[] m_Targets; + string m_PropertyName; + SelectionModes[] m_SelectionMatch; string[] m_OptionNames; int[] m_flagValues; @@ -33,6 +37,8 @@ internal class MaskFieldDropDown : PopupWindowContent public MaskFieldDropDown(SerializedProperty property) { m_SerializedProperty = property; + m_Targets = property.serializedObject.targetObjects; + m_PropertyName = property.propertyPath; m_SingleSelection = false; } @@ -183,6 +189,12 @@ public override void OnGUI(Rect rect) return; } + if (!m_SerializedProperty.isValid) + { + var serializedObject = new SerializedObject(m_Targets); + m_SerializedProperty = serializedObject.FindProperty(m_PropertyName); + } + if (m_SerializedProperty.propertyType != SerializedPropertyType.LayerMask) return; diff --git a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs index c2f28a5c0f..e45fd7938b 100644 --- a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs +++ b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs @@ -743,7 +743,7 @@ void OnDisable() /// tab is displayed in the platform grouping. /// [VisibleToOtherModules("UnityEditor.BuildProfileModule")] - internal void ConfigurePlayerSettingsForBuildProfile(string buildProfileModuleName, bool isServerBuildProfile, bool isActiveBuildProfile) + internal void ConfigurePlayerSettingsForBuildProfile(SerializedObject serializedProfile, string buildProfileModuleName, bool isServerBuildProfile, bool isActiveBuildProfile) { playerSettingsType = isActiveBuildProfile ? PlayerSettingsType.ActiveBuildProfile : PlayerSettingsType.NonActiveBuildProfile; @@ -771,6 +771,29 @@ internal void ConfigurePlayerSettingsForBuildProfile(string buildProfileModuleNa m_SettingsExtensions = new ISettingEditorExtension[1]; m_SettingsExtensions[0] = ModuleManager.GetEditorSettingsExtension(platformModuleName); m_SettingsExtensions[0]?.OnEnable(this); + m_SettingsExtensions[0]?.ConfigurePlatformProfile(serializedProfile); + } + + /// + /// Check if the platform-specific player settings in ISettingsExtensionData on the managed side + /// are equal to the corresponding data in the project settings + /// + [VisibleToOtherModules("UnityEditor.BuildProfileModule")] + internal bool IsPlayerSettingsExtensionDataEqualToProjectSettings() + { + if (m_SettingsExtensions == null || m_SettingsExtensions.Length == 0 || m_SettingsExtensions[0] == null) + return false; + + return m_SettingsExtensions[0].IsPlayerSettingsDataEqualToProjectSettings(); + } + + [VisibleToOtherModules("UnityEditor.BuildProfileModule")] + internal bool CopyProjectSettingsToPlayerSettingsExtension() + { + if (m_SettingsExtensions == null || m_SettingsExtensions.Length == 0 || m_SettingsExtensions[0] == null) + return false; + + return m_SettingsExtensions[0].CopyProjectSettingsPlayerSettingsToBuildProfile(); } [RequiredByNativeCode] @@ -1482,54 +1505,57 @@ private static bool WillEditorUseFirstGraphicsAPI(BuildTarget targetPlatform) Application.platform == RuntimePlatform.OSXEditor && targetPlatform == BuildTarget.StandaloneOSX; } - private bool CheckApplyGraphicsJobsModeChange() + private bool CheckApplyGraphicsJobsModeChange(BuildTarget target) { bool doRestart = false; - // If we have dirty scenes we need to save or discard changes before we restart editor. - // Otherwise user will get a dialog later on where they can click cancel and put editor in a bad device state. - var dirtyScenes = new List(); - for (int i = 0; i < EditorSceneManager.sceneCount; ++i) + if (WillEditorUseFirstGraphicsAPI(target)) { - var scene = EditorSceneManager.GetSceneAt(i); - if (scene.isDirty) - dirtyScenes.Add(scene); - } - if (dirtyScenes.Count != 0) - { - var result = EditorUtility.DisplayDialogComplex("Changing editor graphics jobs mode", - "You've changed the active graphics jobs mode. This requires a restart of the Editor. Do you want to save the Scene when restarting?", - "Save and Restart", "Cancel Changing API", "Discard Changes and Restart"); - if (result == 1) + // If we have dirty scenes we need to save or discard changes before we restart editor. + // Otherwise user will get a dialog later on where they can click cancel and put editor in a bad device state. + var dirtyScenes = new List(); + for (int i = 0; i < EditorSceneManager.sceneCount; ++i) { - doRestart = false; // Cancel was selected + var scene = EditorSceneManager.GetSceneAt(i); + if (scene.isDirty) + dirtyScenes.Add(scene); } - else + if (dirtyScenes.Count != 0) { - doRestart = true; - if (result == 0) // Save and Restart was selected + var result = EditorUtility.DisplayDialogComplex("Changing editor graphics jobs mode", + "You've changed the active graphics jobs mode. This requires a restart of the Editor. Do you want to save the Scene when restarting?", + "Save and Restart", "Cancel Changing API", "Discard Changes and Restart"); + if (result == 1) { - for (int i = 0; i < dirtyScenes.Count; ++i) + doRestart = false; // Cancel was selected + } + else + { + doRestart = true; + if (result == 0) // Save and Restart was selected { - var saved = EditorSceneManager.SaveScene(dirtyScenes[i]); - if (saved == false) + for (int i = 0; i < dirtyScenes.Count; ++i) { - doRestart = false; + var saved = EditorSceneManager.SaveScene(dirtyScenes[i]); + if (saved == false) + { + doRestart = false; + } } } - } - else // Discard Changes and Restart was selected - { - for (int i = 0; i < dirtyScenes.Count; ++i) - EditorSceneManager.ClearSceneDirtiness(dirtyScenes[i]); + else // Discard Changes and Restart was selected + { + for (int i = 0; i < dirtyScenes.Count; ++i) + EditorSceneManager.ClearSceneDirtiness(dirtyScenes[i]); + } } } - } - else - { - doRestart = EditorUtility.DisplayDialog("Changing editor graphics jobs mode", - "You've changed the active graphics jobs mode. This requires a restart of the Editor.", - "Restart Editor", "Not now"); + else + { + doRestart = EditorUtility.DisplayDialog("Changing editor graphics jobs mode", + "You've changed the active graphics josb mode. This requires a restart of the Editor.", + "Restart Editor", "Not now"); + } } return doRestart; } @@ -2293,7 +2319,7 @@ private void OtherSectionRenderingGUI(BuildPlatform platform, ISettingEditorExte Undo.RecordObject(target, SettingsContent.undoChangedGraphicsJobsString); PlayerSettings.SetGraphicsJobsForPlatform(platform.defaultTarget, newGraphicsJobs); - bool restartEditor = CheckApplyGraphicsJobsModeChange(); + bool restartEditor = CheckApplyGraphicsJobsModeChange(platform.defaultTarget); if (restartEditor) { EditorApplication.RequestCloseAndRelaunchWithCurrentArguments(); @@ -2334,7 +2360,7 @@ private void OtherSectionRenderingGUI(BuildPlatform platform, ISettingEditorExte else if (newGfxJobMode == GraphicsJobMode.Split) PlayerSettings.SetGraphicsThreadingModeForPlatform(platform.defaultTarget, GfxThreadingMode.SplitJobs); - bool restartEditor = CheckApplyGraphicsJobsModeChange(); + bool restartEditor = CheckApplyGraphicsJobsModeChange(platform.defaultTarget); if (restartEditor) { EditorApplication.RequestCloseAndRelaunchWithCurrentArguments(); @@ -3840,6 +3866,8 @@ internal static bool BuildPathBoxButton(SerializedProperty prop, string uiString onSelect(); prop.serializedObject.ApplyModifiedProperties(); + + GUIUtility.ExitGUI(); } return changed; @@ -3882,6 +3910,8 @@ internal static bool BuildFileBoxButton(SerializedProperty prop, string uiString onSelect(); prop.serializedObject.ApplyModifiedProperties(); + + GUIUtility.ExitGUI(); } } diff --git a/Editor/Mono/Inspector/VersionControlSettingsInspector.cs b/Editor/Mono/Inspector/VersionControlSettingsInspector.cs index 1dd04ccf43..02bcfad8af 100644 --- a/Editor/Mono/Inspector/VersionControlSettingsInspector.cs +++ b/Editor/Mono/Inspector/VersionControlSettingsInspector.cs @@ -23,6 +23,8 @@ class Styles public static GUIContent logLevel = new GUIContent("Log Level"); public static GUIContent automaticAdd = new GUIContent("Automatic Add", "Automatically add newly created assets to version control."); + public static GUIContent scanLocalPackagesOnConnect = new GUIContent("Scan Local Packages on Connect", + "Scan local packages during the version control initialization to automatically add newly created assets to source control."); public static GUIContent smartMerge = new GUIContent("Smart merge"); public static GUIContent trackPackagesOutsideProject = new GUIContent("Version Packages Outside Project", "Tracks changes to packages that reside on disk outside of the project's root folder."); public static GUIContent vcsConnect = new GUIContent("Connect"); @@ -382,6 +384,9 @@ public override void OnInspectorGUI() EditorUserSettings.AutomaticAdd = EditorGUILayout.Toggle(Styles.automaticAdd, EditorUserSettings.AutomaticAdd); + EditorUserSettings.scanLocalPackagesOnConnect = + EditorGUILayout.Toggle(Styles.scanLocalPackagesOnConnect, EditorUserSettings.scanLocalPackagesOnConnect); + if (Provider.requiresNetwork) EditorUserSettings.allowAsyncStatusUpdate = EditorGUILayout.Toggle(Styles.allowAsyncUpdate, EditorUserSettings.allowAsyncStatusUpdate); diff --git a/Editor/Mono/Modules/DefaultPlayerSettingsEditorExtension.cs b/Editor/Mono/Modules/DefaultPlayerSettingsEditorExtension.cs index 6cf773e22d..de8a6c4de3 100644 --- a/Editor/Mono/Modules/DefaultPlayerSettingsEditorExtension.cs +++ b/Editor/Mono/Modules/DefaultPlayerSettingsEditorExtension.cs @@ -2,11 +2,9 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using System; -using UnityEngine; -using UnityEditor; -using System.Linq; using UnityEditor.Build; +using UnityEditor.Build.Profile; +using UnityEngine; using TargetAttributes = UnityEditor.BuildTargetDiscovery.TargetAttributes; namespace UnityEditor.Modules @@ -27,6 +25,24 @@ public virtual void OnEnable(PlayerSettingsEditor settingsEditor) m_MTRendering = playerSettingsEditor.FindPropertyAssert("m_MTRendering"); } + public virtual void ConfigurePlatformProfile(SerializedObject serializedProfile) + { + } + + public virtual bool CopyProjectSettingsPlayerSettingsToBuildProfile() + { + return false; + } + + public virtual bool IsPlayerSettingsDataEqualToProjectSettings() + { + return true; + } + + public virtual void OnActiveProfileChanged(BuildProfile previous, BuildProfile newProfile) + { + } + public virtual bool HasPublishSection() { return true; diff --git a/Editor/Mono/Modules/PlatformSupportModule.cs b/Editor/Mono/Modules/PlatformSupportModule.cs index 30483726e4..07075d1fcb 100644 --- a/Editor/Mono/Modules/PlatformSupportModule.cs +++ b/Editor/Mono/Modules/PlatformSupportModule.cs @@ -225,6 +225,14 @@ internal interface ISettingEditorExtension { void OnEnable(PlayerSettingsEditor settingsEditor); + void ConfigurePlatformProfile(SerializedObject serializedProfile); + + bool CopyProjectSettingsPlayerSettingsToBuildProfile(); + + bool IsPlayerSettingsDataEqualToProjectSettings(); + + void OnActiveProfileChanged(BuildProfile previous, BuildProfile newProfile); + bool HasPublishSection(); // Leave blank if no contribution diff --git a/Editor/Mono/ObjectFactory.bindings.cs b/Editor/Mono/ObjectFactory.bindings.cs index dbf7cdde95..a86334c3a0 100644 --- a/Editor/Mono/ObjectFactory.bindings.cs +++ b/Editor/Mono/ObjectFactory.bindings.cs @@ -21,6 +21,9 @@ public static class ObjectFactory [FreeFunction] internal static extern void SmartResetObjectToDefault([NotNull] Object target); + [FreeFunction] + internal static extern void FinalizeObjectAndAwake([NotNull] Object target); + [FreeFunction(ThrowsException = true)] static extern Object CreateDefaultInstance([NotNull] Type type); diff --git a/Editor/Mono/Overlays/OverlayCanvas.cs b/Editor/Mono/Overlays/OverlayCanvas.cs index ec59919d1d..feb6cdbf4d 100644 --- a/Editor/Mono/Overlays/OverlayCanvas.cs +++ b/Editor/Mono/Overlays/OverlayCanvas.cs @@ -293,6 +293,8 @@ internal OverlayContainer GetDockZoneContainer(DockZone zone) [SerializeField] bool m_OverlaysVisible = true; + + bool m_OverlaysSupportEnabled = true; VisualElement m_RootVisualElement; internal EditorWindow containerWindow { get; set; } @@ -328,24 +330,68 @@ internal OverlayContainer GetDockZoneContainer(DockZone zone) internal Action afterOverlaysInitialized; internal event Action overlaysEnabledChanged; + internal event Action overlaysSupportEnabledChanged; internal event Action overlayListChanged; public bool overlaysEnabled { - get => m_Containers.All(x => x.style.display != DisplayStyle.None); + get => m_Containers != null && m_OverlaysVisible; set { - m_OverlaysVisible = value; - - if (value == overlaysEnabled) - return; + var changed = m_OverlaysVisible != value; + if (changed) + m_OverlaysVisible = value; + // Ensure the containers' state refreshes in case m_OverlaysVisible value is somehow desynced from container state + var allContainersMatchEnabledState = true; foreach (var container in m_Containers) - container.style.display = value ? DisplayStyle.Flex : DisplayStyle.None; + { + if (container.style.display != (value ? DisplayStyle.Flex : DisplayStyle.None)) + { + allContainersMatchEnabledState = false; + break; + } + } + if (!allContainersMatchEnabledState) + { + foreach (var container in m_Containers) + container.style.display = value ? DisplayStyle.Flex : DisplayStyle.None; + } + + if (changed) + overlaysEnabledChanged?.Invoke(m_OverlaysVisible); + } + } + + internal bool overlaysSupportEnabled + { + get => m_OverlaysSupportEnabled; - overlaysEnabledChanged?.Invoke(value); + set + { + if (value != m_OverlaysSupportEnabled) + { + m_OverlaysSupportEnabled = value; + + if (!m_OverlaysSupportEnabled) + { + // Ensure no lingering popup is left open + ClosePopupOverlay(); + // Hide all overlay containers + foreach (var container in m_Containers) + container.style.display = DisplayStyle.None; + } + // Unhide overlay containers if they're enabled when reactivating support + else if (overlaysEnabled) + { + foreach (var container in m_Containers) + container.style.display = DisplayStyle.Flex; + } + + overlaysSupportEnabledChanged?.Invoke(value); + } } } @@ -515,7 +561,7 @@ internal static Rect ClampRectToBounds(Rect boundary, Rect rectToClamp) // clamp all overlays to root visual element's new bounds void GeometryChanged(GeometryChangedEvent evt) { - if (!overlaysEnabled) + if (!overlaysEnabled || !overlaysSupportEnabled) return; foreach (var overlay in m_Overlays) @@ -731,7 +777,7 @@ public bool Remove(Overlay overlay) public void ShowPopup() where T : Overlay, new() { - if (ClosePopupOverlay()) + if (ClosePopupOverlay() || !overlaysSupportEnabled) return; var popup = OverlayPopup.CreateAtCanvasCenter(this, CreateOverlayForPopup()); @@ -746,12 +792,15 @@ public bool Remove(Overlay overlay) return; } + if (!overlaysSupportEnabled) + return; + ShowPopup(PointerDeviceState.GetPointerPosition(PointerId.mousePointerId, ContextType.Editor)); } public void ShowPopup(Vector2 position) where T : Overlay, new() { - if (ClosePopupOverlay()) + if (ClosePopupOverlay() || !overlaysSupportEnabled) return; var popup = OverlayPopup.CreateAtPosition(this, CreateOverlayForPopup(), position); diff --git a/Editor/Mono/PlayerSettingsIOS.bindings.cs b/Editor/Mono/PlayerSettingsIOS.bindings.cs index eb531dcde5..aa967cbd37 100644 --- a/Editor/Mono/PlayerSettingsIOS.bindings.cs +++ b/Editor/Mono/PlayerSettingsIOS.bindings.cs @@ -120,17 +120,40 @@ public enum iOSAppInBackgroundBehavior [Flags] public enum iOSBackgroundMode: uint { - None = 0, - Audio = 1 << 0, - Location = 1 << 1, - VOIP = 1 << 2, - NewsstandContent = 1 << 3, - ExternalAccessory = 1 << 4, - BluetoothCentral = 1 << 5, - BluetoothPeripheral = 1 << 6, - Fetch = 1 << 7, - RemoteNotification = 1 << 8, - Processing = 1 << 9, + None = 0, + AudioAirplayPiP = 1 << 0, + LocationUpdates = 1 << 1, + VoiceOverIP = 1 << 2, + NewsstandDownloads = 1 << 3, + ExternalAccessoryCommunication = 1 << 4, + UsesBluetoothLEAccessory = 1 << 5, + ActsAsABluetoothLEAccessory = 1 << 6, + BackgroundFetch = 1 << 7, + RemoteNotifications = 1 << 8, + Processing = 1 << 9, + NearbyInteraction = 1 << 10, + NetworkAuthentication = 1 << 11, + PushToTalk = 1 << 12, + + // Obsolete/renamed values + [Obsolete("iOSBackgroundMode.Audio has been deprecated. Use AudioAirplayPiP instead (UnityUpgradable) -> AudioAirplayPiP", true)] + Audio = AudioAirplayPiP, + [Obsolete("iOSBackgroundMode.Location has been deprecated. Use LocationUpdates instead (UnityUpgradable) -> LocationUpdates", true)] + Location = LocationUpdates, + [Obsolete("iOSBackgroundMode.VoIP has been deprecated. Use VoiceOverIP instead (UnityUpgradable) -> VoiceOverIP", true)] + VoIP = VoiceOverIP, + [Obsolete("iOSBackgroundMode.NewsstandContent has been deprecated. Use NewsstandDownloads instead (UnityUpgradable) -> NewsstandDownloads", true)] + NewsstandContent = NewsstandDownloads, + [Obsolete("iOSBackgroundMode.ExternalAccessory has been deprecated. Use ExternalAccessoryCommunication instead (UnityUpgradable) -> ExternalAccessoryCommunication", true)] + ExternalAccessory = ExternalAccessoryCommunication, + [Obsolete("iOSBackgroundMode.BluetoothCentral has been deprecated. Use UsesBluetoothLEAccessory instead (UnityUpgradable) -> UsesBluetoothLEAccessory", true)] + BluetoothCentral = UsesBluetoothLEAccessory, + [Obsolete("iOSBackgroundMode.BluetoothPeripheral has been deprecated. Use ActsAsABluetoothLEAccessory instead (UnityUpgradable) -> ActsAsABluetoothLEAccessory", true)] + BluetoothPeripheral = ActsAsABluetoothLEAccessory, + [Obsolete("iOSBackgroundMode.Fetch has been deprecated. Use BackgroundFetch instead (UnityUpgradable) -> BackgroundFetch", true)] + Fetch = BackgroundFetch, + [Obsolete("iOSBackgroundMode.RemoteNotification has been deprecated. Use RemoteNotifications instead (UnityUpgradable) -> RemoteNotifications", true)] + RemoteNotification = RemoteNotifications, } public enum iOSLaunchScreenImageType diff --git a/Editor/Mono/ProjectBrowser/ProjectWindowUtil.cs b/Editor/Mono/ProjectBrowser/ProjectWindowUtil.cs index 79c19ca296..7aa72f47f7 100644 --- a/Editor/Mono/ProjectBrowser/ProjectWindowUtil.cs +++ b/Editor/Mono/ProjectBrowser/ProjectWindowUtil.cs @@ -69,7 +69,7 @@ public override void Action(int instanceId, string pathName, string resourceFile cleanPath); var obj = AssetDatabase.LoadMainAssetAtPath(cleanPath); var name = obj.name; - ObjectFactory.SmartResetObjectToDefault(obj); + ObjectFactory.FinalizeObjectAndAwake(obj); obj.name = name; AssetDatabase.SaveAssetIfDirty(obj); ProjectWindowUtil.FrameObjectInProjectWindow(instanceId); @@ -443,6 +443,11 @@ static void CreatePrefabVariant() } } + [MenuItem("Assets/Create/Prefab Variant", true)] + static bool CreatePrefabVariantShortcutValidation() => CreatePrefabVariantValidation(); + [MenuItem("Assets/Create/Prefab Variant", false, -215)] + static void CreatePrefabVariantShortcut() => CreatePrefabVariant(); + static GameObject[] CreatePrefabVariants(GameObject[] gameObjects) { if (gameObjects == null) diff --git a/Editor/Mono/SceneView/SceneOrientationGizmo.cs b/Editor/Mono/SceneView/SceneOrientationGizmo.cs index 16c88c86d9..134067cdaf 100644 --- a/Editor/Mono/SceneView/SceneOrientationGizmo.cs +++ b/Editor/Mono/SceneView/SceneOrientationGizmo.cs @@ -165,18 +165,6 @@ void UpdateHeaderAndBackground() rootVisualElement.EnableInClassList(k_ShowOrientationBackground, !collapsed && !showBackGround); } - internal void SkipFading() - { - for (int i = dirVisible.Length - 1; i >= 0; i--) - dirVisible[i].SkipFading(); - - for (int i = dirNameVisible.Length - 1; i >= 0; i--) - dirNameVisible[i].SkipFading(); - - m_RotationLocked.SkipFading(); - m_Visible.SkipFading(); - } - public override void OnCreated() { if (!(containerWindow is SceneView view)) diff --git a/Editor/Mono/SceneView/SceneView.cs b/Editor/Mono/SceneView/SceneView.cs index 5723c827f3..fb8192a49e 100644 --- a/Editor/Mono/SceneView/SceneView.cs +++ b/Editor/Mono/SceneView/SceneView.cs @@ -3533,6 +3533,11 @@ public void LookAt(Vector3 point, Quaternion direction, float newSize, bool orth m_OrientationGizmo?.UpdateGizmoLabel(this, direction * Vector3.forward, m_Ortho.target); } + internal void UpdateOrientationGizmos() + { + m_OrientationGizmo?.UpdateGizmoLabel(this, rotation * Vector3.forward, m_Ortho.target); + } + void DefaultHandles() { // Note event state. diff --git a/Editor/Mono/SceneView/SceneViewMotion.cs b/Editor/Mono/SceneView/SceneViewMotion.cs index d98c3ecc2d..73f9b9865c 100644 --- a/Editor/Mono/SceneView/SceneViewMotion.cs +++ b/Editor/Mono/SceneView/SceneViewMotion.cs @@ -511,8 +511,7 @@ private void HandleMouseDrag(SceneView view) if (!view.in2DMode && !view.isRotationLocked) { OrbitCameraBehavior(view); - // todo gizmo update label - // view.m_OrientationGizmo.UpdateGizmoLabel(view, view.rotation * Vector3.forward, view.m_Ortho.target); + view.UpdateOrientationGizmos(); } } break; @@ -546,8 +545,7 @@ private void HandleMouseDrag(SceneView view) OrbitCameraBehavior(view); } - // todo gizmo update label - // view.m_OrientationGizmo.UpdateGizmoLabel(view, view.rotation * Vector3.forward, view.m_Ortho.target); + view.UpdateOrientationGizmos(); } } break; @@ -652,7 +650,7 @@ void HandleScrollWheel(SceneView view, bool zoomTowardsCenter) 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/Tools/EditorToolCache.cs b/Editor/Mono/Tools/EditorToolCache.cs index 80d0d98f28..a455381dd8 100644 --- a/Editor/Mono/Tools/EditorToolCache.cs +++ b/Editor/Mono/Tools/EditorToolCache.cs @@ -121,12 +121,9 @@ public UnityObject[] targets { if (additionalEditors == null) return inspector.targets; - List objects = new List(inspector.targets); - foreach (var additionalInspector in additionalEditors) - foreach (var additionalTarget in additionalInspector.targets) - if (!objects.Contains(additionalTarget)) - objects.Add(additionalTarget); + foreach (var insp in additionalEditors) + objects.AddRange(insp.targets); return objects.ToArray(); } } diff --git a/Editor/Mono/Tools/EditorToolManager.cs b/Editor/Mono/Tools/EditorToolManager.cs index bc66f48bd0..08ac6d2a6c 100644 --- a/Editor/Mono/Tools/EditorToolManager.cs +++ b/Editor/Mono/Tools/EditorToolManager.cs @@ -671,7 +671,7 @@ internal static EditorTool GetComponentTool(Func predicat if (!searchLockedInspectors && customEditorTool.lockedInspector) continue; - if (predicate(customEditorTool) && customEditorTool.editor is EditorTool tool && tool.IsAvailable()) + if (predicate(customEditorTool) && customEditorTool.editor is EditorTool tool) return tool; } diff --git a/Editor/Mono/Tools/EditorToolUtility.cs b/Editor/Mono/Tools/EditorToolUtility.cs index 65020fec46..8fd596f292 100644 --- a/Editor/Mono/Tools/EditorToolUtility.cs +++ b/Editor/Mono/Tools/EditorToolUtility.cs @@ -145,6 +145,14 @@ internal static EditorTool GetEditorToolWithEnum(Tool type, EditorToolContext ct EditorToolManager.activeToolContext = EditorToolManager.GetSingleton(); return (EditorTool)EditorToolManager.GetSingleton(EditorToolManager.activeToolContext.ResolveTool(type)); } + else if (!instance.IsAvailable()) + { + Debug.LogError($"{context} resolved Tool.{type} to a Component tool of type `{resolved}`, but " + + $"the matching component tool is not Available with the active selection. The active tool " + + $"context will be set to the default."); + EditorToolManager.activeToolContext = EditorToolManager.GetSingleton(); + return (EditorTool)EditorToolManager.GetSingleton(EditorToolManager.activeToolContext.ResolveTool(type)); + } return instance; } diff --git a/Editor/Mono/Tools/ToolManager.cs b/Editor/Mono/Tools/ToolManager.cs index c3605a87cb..3e48c19de5 100644 --- a/Editor/Mono/Tools/ToolManager.cs +++ b/Editor/Mono/Tools/ToolManager.cs @@ -105,6 +105,8 @@ public static void SetActiveTool(Type type) if (tool == null) throw new InvalidOperationException("The current selection does not contain any objects editable " + $"by the component tool of type: {type}"); + if (!tool.IsAvailable()) + throw new InvalidOperationException($"Cannot activate {type} tool because it is currently not available (the tool's IsAvailable() method returned false)."); SetActiveTool(tool); return; } diff --git a/Editor/Mono/UIElements/DefaultMainToolbar.cs b/Editor/Mono/UIElements/DefaultMainToolbar.cs index 8da17e327b..e1b301ed95 100644 --- a/Editor/Mono/UIElements/DefaultMainToolbar.cs +++ b/Editor/Mono/UIElements/DefaultMainToolbar.cs @@ -16,7 +16,6 @@ static IEnumerable leftToolbar { //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 @@ -47,6 +46,7 @@ static IEnumerable rightToolbar yield return "Editor Utility/Undo"; // Modules/Multiplayer/MultiplayerRoleDropdown.cs yield return "Multiplayer/MultiplayerRole"; + yield return "Services/Cloud"; } } diff --git a/External/NiceIO/NiceIO.cs b/External/NiceIO/NiceIO.cs index 3413053e30..a4546c8849 100644 --- a/External/NiceIO/NiceIO.cs +++ b/External/NiceIO/NiceIO.cs @@ -2421,14 +2421,8 @@ class PosixFileSystem : SystemIOFileSystem { public override bool IsSymbolicLink(NPath path) { - PosixNative.Stat stat; - if (PosixNative.lstat(path.ToString(SlashMode.Native), out stat) != 0) - { - var errorCode = Marshal.GetLastWin32Error(); - throw new IOException($"Failed to create stat path {this} (error code {errorCode})", errorCode); - } - - return PosixNative.S_ISLNK(stat.st_mode); + var pathInfo = new FileInfo(path.ToString()); + return pathInfo.Attributes.HasFlag(FileAttributes.ReparsePoint); } public override void CreateSymbolicLink(NPath fromPath, NPath targetPath, bool targetIsFile) @@ -2453,44 +2447,6 @@ static class PosixNative [DllImport("libc", SetLastError = true)] public static extern int symlink([MarshalAs(UnmanagedType.LPStr)] string targetPath, [MarshalAs(UnmanagedType.LPStr)] string linkPath); - - // Notice that this is not a mapping for the normal 'stat' structure, but specifically for MonoPosixHelper's - // own Mono_Posix_Stat structure (in support/map.h). This means we don't need to worry about e.g. Darwin's - // 64bit inode stuff. - [StructLayout(LayoutKind.Sequential)] - public struct Stat - { - public ulong st_dev; // device - public ulong st_ino; // inode - public uint st_mode; // protection - [NonSerialized] -#pragma warning disable 169 - private uint _padding_; // padding for structure alignment -#pragma warning restore 169 - public ulong st_nlink; // number of hard links - public uint st_uid; // user ID of owner - public uint st_gid; // group ID of owner - public ulong st_rdev; // device type (if inode device) - public long st_size; // total size, in bytes - public long st_blksize; // blocksize for filesystem I/O - public long st_blocks; // number of blocks allocated - public long st_atime; // time of last access - public long st_mtime; // time of last modification - public long st_ctime; // time of last status change - public long st_atime_nsec; // Timespec.tv_nsec partner to st_atime - public long st_mtime_nsec; // Timespec.tv_nsec partner to st_mtime - public long st_ctime_nsec; // Timespec.tv_nsec partner to st_ctime - } - - [DllImport("MonoPosixHelper", SetLastError = true, EntryPoint = "Mono_Posix_Syscall_lstat")] - public static extern int lstat(string file_name, out Stat buf); - - private const uint Mono_Posix_FilePermissions_S_IFLNK = 0x0000a000; - - public static bool S_ISLNK(uint m) - { - return (m & Mono_Posix_FilePermissions_S_IFLNK) == Mono_Posix_FilePermissions_S_IFLNK; - } } } diff --git a/External/baselib/baselib/CSharp/BindingsUnity/Baselib_ErrorState.gen.binding.cs b/External/baselib/baselib/CSharp/BindingsUnity/Baselib_ErrorState.gen.binding.cs index 47670845a4..9274a5bfc0 100644 --- a/External/baselib/baselib/CSharp/BindingsUnity/Baselib_ErrorState.gen.binding.cs +++ b/External/baselib/baselib/CSharp/BindingsUnity/Baselib_ErrorState.gen.binding.cs @@ -55,7 +55,7 @@ public enum Baselib_ErrorState_ExplainVerbosity : Int32 ErrorType = 0x0, /// /// Include error type with platform specific value (if specified), - /// source location (subject to BASELIB_ENABLE_SOURCELOCATION define) and an error explanation if available. + /// source location and an error explanation if available. /// ErrorType_SourceLocation_Explanation = 0x1, } diff --git a/Modules/AndroidJNI/AndroidApp.bindings.cs b/Modules/AndroidJNI/AndroidApp.bindings.cs deleted file mode 100644 index f7bc5f2e23..0000000000 --- a/Modules/AndroidJNI/AndroidApp.bindings.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Unity C# reference source -// Copyright (c) Unity Technologies. For terms of use, see -// https://unity3d.com/legal/licenses/Unity_Reference_Only_License - -using System; -using UnityEngine.Bindings; - -namespace UnityEngine.Android -{ - [NativeHeader("Modules/AndroidJNI/Public/AndroidApp.bindings.h")] - [StaticAccessor("AndroidApp", StaticAccessorType.DoubleColon)] - [NativeConditional("PLATFORM_ANDROID")] - internal static class AndroidApp - { - private static AndroidJavaObject m_Context; - private static AndroidJavaObject m_Activity; - - public static AndroidJavaObject Context - { - get - { - AcquireContextAndActivity(); - return m_Context; - } - } - - public static AndroidJavaObject Activity - { - get - { - AcquireContextAndActivity(); - return m_Activity; // can be null if context is not an activity - } - } - - private static void AcquireContextAndActivity() - { - if (m_Context != null) - return; - - using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) - { - m_Context = unityPlayer.GetStatic("currentContext"); - m_Activity = unityPlayer.GetStatic("currentActivity"); - } - } - - public static extern IntPtr UnityPlayerRaw { [ThreadSafe] get; } - - private static AndroidJavaObject m_UnityPlayer; - - public static AndroidJavaObject UnityPlayer - { - get - { - if (m_UnityPlayer != null) - return m_UnityPlayer; - - m_UnityPlayer = new AndroidJavaObject(UnityPlayerRaw); - return m_UnityPlayer; - } - } - } -} diff --git a/Modules/AndroidJNI/AndroidApplication.bindings.cs b/Modules/AndroidJNI/AndroidApplication.bindings.cs new file mode 100644 index 0000000000..c6ea473698 --- /dev/null +++ b/Modules/AndroidJNI/AndroidApplication.bindings.cs @@ -0,0 +1,80 @@ +// 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.Threading; +using UnityEngine.Bindings; +using UnityEngine.Scripting; + +namespace UnityEngine.Android +{ + [NativeHeader("Modules/AndroidJNI/Public/AndroidApplication.bindings.h")] + [StaticAccessor("AndroidApplication", StaticAccessorType.DoubleColon)] + public static class AndroidApplication + { + private static SynchronizationContext m_MainThreadSynchronizationContext; + private static AndroidJavaObjectUnityOwned m_Context = null; + private static AndroidJavaObjectUnityOwned m_Activity = null; + private static AndroidJavaObjectUnityOwned m_UnityPlayer = null; + internal static extern IntPtr UnityPlayerRaw { [ThreadSafe] get; } + private static extern IntPtr CurrentContextRaw { [ThreadSafe] get; } + private static extern IntPtr CurrentActivityRaw { [ThreadSafe] get; } + + [RequiredByNativeCode(GenerateProxy = true)] + private static void AcquireMainThreadSynchronizationContext() + { + m_MainThreadSynchronizationContext = UnitySynchronizationContext.Current; + if (m_MainThreadSynchronizationContext == null) + throw new Exception("Failed to acquire main thread synchronization context"); + } + + public static AndroidJavaObject currentContext + { + get + { + return m_Context; + } + } + + public static AndroidJavaObject currentActivity + { + get + { + return m_Activity; + } + } + + + public static AndroidJavaObject unityPlayer + { + get + { + return m_UnityPlayer; + } + } + + private static AndroidConfiguration m_CurrentConfiguration; + + [RequiredByNativeCode(GenerateProxy = true)] + private static void ApplyConfiguration(AndroidConfiguration config, bool notifySubscribers) + { + m_CurrentConfiguration = config; + + if (notifySubscribers) + onConfigurationChanged?.Invoke(m_CurrentConfiguration); + } + + public static AndroidConfiguration currentConfiguration => m_CurrentConfiguration; + + public static event Action onConfigurationChanged; + + public static void InvokeOnUIThread(Action action) + { + } + + public static void InvokeOnUnityMainThread(Action action) + { + } + } +} diff --git a/Modules/AndroidJNI/AndroidJNI.bindings.cs b/Modules/AndroidJNI/AndroidJNI.bindings.cs index 63b2154885..757372651d 100644 --- a/Modules/AndroidJNI/AndroidJNI.bindings.cs +++ b/Modules/AndroidJNI/AndroidJNI.bindings.cs @@ -107,7 +107,7 @@ public static IntPtr CreateJavaProxy(AndroidJavaProxy proxy) var handle = GCHandle.Alloc(proxy); try { - return _AndroidJNIHelper.CreateJavaProxy(AndroidApp.UnityPlayerRaw, GCHandle.ToIntPtr(handle), proxy); + return _AndroidJNIHelper.CreateJavaProxy(AndroidApplication.UnityPlayerRaw, GCHandle.ToIntPtr(handle), proxy); } catch { @@ -392,6 +392,12 @@ public void Dispose() [ThreadSafe] public static extern int DetachCurrentThread(); + [RequiredByNativeCode] + private static void InvokeAction(Action action) => action(); + + [ThreadSafe] + public static extern void InvokeAttached(Action action); + // Returns the version of the native method interface. [ThreadSafe] public static extern int GetVersion(); diff --git a/Modules/AndroidJNI/AndroidJava.cs b/Modules/AndroidJNI/AndroidJava.cs index 79afd50455..6a0a7ad783 100644 --- a/Modules/AndroidJNI/AndroidJava.cs +++ b/Modules/AndroidJNI/AndroidJava.cs @@ -1069,6 +1069,19 @@ internal static ReturnType FromJavaArray(IntPtr jobject) internal GlobalJavaObjectRef m_jclass; // use this for static lookups; reset in subclases } + internal class AndroidJavaObjectUnityOwned : AndroidJavaObject + { + public AndroidJavaObjectUnityOwned(IntPtr jobject) : base(jobject) + { + } + + protected override void Dispose(bool disposing) + { + if (disposing) + throw new Exception("The object is owned by Unity runtime, you shouldn't call Dispose on it."); + base.Dispose(disposing); + } + } public class AndroidJavaClass : AndroidJavaObject { // Construct an AndroidJavaClass from the class name @@ -1880,22 +1893,22 @@ public static string GetSignature(object obj) { return "Ljava/lang/Runnable;"; } - else if (type.Equals(typeof(AndroidJavaClass))) + else if (obj is AndroidJavaClass || obj == (object)type && AndroidReflection.IsAssignableFrom(typeof(AndroidJavaClass), type)) { return "Ljava/lang/Class;"; } - else if (type.Equals(typeof(AndroidJavaObject))) + else if (obj is AndroidJavaObject) { - if (obj == (object)type) - { - return "Ljava/lang/Object;"; - } AndroidJavaObject javaObject = (AndroidJavaObject)obj; using (AndroidJavaObject javaClass = javaObject.Call("getClass")) { return "L" + javaClass.Call("getName") + ";"; } } + else if (obj == (object)type && AndroidReflection.IsAssignableFrom(typeof(AndroidJavaObject), type)) + { + return "Ljava/lang/Object;"; + } else if (AndroidReflection.IsAssignableFrom(typeof(System.Array), type)) { if (type.GetArrayRank() != 1) diff --git a/Modules/AndroidJNI/Configuration/AndroidColorModeHdr.cs b/Modules/AndroidJNI/Configuration/AndroidColorModeHdr.cs new file mode 100644 index 0000000000..ef230a91a2 --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidColorModeHdr.cs @@ -0,0 +1,13 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEngine.Android +{ + public enum AndroidColorModeHdr : int + { + Undefined = 0, + No = 4, + Yes = 8, + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidColorModeWideColorGamut.cs b/Modules/AndroidJNI/Configuration/AndroidColorModeWideColorGamut.cs new file mode 100644 index 0000000000..c3cc16deee --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidColorModeWideColorGamut.cs @@ -0,0 +1,13 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEngine.Android +{ + public enum AndroidColorModeWideColorGamut : int + { + Undefined = 0, + No = 1, + Yes = 2, + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidConfiguration.cs b/Modules/AndroidJNI/Configuration/AndroidConfiguration.cs new file mode 100644 index 0000000000..5e3d6612c4 --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidConfiguration.cs @@ -0,0 +1,114 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System.Runtime.InteropServices; +using System.Text; +using UnityEngine.Bindings; +using UnityEngine.Scripting; + +namespace UnityEngine.Android +{ + public class AndroidLocale + { + public string country { get; } + public string language { get; } + + internal AndroidLocale(string _country, string _language) + { + country = _country; + language = _language; + } + } + + [NativeAsStruct] + [NativeType(Header = "Modules/AndroidJNI/Public/AndroidConfiguration.bindings.h")] + [RequiredByNativeCode] + [StructLayout(LayoutKind.Sequential)] + public sealed class AndroidConfiguration + { + const int UiModeNightMask = 48; + const int UiModeTypeMask = 15; + + const int ScreenLayoutDirectionMask = 192; + const int ScreenLayoutLongMask = 48; + const int ScreenLayoutRoundMask = 768; + const int ScreenLayoutSizeMask = 15; + + const int ColorModeHdrMask = 12; + const int ColorModeWideColorGamutMask = 3; + + private int colorMode { get; } + public int densityDpi { get; } + public float fontScale { get; } + public int fontWeightAdjustment { get; } + public AndroidKeyboard keyboard { get; } + public AndroidHardwareKeyboardHidden hardKeyboardHidden { get; } + public AndroidKeyboardHidden keyboardHidden { get; } + public int mobileCountryCode { get; } + public int mobileNetworkCode { get; } + public AndroidNavigation navigation { get; } + public AndroidNavigationHidden navigationHidden { get; } + public AndroidOrientation orientation { get; } + public int screenHeightDp { get; } + public int screenWidthDp { get; } + public int smallestScreenWidthDp { get; } + private int screenLayout { get; } + public AndroidTouchScreen touchScreen { get; } + private int uiMode { get; } + private string primaryLocaleCountry { get; } + private string primaryLocaleLanguage { get; } + // Having this as an array, because it seems you can have multiple locales set, but for now we can only acquire primary locale + // In case we'll have a way to acquire multiple locales in the future, have this as an array to prevent API changes + public AndroidLocale[] locales => new[] { new AndroidLocale(primaryLocaleCountry, primaryLocaleLanguage) }; + + // Below properties are not marshalled + public AndroidColorModeHdr colorModeHdr => (AndroidColorModeHdr)(colorMode & ColorModeHdrMask); + public AndroidColorModeWideColorGamut colorModeWideColorGamut => (AndroidColorModeWideColorGamut)(colorMode & ColorModeWideColorGamutMask); + public AndroidScreenLayoutDirection screenLayoutDirection => (AndroidScreenLayoutDirection)(screenLayout & ScreenLayoutDirectionMask); + public AndroidScreenLayoutLong screenLayoutLong => (AndroidScreenLayoutLong)(screenLayout & ScreenLayoutLongMask); + public AndroidScreenLayoutRound screenLayoutRound => (AndroidScreenLayoutRound)(screenLayout & ScreenLayoutRoundMask); + public AndroidScreenLayoutSize screenLayoutSize => (AndroidScreenLayoutSize)(screenLayout & ScreenLayoutSizeMask); + public AndroidUIModeNight uiModeNight => (AndroidUIModeNight)(uiMode & UiModeNightMask); + public AndroidUIModeType uiModeType => (AndroidUIModeType)(uiMode & UiModeTypeMask); + + [Preserve] + public override string ToString() + { + var contents = new StringBuilder(); + + contents.AppendLine($"* ColorMode, Hdr: {colorModeHdr}"); + contents.AppendLine($"* ColorMode, Gamut: {colorModeWideColorGamut}"); + contents.AppendLine($"* DensityDpi: {densityDpi}"); + contents.AppendLine($"* FontScale: {fontScale}"); + contents.AppendLine($"* FontWeightAdj: {fontWeightAdjustment}"); + contents.AppendLine($"* Keyboard: {keyboard}"); + contents.AppendLine($"* Keyboard Hidden, Hard: {hardKeyboardHidden}"); + contents.AppendLine($"* Keyboard Hidden, Normal: {keyboardHidden}"); + contents.AppendLine($"* Mcc: {mobileCountryCode}"); + contents.AppendLine($"* Mnc: {mobileNetworkCode}"); + contents.AppendLine($"* Navigation: {navigation}"); + contents.AppendLine($"* NavigationHidden: {navigationHidden}"); + contents.AppendLine($"* Orientation: {orientation}"); + contents.AppendLine($"* ScreenHeightDp: {screenHeightDp}"); + contents.AppendLine($"* ScreenWidthDp: {screenWidthDp}"); + contents.AppendLine($"* SmallestScreenWidthDp: {smallestScreenWidthDp}"); + contents.AppendLine($"* ScreenLayout, Direction: {screenLayoutDirection}"); + contents.AppendLine($"* ScreenLayout, Size: {screenLayoutSize}"); + contents.AppendLine($"* ScreenLayout, Long: {screenLayoutLong}"); + contents.AppendLine($"* ScreenLayout, Round: {screenLayoutRound}"); + contents.AppendLine($"* TouchScreen: {touchScreen}"); + contents.AppendLine($"* UiMode, Night: {uiModeNight}"); + contents.AppendLine($"* UiMode, Type: {uiModeType}"); + + contents.AppendLine($"* Locales ({locales.Length}):"); + for (int i = 0; i < locales.Length; i++) + { + var l = locales[i]; + contents.AppendLine($"* Locale[{i}] {l.country}-{l.language}"); + }; + + return contents.ToString(); + } + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidHardwareKeyboardHidden.cs b/Modules/AndroidJNI/Configuration/AndroidHardwareKeyboardHidden.cs new file mode 100644 index 0000000000..cd55026bed --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidHardwareKeyboardHidden.cs @@ -0,0 +1,13 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEngine.Android +{ + public enum AndroidHardwareKeyboardHidden : int + { + Undefined = 0, + No = 1, + Yes = 2 + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidKeyboard.cs b/Modules/AndroidJNI/Configuration/AndroidKeyboard.cs new file mode 100644 index 0000000000..a3f3eacce5 --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidKeyboard.cs @@ -0,0 +1,14 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEngine.Android +{ + public enum AndroidKeyboard : int + { + Undefined = 0, + NoKeys = 1, + Qwerty = 2, + _12Key = 3 + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidKeyboardHidden.cs b/Modules/AndroidJNI/Configuration/AndroidKeyboardHidden.cs new file mode 100644 index 0000000000..9d01e8dfdb --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidKeyboardHidden.cs @@ -0,0 +1,13 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEngine.Android +{ + public enum AndroidKeyboardHidden : int + { + Undefined = 0, + No = 1, + Yes = 2 + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidNavigation.cs b/Modules/AndroidJNI/Configuration/AndroidNavigation.cs new file mode 100644 index 0000000000..524a89e8ac --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidNavigation.cs @@ -0,0 +1,15 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEngine.Android +{ + public enum AndroidNavigation : int + { + Undefined = 0, + NoNav = 1, + Dpad = 2, + TrackBall = 3, + Wheel = 4, + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidNavigationHidden.cs b/Modules/AndroidJNI/Configuration/AndroidNavigationHidden.cs new file mode 100644 index 0000000000..719d20b6e1 --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidNavigationHidden.cs @@ -0,0 +1,13 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEngine.Android +{ + public enum AndroidNavigationHidden : int + { + Undefined = 0, + No = 1, + Yes = 2 + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidOrientation.cs b/Modules/AndroidJNI/Configuration/AndroidOrientation.cs new file mode 100644 index 0000000000..15dfdb50ff --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidOrientation.cs @@ -0,0 +1,13 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEngine.Android +{ + public enum AndroidOrientation : int + { + Undefined = 0, + Portrait = 1, + Landscape = 2 + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidScreenLayoutDirection.cs b/Modules/AndroidJNI/Configuration/AndroidScreenLayoutDirection.cs new file mode 100644 index 0000000000..4ed279a4e1 --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidScreenLayoutDirection.cs @@ -0,0 +1,14 @@ +// 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 UnityEngine.Android +{ + public enum AndroidScreenLayoutDirection : int + { + LTR = 64, + RTL = 128 + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidScreenLayoutLong.cs b/Modules/AndroidJNI/Configuration/AndroidScreenLayoutLong.cs new file mode 100644 index 0000000000..301b99978c --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidScreenLayoutLong.cs @@ -0,0 +1,15 @@ +// 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 UnityEngine.Android +{ + public enum AndroidScreenLayoutLong : int + { + Undefined = 0, + No = 16, + Yes = 32 + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidScreenLayoutRound.cs b/Modules/AndroidJNI/Configuration/AndroidScreenLayoutRound.cs new file mode 100644 index 0000000000..774bedb3f7 --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidScreenLayoutRound.cs @@ -0,0 +1,15 @@ +// 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 UnityEngine.Android +{ + public enum AndroidScreenLayoutRound : int + { + Undefined = 0, + No = 256, + Yes = 512 + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidScreenLayoutSize.cs b/Modules/AndroidJNI/Configuration/AndroidScreenLayoutSize.cs new file mode 100644 index 0000000000..ac1febd556 --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidScreenLayoutSize.cs @@ -0,0 +1,17 @@ +// 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 UnityEngine.Android +{ + public enum AndroidScreenLayoutSize : int + { + Undefined = 0, + Small = 1, + Normal = 2, + Large = 3, + XLarge = 4 + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidTouchScreen.cs b/Modules/AndroidJNI/Configuration/AndroidTouchScreen.cs new file mode 100644 index 0000000000..d26a6f2de4 --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidTouchScreen.cs @@ -0,0 +1,13 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEngine.Android +{ + public enum AndroidTouchScreen : int + { + Undefined = 0, + NoTouch = 1, + Finger = 3 + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidUiModeNight.cs b/Modules/AndroidJNI/Configuration/AndroidUiModeNight.cs new file mode 100644 index 0000000000..3c8e0f3028 --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidUiModeNight.cs @@ -0,0 +1,15 @@ +// 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 UnityEngine.Android +{ + public enum AndroidUIModeNight : int + { + Undefined = 0, + No = 16, + Yes = 32 + } +} diff --git a/Modules/AndroidJNI/Configuration/AndroidUiModeType.cs b/Modules/AndroidJNI/Configuration/AndroidUiModeType.cs new file mode 100644 index 0000000000..7cfe8f3c3e --- /dev/null +++ b/Modules/AndroidJNI/Configuration/AndroidUiModeType.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; + +namespace UnityEngine.Android +{ + public enum AndroidUIModeType : int + { + Undefined = 0, + Normal = 1, + Desk = 2, + Car = 3, + Television = 4, + Appliance = 5, + Watch = 6, + VrHeadset = 7 + } +} diff --git a/Modules/BuildProfileEditor/BuildProfilePlayerSettingsEditor.cs b/Modules/BuildProfileEditor/BuildProfilePlayerSettingsEditor.cs index 0ac2bdf865..b33d90a0f9 100644 --- a/Modules/BuildProfileEditor/BuildProfilePlayerSettingsEditor.cs +++ b/Modules/BuildProfileEditor/BuildProfilePlayerSettingsEditor.cs @@ -99,7 +99,9 @@ internal void ShowPlayerSettingsEditor() { m_PlayerSettingsHelpBox.Hide(); - if (m_Profile.playerSettings == null) + bool createPlayerSettings = m_Profile.playerSettings == null; + + if (createPlayerSettings) { BuildProfileModuleUtil.CreatePlayerSettingsFromGlobal(m_Profile); UpdateBuildProfile(); @@ -107,6 +109,9 @@ internal void ShowPlayerSettingsEditor() CreatePlayerSettingsInspector(); + if (createPlayerSettings && m_PlayerSettingsEditor.CopyProjectSettingsToPlayerSettingsExtension()) + UpdateBuildProfile(); + m_PlayerSettingsOptions.clicked += PlayerSettingsOptionMenu; m_PlayerSettingsOptions.Show(); m_PlayerSettingsFoldout.Show(); @@ -124,7 +129,7 @@ void CreatePlayerSettingsInspector() { var isActiveProfile = BuildProfile.GetActiveBuildProfile() == m_Profile; m_PlayerSettingsEditor = Editor.CreateEditor(m_Profile.playerSettings) as PlayerSettingsEditor; - m_PlayerSettingsEditor.ConfigurePlayerSettingsForBuildProfile(m_Profile.moduleName, m_Profile.subtarget == StandaloneBuildSubtarget.Server, isActiveProfile); + m_PlayerSettingsEditor.ConfigurePlayerSettingsForBuildProfile(m_ProfileSerializedObject, m_Profile.moduleName, m_Profile.subtarget == StandaloneBuildSubtarget.Server, isActiveProfile); } if (m_PlayerSettingsInspector == null) @@ -169,6 +174,7 @@ void ShowPlayerSettingsHelpBox() void PlayerSettingsOptionMenu() { bool isDataSameAsProjSettings = BuildProfileModuleUtil.IsDataEqualToProjectSettings(m_Profile.playerSettings); + isDataSameAsProjSettings = isDataSameAsProjSettings && m_PlayerSettingsEditor.IsPlayerSettingsExtensionDataEqualToProjectSettings(); var menu = new GenericMenu(); menu.AddItem(TrText.playerSetttingsRemove, false, RemovePlayerSettings); menu.AddItem(TrText.playerSettingsReset, false, isDataSameAsProjSettings ? null : ResetToProjectSettingsValues); @@ -212,6 +218,7 @@ void ResetToProjectSettingsValues() var playerSettings = AssetDatabase.LoadAssetAtPath(k_ProjectSettingsPath); var preset = new Preset(playerSettings); preset.ApplyTo(m_Profile.playerSettings); + m_PlayerSettingsEditor.CopyProjectSettingsToPlayerSettingsExtension(); UpdateBuildProfile(); diff --git a/Modules/EditorToolbar/Controls/ToolButton.cs b/Modules/EditorToolbar/Controls/ToolButton.cs index c2fc685448..9aeaf70afb 100644 --- a/Modules/EditorToolbar/Controls/ToolButton.cs +++ b/Modules/EditorToolbar/Controls/ToolButton.cs @@ -231,7 +231,7 @@ void OnMouseUp(MouseUpEvent evt) { if (value && m_TargetTool == Tool.Custom) ToolManager.RestorePreviousTool(); - else + else ToolManager.SetActiveTool(currentVariant); } @@ -250,6 +250,8 @@ void OnAttachedToPanel(AttachToPanelEvent evt) Tools.viewToolChanged += UpdateViewToolContent; UpdateViewToolContent(); } + + EditorApplication.delayCall += UpdateState; } void OnDetachFromPanel(DetachFromPanelEvent evt) @@ -332,7 +334,7 @@ void UpdateContent() break; } } - + void ClearButtonClassList() { RemoveFromClassList(s_UssClassName_MoveTool); @@ -353,12 +355,20 @@ void UpdateState() var missing = EditorToolUtility.GetEditorToolWithEnum(m_TargetTool) is NoneTool; var display = missing ? DisplayStyle.None : DisplayStyle.Flex; + var enabled = currentVariant.IsAvailable(); if (style.display != display) { style.display = display; displayChanged?.Invoke(); } + + if (enabledSelf != enabled) + enabledSelf = enabled; + + // Break the delayCall chain if button's dettached from panel + if (panel != null) + EditorApplication.delayCall += UpdateState; } bool IsActiveTool() diff --git a/Modules/EditorToolbar/ToolbarElements/CloudButton.cs b/Modules/EditorToolbar/ToolbarElements/CloudButton.cs index 94484a7e80..afe0969c4b 100644 --- a/Modules/EditorToolbar/ToolbarElements/CloudButton.cs +++ b/Modules/EditorToolbar/ToolbarElements/CloudButton.cs @@ -15,10 +15,10 @@ sealed class CloudButton : EditorToolbarButton public CloudButton() : base(OpenCloudWindow) { name = "Cloud"; - - icon = EditorGUIUtility.FindTexture("CloudConnect"); tooltip = L10n.Tr("Manage services"); + this.Q(className: EditorToolbar.elementIconClassName).style.display = DisplayStyle.Flex; + RegisterCallback(OnAttachedToPanel); RegisterCallback(OnDetachFromPanel); } diff --git a/Modules/EditorToolbar/ToolbarElements/LayoutDropdown.cs b/Modules/EditorToolbar/ToolbarElements/LayoutDropdown.cs index 0f027b6823..40beda4fb6 100644 --- a/Modules/EditorToolbar/ToolbarElements/LayoutDropdown.cs +++ b/Modules/EditorToolbar/ToolbarElements/LayoutDropdown.cs @@ -18,6 +18,8 @@ public LayoutDropdown() clicked += () => OpenLayoutWindow(worldBound); tooltip = L10n.Tr("Select editor layout"); + this.Q(className: EditorToolbar.elementIconClassName).style.display = DisplayStyle.Flex; + RegisterCallback(OnAttachedToPanel); RegisterCallback(OnDetachFromPanel); EditorApplication.delayCall += CheckAvailability; //Immediately after a domain reload, calling check availability sometimes returns the wrong value diff --git a/Modules/EditorToolbar/ToolbarElements/OverlayMenu.cs b/Modules/EditorToolbar/ToolbarElements/OverlayMenu.cs index 7d99b92857..0d8d7c8df2 100644 --- a/Modules/EditorToolbar/ToolbarElements/OverlayMenu.cs +++ b/Modules/EditorToolbar/ToolbarElements/OverlayMenu.cs @@ -130,12 +130,16 @@ static void PopulateDefaultMenuItems(GenericMenu menu, EditorWindow targetWindow if (targetWindow is ISupportsOverlays) { var binding = ShortcutManager.instance.GetShortcutBinding(k_ShowOverlayMenuShortcut); + var itemContent = EditorGUIUtility.TrTextContent($"Overlay Menu _{binding}"); - menu.AddItem(EditorGUIUtility.TrTextContent($"Overlay Menu _{binding}"), false, - () => - { - targetWindow.overlayCanvas.ShowPopup(); - }); + + if (targetWindow.overlayCanvas.overlaysSupportEnabled) + { + menu.AddItem(itemContent, false, + () => { targetWindow.overlayCanvas.ShowPopup(); }); + } + else + menu.AddDisabledItem(itemContent); } } diff --git a/Modules/EditorToolbar/ToolbarElements/UndoButton.cs b/Modules/EditorToolbar/ToolbarElements/UndoButton.cs index a31fbabcf6..92587f8f22 100644 --- a/Modules/EditorToolbar/ToolbarElements/UndoButton.cs +++ b/Modules/EditorToolbar/ToolbarElements/UndoButton.cs @@ -15,7 +15,8 @@ sealed class UndoButton : EditorToolbarButton public UndoButton() : base(OpenUndoHistoryWindow) { name = "History"; - icon = EditorGUIUtility.FindTexture("UndoHistory"); + + this.Q(className: EditorToolbar.elementIconClassName).style.display = DisplayStyle.Flex; RegisterCallback(OnAttachedToPanel); RegisterCallback(OnDetachFromPanel); diff --git a/Modules/EmbreeEditor/Embree.bindings.cs b/Modules/EmbreeEditor/Embree.bindings.cs new file mode 100644 index 0000000000..3ca5fc2af9 --- /dev/null +++ b/Modules/EmbreeEditor/Embree.bindings.cs @@ -0,0 +1,44 @@ +// 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; +using UnityEngine.Bindings; +using UnityEngine.Scripting; + +namespace UnityEditor.Embree +{ + [StructLayout(LayoutKind.Sequential)] + [RequiredByNativeCode] + public struct GpuBvhPrimitiveDescriptor + { + public Vector3 lowerBound { get; set; } + public Vector3 upperBound { get; set; } + public uint primID { get; set; } + } + + [StructLayout(LayoutKind.Sequential)] + [RequiredByNativeCode] + public struct GpuBvhBuildOptions + { + public GpuBvhBuildQuality quality { get; set; } + public uint minLeafSize { get; set; } + public uint maxLeafSize { get; set; } + public bool allowPrimitiveSplits { get; set; } + }; + + public enum GpuBvhBuildQuality : int + { + Low = 0, Medium, High + }; + + [NativeHeader("Modules/EmbreeEditor/Embree.bindings.h")] + public static class GpuBvh + { + [return: Unmarshalled] + extern public static uint[] Build(GpuBvhBuildOptions options, Span prims); + + } +} diff --git a/Modules/PackageManager/Editor/Managed/ResolutionStrategy.cs b/Modules/PackageManager/Editor/Managed/ResolutionStrategy.cs new file mode 100644 index 0000000000..712eaf00de --- /dev/null +++ b/Modules/PackageManager/Editor/Managed/ResolutionStrategy.cs @@ -0,0 +1,13 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +namespace UnityEditor.PackageManager +{ + internal enum ResolutionStrategy + { + HighestPatch, + HighestMinor, + Highest + } +} diff --git a/Modules/PackageManager/Editor/Managed/SemVersionHelper.cs b/Modules/PackageManager/Editor/Managed/SemVersionHelper.cs new file mode 100644 index 0000000000..e01a9bcfec --- /dev/null +++ b/Modules/PackageManager/Editor/Managed/SemVersionHelper.cs @@ -0,0 +1,63 @@ +// 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.Scripting.ScriptCompilation; + +namespace UnityEditor.PackageManager +{ + internal class SemVersionHelper + { + public static string MaxSatisfying(String version, string[] versions, ResolutionStrategy resolutionStrategy = ResolutionStrategy.Highest, bool includePrereleases = false) + { + SemVersion baseVersion = ParseVersion(version); + SemVersion? maxValue = null; + + if (versions.Length == 0) + { + throw new ArgumentException("No Semver versions to process."); + } + + foreach (var v in versions) + { + SemVersion candidate = ParseVersion(v); + + if (!includePrereleases && !string.IsNullOrEmpty(candidate.Prerelease)) + { + continue; + } + + if (candidate < baseVersion || maxValue > candidate) + { + continue; + } + + if (!SatisfiesResolutionStrategy(candidate, baseVersion, resolutionStrategy)) { + continue; + } + + maxValue = candidate; + } + + return maxValue?.ToString(); + } + + private static bool SatisfiesResolutionStrategy(SemVersion candidate, SemVersion version, ResolutionStrategy resolutionStrategy) { + switch (resolutionStrategy) { + case ResolutionStrategy.HighestPatch: + return candidate.Major == version.Major && candidate.Minor == version.Minor; + case ResolutionStrategy.HighestMinor: + return candidate.Major == version.Major; + default: + return true; + } + } + + private static SemVersion ParseVersion(string version) + { + return SemVersionParser.Parse(version); + } + } +} diff --git a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadManager.cs b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadManager.cs index 120f9a8672..b849ff6575 100644 --- a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadManager.cs +++ b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadManager.cs @@ -306,7 +306,7 @@ private void OnAssetStoreCacheConfigChange(CachePathConfig config) if (!m_Application.isBatchMode) m_Application.DisplayDialog("assetCacheLocationChanged", L10n.Tr("Assets Cache location changed"), - L10n.Tr("The Assets Cache location has been changed, all current downloads will be aborted."), + L10n.Tr("The Assets Cache location has been changed, all current downloads will be canceled."), L10n.Tr("Ok")); AbortAllDownloads(); diff --git a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadOperation.cs b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadOperation.cs index b2008c8834..08dfffa3d9 100644 --- a/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadOperation.cs +++ b/Modules/PackageManagerUI/Editor/Services/AssetStore/AssetStoreDownloadOperation.cs @@ -15,7 +15,7 @@ namespace UnityEditor.PackageManager.UI.Internal internal class AssetStoreDownloadOperation : IOperation { internal static readonly string k_DownloadErrorMessage = L10n.Tr("The download could not be completed. See details in console."); - internal static readonly string k_AbortErrorMessage = L10n.Tr("The download could not be aborted. Please try again."); + internal static readonly string k_AbortErrorMessage = L10n.Tr("The download could not be canceled. Please try again."); internal static readonly string k_AssetStoreDownloadPrefix = "content__"; internal static readonly string k_NotPurchasedErrorMessage = L10n.Tr("The Asset Store package you are trying to download is not available to the current Unity account. If you purchased this asset from the Asset Store using a different account, use that Unity account to sign into the Editor."); internal static readonly string k_ForbiddenErrorMessage = L10n.Tr("The Asset Store package couldn't be downloaded at this time. Please try again later. Should the issue persist, please contact our customer support for assistance."); diff --git a/Modules/PackageManagerUI/Editor/Services/Common/Package.cs b/Modules/PackageManagerUI/Editor/Services/Common/Package.cs index 0bcdf39101..57f9e23e26 100644 --- a/Modules/PackageManagerUI/Editor/Services/Common/Package.cs +++ b/Modules/PackageManagerUI/Editor/Services/Common/Package.cs @@ -60,14 +60,17 @@ public PackageState state if (numErrors > 0 && numWarnings == numErrors || isDeprecated) return PackageState.Warning; - var latestKeyVersion = versions.key.LastOrDefault(); if (primary.HasTag(PackageTag.Custom)) return PackageState.InDevelopment; + if (isLocked) + return PackageState.Locked; + if (primary.isInstalled && !primary.isDirectDependency) return PackageState.InstalledAsDependency; var recommended = versions.recommended; + var latestKeyVersion = versions.key.LastOrDefault(); if (recommended != null && primary != recommended && ((primary.isInstalled && primary != latestKeyVersion) || primary.HasTag(PackageTag.LegacyFormat)) && !primary.HasTag(PackageTag.Local)) return PackageState.UpdateAvailable; @@ -99,6 +102,10 @@ public PackageState state private bool m_IsDeprecated; public virtual bool isDeprecated => m_IsDeprecated; + [SerializeField] + private bool m_IsLocked; + public virtual bool isLocked => m_IsLocked; + // errors on the package level (not just about a particular version) [SerializeField] private List m_Errors; @@ -139,7 +146,7 @@ public void OnAfterDeserialize() LinkPackageAndVersions(); } - private Package(string name, IVersionList versionList, Product product = null, bool isDiscoverable = true, bool isDeprecated = false, string deprecationMessage = null) + private Package(string name, IVersionList versionList, Product product = null, bool isDiscoverable = true, bool isDeprecated = false, string deprecationMessage = null, bool isLocked = false) { m_Name = name; m_VersionList = versionList; @@ -154,6 +161,8 @@ private Package(string name, IVersionList versionList, Product product = null, b m_IsDeprecated = versionList.primary?.HasTag(PackageTag.InstalledFromPath) == false && isDeprecated; m_DeprecationMessage = deprecationMessage; + m_IsLocked = isLocked; + LinkPackageAndVersions(); } @@ -162,9 +171,9 @@ private Package(string name, IVersionList versionList, Product product = null, b // package modifications that's not caught by the package change events. internal class Factory : BaseService { - public Package CreatePackage(string name, IVersionList versionList, Product product = null, bool isDiscoverable = true, bool isDeprecated = false, string deprecationMessage = null) + public Package CreatePackage(string name, IVersionList versionList, Product product = null, bool isDiscoverable = true, bool isDeprecated = false, string deprecationMessage = null, bool isLocked = false) { - return new Package(name, versionList, product, isDiscoverable, isDeprecated, deprecationMessage); + return new Package(name, versionList, product, isDiscoverable, isDeprecated, deprecationMessage, isLocked); } public void AddError(Package package, UIError error) diff --git a/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackage.cs b/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackage.cs index de9c0b74e9..211b697adc 100644 --- a/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackage.cs +++ b/Modules/PackageManagerUI/Editor/Services/Interfaces/IPackage.cs @@ -2,7 +2,6 @@ // 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.PackageManager.UI @@ -43,5 +42,7 @@ internal interface IPackage : UI.IPackage string deprecationMessage { get; } bool isDeprecated { get; } + + bool isLocked { get; } } } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/AddAction.cs b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/AddAction.cs index 28496e91b7..777d385102 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/AddAction.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/AddAction.cs @@ -28,7 +28,8 @@ public AddAction(IPackageOperationDispatcher operationDispatcher, IApplicationPr protected override bool TriggerActionImplementation(IList packages) { var primaryVersions = packages.Select(p => p.versions.primary).ToArray(); - m_OperationDispatcher.Install(primaryVersions); + if(!m_OperationDispatcher.Install(primaryVersions)) + return false; // 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", primaryVersions); @@ -76,7 +77,8 @@ protected override bool TriggerActionImplementation(IPackageVersion version) if (version.package.isDeprecated && !m_Application.DisplayDialog("installDeprecatedPackage", L10n.Tr("Deprecated package installation"), L10n.Tr("Are you sure you want to install this deprecated package?"), L10n.Tr("Install"), L10n.Tr("Cancel"))) return false; - m_OperationDispatcher.Install(version); + if (!m_OperationDispatcher.Install(version)) + return false; PackageManagerWindowAnalytics.SendEvent(eventName, version); } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/GitUpdateAction.cs b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/GitUpdateAction.cs index d1d24a2743..84ae0a9d51 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/GitUpdateAction.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/GitUpdateAction.cs @@ -22,7 +22,10 @@ protected override bool TriggerActionImplementation(IPackageVersion version) { var installedVersion = version.package.versions.installed; var packageInfo = m_UpmCache.GetBestMatchPackageInfo(installedVersion.name, true); - m_OperationDispatcher.Install(packageInfo.packageId); + + if (!m_OperationDispatcher.Install(packageInfo.packageId)) + return false; + PackageManagerWindowAnalytics.SendEvent("updateGit", installedVersion.uniqueId); return true; } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/UpdateAction.cs b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/UpdateAction.cs index 88d559558d..3710286530 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/Actions/UpdateAction.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/Actions/UpdateAction.cs @@ -35,7 +35,8 @@ public UpdateAction(IPackageOperationDispatcher operationDispatcher, protected override bool TriggerActionImplementation(IList packages) { - m_OperationDispatcher.Install(packages.Select(p => p?.versions.GetUpdateTarget(p.versions.primary))); + if (!m_OperationDispatcher.Install(packages.Select(p => p?.versions.GetUpdateTarget(p.versions.primary)))) + return false; // 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", packages.Select(p => p.versions.primary)); @@ -100,7 +101,8 @@ protected override bool TriggerActionImplementation(IPackageVersion version) } else { - m_OperationDispatcher.Install(targetVersion); + if (!m_OperationDispatcher.Install(targetVersion)) + return false; var installRecommended = version.package.versions.recommended == targetVersion ? "Recommended" : "NonRecommended"; var eventName = $"installUpdate{installRecommended}"; diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageOperationDispatcher.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageOperationDispatcher.cs index 1a2801aa2e..b32b83eece 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageOperationDispatcher.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageOperationDispatcher.cs @@ -15,10 +15,10 @@ internal interface IPackageOperationDispatcher : IService bool IsUninstallInProgress(IPackage package); bool IsInstallInProgress(IPackageVersion version); - void Install(IPackageVersion version); - void Install(IEnumerable versions); - void Install(string packageId); - void InstallFromUrl(string url); + bool Install(IPackageVersion version); + bool Install(IEnumerable versions); + bool Install(string packageId); + bool InstallFromUrl(string url); bool InstallFromPath(string path, out string tempPackageId); void Uninstall(IPackage package); void Uninstall(IEnumerable packages); @@ -59,6 +59,7 @@ public PackageOperationDispatcher(IAssetStorePackageInstaller assetStorePackageI public bool isInstallOrUninstallInProgress => m_UpmClient.isAddOrRemoveInProgress; + private string InstallOrRemoveInProgressWarningMessage(string installSource) => string.Format(L10n.Tr("[Package Manager Window] The request to install {0} will be canceled due to an ongoing Install/Remove operation. Please retry your request once the current operation has completed."), installSource); public bool IsUninstallInProgress(IPackage package) { return m_UpmClient.IsRemoveInProgress(package?.name); @@ -69,33 +70,54 @@ public bool IsInstallInProgress(IPackageVersion version) return m_UpmClient.IsAddInProgress(version?.packageId); } - public void Install(IPackageVersion version) + public bool Install(IPackageVersion version) { if (version == null || version.isInstalled) - return; + return false; + m_UpmClient.AddById(version.packageId); + return true; } - public void Install(IEnumerable versions) + public bool Install(IEnumerable versions) { if (versions == null || !versions.Any()) - return; + return false; m_UpmClient.AddByIds(versions.Select(v => v.packageId)); + return true; } - public void Install(string packageId) + public bool Install(string packageId) { + if (isInstallOrUninstallInProgress) + { + Debug.LogWarning(InstallOrRemoveInProgressWarningMessage(packageId)); + return false; + } m_UpmClient.AddById(packageId); + return true; } - public void InstallFromUrl(string url) + public bool InstallFromUrl(string url) { + if (isInstallOrUninstallInProgress) + { + Debug.LogWarning(InstallOrRemoveInProgressWarningMessage(url)); + return false; + } m_UpmClient.AddByUrl(url); + return true; } public bool InstallFromPath(string path, out string tempPackageId) { + if (isInstallOrUninstallInProgress) + { + tempPackageId = null; + Debug.LogWarning(InstallOrRemoveInProgressWarningMessage(path)); + return false; + } return m_UpmClient.AddByPath(path, out tempPackageId); } diff --git a/Modules/PackageManagerUI/Editor/Services/Packages/PackageState.cs b/Modules/PackageManagerUI/Editor/Services/Packages/PackageState.cs index 1637810a77..0d96a7f2eb 100644 --- a/Modules/PackageManagerUI/Editor/Services/Packages/PackageState.cs +++ b/Modules/PackageManagerUI/Editor/Services/Packages/PackageState.cs @@ -4,6 +4,7 @@ namespace UnityEditor.PackageManager.UI.Internal { + // If a new state is added to this list, make sure to sync up the PackageItem.k_TooltipsByProgress array internal enum PackageState { None = 0, @@ -16,6 +17,8 @@ internal enum PackageState UpdateAvailable, InProgress, Error, - Warning + Warning, + Locked, + UnlockedByUser } } diff --git a/Modules/PackageManagerUI/Editor/Services/Pages/SimplePage.cs b/Modules/PackageManagerUI/Editor/Services/Pages/SimplePage.cs index 277b4050f6..414e3203be 100644 --- a/Modules/PackageManagerUI/Editor/Services/Pages/SimplePage.cs +++ b/Modules/PackageManagerUI/Editor/Services/Pages/SimplePage.cs @@ -115,8 +115,7 @@ protected virtual void SortGroupNames(List groupNames) public override bool GetDefaultLockState(IPackage package) { - return package.versions.installed?.isDirectDependency != true && - m_PackageDatabase.GetFeaturesThatUseThisPackage(package.versions.installed)?.Any() == true; + return package.isLocked; } // All the following load functions do nothing, because for a SimplePage we already know the complete list and there's no more to load diff --git a/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageFactory.cs b/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageFactory.cs index 4ff268121c..5fc097ca28 100644 --- a/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageFactory.cs +++ b/Modules/PackageManagerUI/Editor/Services/Upm/UpmPackageFactory.cs @@ -32,8 +32,8 @@ public UpmPackageFactory(IUniqueIdMapper uniqueIdMapper, public override void OnEnable() { - m_SettingsProxy.onEnablePreReleasePackagesChanged += OnShowPreReleasePackagesesOrSeeAllVersionsChanged; - m_SettingsProxy.onSeeAllVersionsChanged += OnShowPreReleasePackagesesOrSeeAllVersionsChanged; + m_SettingsProxy.onEnablePreReleasePackagesChanged += OnShowPreReleasePackagesOrSeeAllVersionsChanged; + m_SettingsProxy.onSeeAllVersionsChanged += OnShowPreReleasePackagesOrSeeAllVersionsChanged; m_UpmCache.onPackageInfosUpdated += OnPackageInfosUpdated; m_UpmCache.onExtraPackageInfoFetched += OnExtraPackageInfoFetched; @@ -45,8 +45,8 @@ public override void OnEnable() public override void OnDisable() { - m_SettingsProxy.onEnablePreReleasePackagesChanged -= OnShowPreReleasePackagesesOrSeeAllVersionsChanged; - m_SettingsProxy.onSeeAllVersionsChanged -= OnShowPreReleasePackagesesOrSeeAllVersionsChanged; + m_SettingsProxy.onEnablePreReleasePackagesChanged -= OnShowPreReleasePackagesOrSeeAllVersionsChanged; + m_SettingsProxy.onSeeAllVersionsChanged -= OnShowPreReleasePackagesOrSeeAllVersionsChanged; m_UpmCache.onPackageInfosUpdated -= OnPackageInfosUpdated; m_UpmCache.onExtraPackageInfoFetched -= OnExtraPackageInfoFetched; @@ -129,7 +129,7 @@ private void OnLoadAllVersionsChanged(string packageUniqueId, bool _) GeneratePackagesAndTriggerChangeEvent(new[] { packageUniqueId }); } - private void OnShowPreReleasePackagesesOrSeeAllVersionsChanged(bool _) + private void OnShowPreReleasePackagesOrSeeAllVersionsChanged(bool _) { var allPackageNames = m_UpmCache.installedPackageInfos.Concat(m_UpmCache.searchPackageInfos).Select(p => p.name).ToHashSet(); GeneratePackagesAndTriggerChangeEvent(allPackageNames); @@ -170,7 +170,9 @@ public void GeneratePackagesAndTriggerChangeEvent(IEnumerable packageNam continue; } - var package = CreatePackage(packageName, versionList, isDiscoverable: searchInfo != null, isDeprecated: isDeprecated, deprecationMessage: deprecationMessage); + var isLocked = versionList.installed?.isDirectDependency != true && + m_PackageDatabase.GetFeaturesThatUseThisPackage(versionList.installed)?.Any() == true; + var package = CreatePackage(packageName, versionList, isDiscoverable: searchInfo != null, isDeprecated: isDeprecated, deprecationMessage: deprecationMessage, isLocked: isLocked); updatedPackages.Add(package); // if the primary version is not fully fetched, trigger an extra fetch automatically right away to get results early diff --git a/Modules/PackageManagerUI/Editor/Services/UserSettings/PackageManagerUserSettingsProvider.cs b/Modules/PackageManagerUI/Editor/Services/UserSettings/PackageManagerUserSettingsProvider.cs index 227d4bc8d5..a6822f4650 100644 --- a/Modules/PackageManagerUI/Editor/Services/UserSettings/PackageManagerUserSettingsProvider.cs +++ b/Modules/PackageManagerUI/Editor/Services/UserSettings/PackageManagerUserSettingsProvider.cs @@ -225,7 +225,7 @@ private bool CancelDownloadInProgress() if (m_ApplicationProxy.isBatchMode || !m_ApplicationProxy.DisplayDialog("abortDownloadBeforeChangeAssetsCacheLocation", L10n.Tr("Changing Assets Cache location"), - L10n.Tr("Changing the Assets Cache location will abort all downloads in progress."), + L10n.Tr("Changing the Assets Cache location will cancel all downloads in progress."), L10n.Tr("Continue"), L10n.Tr("Cancel"))) return false; diff --git a/Modules/PackageManagerUI/Editor/UI/AddPackageByNameDropdown.cs b/Modules/PackageManagerUI/Editor/UI/AddPackageByNameDropdown.cs index 431bce594d..32b1dbe1dd 100644 --- a/Modules/PackageManagerUI/Editor/UI/AddPackageByNameDropdown.cs +++ b/Modules/PackageManagerUI/Editor/UI/AddPackageByNameDropdown.cs @@ -24,17 +24,19 @@ internal class AddPackageByNameDropdown : DropdownContent private IUpmClient m_UpmClient; private IPackageDatabase m_PackageDatabase; private IPageManager m_PageManager; - private void ResolveDependencies(IResourceLoader resourceLoader, IUpmClient upmClient, IPackageDatabase packageDatabase, IPageManager packageManager) + private IPackageOperationDispatcher m_OperationDispatcher; + private void ResolveDependencies(IResourceLoader resourceLoader, IUpmClient upmClient, IPackageDatabase packageDatabase, IPageManager packageManager, IPackageOperationDispatcher packageOperationDispatcher) { m_ResourceLoader = resourceLoader; m_UpmClient = upmClient; m_PackageDatabase = packageDatabase; m_PageManager = packageManager; + m_OperationDispatcher = packageOperationDispatcher; } - public AddPackageByNameDropdown(IResourceLoader resourceLoader, IUpmClient upmClient, IPackageDatabase packageDatabase, IPageManager packageManager, EditorWindow anchorWindow) + public AddPackageByNameDropdown(IResourceLoader resourceLoader, IUpmClient upmClient, IPackageDatabase packageDatabase, IPageManager packageManager, IPackageOperationDispatcher packageOperationDispatcher, EditorWindow anchorWindow) { - ResolveDependencies(resourceLoader, upmClient, packageDatabase, packageManager); + ResolveDependencies(resourceLoader, upmClient, packageDatabase, packageManager, packageOperationDispatcher); styleSheets.Add(m_ResourceLoader.inputDropdownStyleSheet); @@ -167,7 +169,12 @@ internal void SubmitClicked() private void InstallByNameAndVersion(string packageName, string packageVersion = null, string productId = null) { var packageId = string.IsNullOrEmpty(packageVersion) ? packageName : $"{packageName}@{packageVersion}"; - m_UpmClient.AddById(packageId); + + if(!m_OperationDispatcher.Install(packageId)) + { + Close(); + return; + } PackageManagerWindowAnalytics.SendEvent("addByNameAndVersion", packageId); diff --git a/Modules/PackageManagerUI/Editor/UI/Common/BaseDropdownButton.cs b/Modules/PackageManagerUI/Editor/UI/Common/BaseDropdownButton.cs new file mode 100644 index 0000000000..f24d9dcd2d --- /dev/null +++ b/Modules/PackageManagerUI/Editor/UI/Common/BaseDropdownButton.cs @@ -0,0 +1,232 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System; +using UnityEngine; +using UnityEngine.UIElements; + +namespace UnityEditor.PackageManager.UI.Internal +{ + internal abstract class BaseDropdownButton : VisualElement, ITextElement + { + private const string k_UssClassName = "dropdown-button"; + private const string k_HasSeparateDropdownClass = "separate-dropdown"; + private const string k_HasIconClass = "has-icon"; + + private const float k_MarginsWidth = 6.0f; + private const float k_PaddingWidth = 14.0f; + private const float k_SideElementWidth = 18.0f; + private const float k_DropdownWidth = 12.0f; + + private VisualElement m_MainButton; + public VisualElement mainButton => m_MainButton; + + private TextElement m_Label; + private VisualElement m_ImageIcon; + private Background? m_IconBackground; + + private VisualElement m_SeparateDropdownArea; + private VisualElement m_DropdownIcon; + + private T m_DropdownMenu; + /// + /// Sets a dropdown menu for this button. The dropdown menu icon will only show if there is a non-null menu set. + /// + public T menu + { + get => m_DropdownMenu; + set + { + m_DropdownMenu = value; + RefreshDropdownIcon(); + } + } + + + private bool m_AlwaysShowDropdown; + public bool alwaysShowDropdown + { + get => m_AlwaysShowDropdown; + set + { + if (m_AlwaysShowDropdown == value) + return; + m_AlwaysShowDropdown = value; + RefreshDropdownIcon(); + } + } + + private Action m_Clicked; + /// + /// If the clicked event is never set, then the default behaviour of the button click is to open the dropdown menu + /// + public event Action clicked + { + add + { + m_Clicked += value; + RefreshDropdownIcon(); + } + remove + { + m_Clicked -= value; + RefreshDropdownIcon(); + } + } + + public string text + { + get => m_Label.text; + set + { + m_Label.text = value; + UIUtils.SetElementDisplay(m_Label, !string.IsNullOrEmpty(value)); + } + } + + protected abstract int numDropdownItems { get; } + private bool showDropdownIcon => m_AlwaysShowDropdown || numDropdownItems > 0; + private bool isDropdownIconSeparated => m_Clicked != null; + + private Clickable m_MainButtonClickable; + public Clickable clickable => m_MainButtonClickable; + + public float estimatedWidth + { + get + { + var width = string.IsNullOrEmpty(text) ? 0.0f : m_Label.MeasureTextSize(text, 0, MeasureMode.Undefined, 0, MeasureMode.Undefined).x; + if (m_ImageIcon != null && (m_IconBackground != null || m_ImageIcon.classList.Count > 0)) + width += k_SideElementWidth; + if (showDropdownIcon) + width += isDropdownIconSeparated ? k_SideElementWidth : k_DropdownWidth; + return width + k_MarginsWidth + k_PaddingWidth; + } + } + + protected BaseDropdownButton() + { + AddToClassList(k_UssClassName); + + m_MainButton = new VisualElement { name = "mainButton" }; + m_MainButton.AddToClassList(Button.ussClassName); + m_MainButtonClickable = new Clickable(OnMainButtonClicked); + m_MainButton.AddManipulator(m_MainButtonClickable); + Add(m_MainButton); + + m_Label = new TextElement { name = "label" }; + m_MainButton.Add(m_Label); + text = string.Empty; + } + + protected BaseDropdownButton(Action clickEvent) : this() + { + clicked += clickEvent; + } + + private void ShowImageIcon() + { + if (m_ImageIcon == null) + { + m_ImageIcon = new VisualElement { name = "imageIcon" }; + m_MainButton.Insert(0, m_ImageIcon); + } + AddToClassList(k_HasIconClass); + UIUtils.SetElementDisplay(m_ImageIcon, true); + } + + private void HideImageIcon() + { + if (m_ImageIcon == null) + return; + m_ImageIcon.ClearClassList(); + RemoveFromClassList(k_HasIconClass); + UIUtils.SetElementDisplay(m_ImageIcon, false); + } + + public void SetIcon(Icon icon) + { + if (m_IconBackground != null) + return; + + if (icon == Icon.None) + { + HideImageIcon(); + } + else + { + ShowImageIcon(); + m_ImageIcon.ClearClassList(); + m_ImageIcon.AddToClassList(icon.ClassName()); + } + } + + public void SetIcon(Texture2D icon) + { + if (icon == null) + { + m_IconBackground = null; + HideImageIcon(); + } + else + { + ShowImageIcon(); + m_IconBackground = Background.FromTexture2D(icon); + m_ImageIcon.ClearClassList(); + m_ImageIcon.style.backgroundImage = new StyleBackground((Background)m_IconBackground); + } + } + + protected void RefreshDropdownIcon() + { + if (!showDropdownIcon) + { + m_DropdownIcon?.RemoveFromHierarchy(); + RemoveFromClassList(k_HasSeparateDropdownClass); + UIUtils.SetElementDisplay(m_SeparateDropdownArea, false); + return; + } + + m_DropdownIcon ??= new VisualElement { name = "dropdownIcon" }; + if (isDropdownIconSeparated) + { + if (m_SeparateDropdownArea == null) + { + m_SeparateDropdownArea = new VisualElement { name = "dropdownArea" }; + m_SeparateDropdownArea.AddToClassList(Button.ussClassName); + m_SeparateDropdownArea.AddManipulator(new Clickable(ShowDropdown)); + Add(m_SeparateDropdownArea); + } + m_SeparateDropdownArea.Add(m_DropdownIcon); + AddToClassList(k_HasSeparateDropdownClass); + UIUtils.SetElementDisplay(m_SeparateDropdownArea, true); + } + else + { + m_MainButton.Add(m_DropdownIcon); + RemoveFromClassList(k_HasSeparateDropdownClass); + UIUtils.SetElementDisplay(m_SeparateDropdownArea, false); + } + } + + public void ClearClickedEvents() + { + if (m_Clicked == null) + return; + + m_Clicked = null; + RefreshDropdownIcon(); + } + + private void OnMainButtonClicked() + { + if (m_Clicked != null) + m_Clicked.Invoke(); + else + ShowDropdown(); + } + + protected abstract void ShowDropdown(); + } +} diff --git a/Modules/PackageManagerUI/Editor/UI/Common/DropdownButton.cs b/Modules/PackageManagerUI/Editor/UI/Common/DropdownButton.cs index 8570ebe39e..81e3ff4296 100644 --- a/Modules/PackageManagerUI/Editor/UI/Common/DropdownButton.cs +++ b/Modules/PackageManagerUI/Editor/UI/Common/DropdownButton.cs @@ -3,14 +3,12 @@ // https://unity3d.com/legal/licenses/Unity_Reference_Only_License using System; -using System.Linq; using UnityEditor.UIElements; -using UnityEngine; using UnityEngine.UIElements; namespace UnityEditor.PackageManager.UI.Internal { - internal class DropdownButton : VisualElement, ITextElement, IToolbarMenuElement + internal class DropdownButton : BaseDropdownButton, IToolbarMenuElement { [Serializable] public new class UxmlSerializedData : VisualElement.UxmlSerializedData @@ -18,221 +16,19 @@ internal class DropdownButton : VisualElement, ITextElement, IToolbarMenuElement public override object CreateInstance() => new DropdownButton(); } - private const string k_HasSeparateDropdownClass = "separate-dropdown"; - private const string k_HasIconClass = "has-icon"; - - private const float k_MarginsWidth = 6.0f; - private const float k_PaddingWidth = 14.0f; - private const float k_SideElementWidth = 18.0f; - private const float k_DropdownWidth = 12.0f; - - private VisualElement m_MainButton; - public VisualElement mainButton => m_MainButton; - - private TextElement m_Label; - private VisualElement m_ImageIcon; - private Background? m_IconBackground; - - private VisualElement m_SeparateDropdownArea; - private VisualElement m_DropdownIcon; - - private DropdownMenu m_DropdownMenu; - /// - /// Sets a dropdown menu for this button. The dropdown menu icon will only show if there is a non-null menu set. - /// - public DropdownMenu menu - { - get => m_DropdownMenu; - set - { - m_DropdownMenu = value; - RefreshDropdownIcon(); - } - } - - private bool m_AlwaysShowDropdown; - public bool alwaysShowDropdown - { - get => m_AlwaysShowDropdown; - set - { - if (m_AlwaysShowDropdown == value) - return; - m_AlwaysShowDropdown = value; - RefreshDropdownIcon(); - } - } - - private Action m_Clicked; - /// - /// If the clicked event is never set, then the default behaviour of the button click is to open the dropdown menu - /// - public event Action clicked - { - add - { - m_Clicked += value; - RefreshDropdownIcon(); - } - remove - { - m_Clicked -= value; - RefreshDropdownIcon(); - } - } - - public string text - { - get => m_Label.text; - set - { - m_Label.text = value; - UIUtils.SetElementDisplay(m_Label, !string.IsNullOrEmpty(value)); - } - } - public event Action onBeforeShowDropdown = delegate {}; - private bool showDropdownIcon => m_AlwaysShowDropdown || m_DropdownMenu?.Count > 0; - private bool isDropdownIconSeparated => m_Clicked != null; - - private Clickable m_MainButtonClickable; - public Clickable clickable => m_MainButtonClickable; - - public float estimatedWidth - { - get - { - var width = string.IsNullOrEmpty(text) ? 0.0f : m_Label.MeasureTextSize(text, 0, MeasureMode.Undefined, 0, MeasureMode.Undefined).x; - if (m_ImageIcon != null && (m_IconBackground != null || m_ImageIcon.classList.Any())) - width += k_SideElementWidth; - if (showDropdownIcon) - width += isDropdownIconSeparated ? k_SideElementWidth : k_DropdownWidth; - return width + k_MarginsWidth + k_PaddingWidth; - } - } - - public DropdownButton() - { - m_MainButton = new VisualElement { name = "mainButton" }; - m_MainButton.AddToClassList(Button.ussClassName); - m_MainButtonClickable = new Clickable(OnMainButtonClicked); - m_MainButton.AddManipulator(m_MainButtonClickable); - Add(m_MainButton); - - m_Label = new TextElement { name = "label" }; - m_MainButton.Add(m_Label); - text = string.Empty; - } - - public DropdownButton(Action clickEvent) : this() - { - clicked += clickEvent; - } - - private void ShowImageIcon() + public DropdownButton() : base() { - if (m_ImageIcon == null) - { - m_ImageIcon = new VisualElement { name = "imageIcon" }; - m_MainButton.Insert(0, m_ImageIcon); - } - AddToClassList(k_HasIconClass); - UIUtils.SetElementDisplay(m_ImageIcon, true); } - private void HideImageIcon() + public DropdownButton(Action clickEvent) : base(clickEvent) { - if (m_ImageIcon == null) - return; - m_ImageIcon.ClearClassList(); - RemoveFromClassList(k_HasIconClass); - UIUtils.SetElementDisplay(m_ImageIcon, false); } - public void SetIcon(Icon icon) - { - if (m_IconBackground != null) - return; - - if (icon == Icon.None) - { - HideImageIcon(); - } - else - { - ShowImageIcon(); - m_ImageIcon.ClearClassList(); - m_ImageIcon.AddToClassList(icon.ClassName()); - } - } - - public void SetIcon(Texture2D icon) - { - if (icon == null) - { - m_IconBackground = null; - HideImageIcon(); - } - else - { - ShowImageIcon(); - m_IconBackground = Background.FromTexture2D(icon); - m_ImageIcon.ClearClassList(); - m_ImageIcon.style.backgroundImage = new StyleBackground((Background)m_IconBackground); - } - } - - private void RefreshDropdownIcon() - { - if (!showDropdownIcon) - { - m_DropdownIcon?.RemoveFromHierarchy(); - RemoveFromClassList(k_HasSeparateDropdownClass); - UIUtils.SetElementDisplay(m_SeparateDropdownArea, false); - return; - } - - m_DropdownIcon ??= new VisualElement { name = "dropdownIcon" }; - if (isDropdownIconSeparated) - { - if (m_SeparateDropdownArea == null) - { - m_SeparateDropdownArea = new VisualElement { name = "dropdownArea" }; - m_SeparateDropdownArea.AddToClassList(Button.ussClassName); - m_SeparateDropdownArea.AddManipulator(new Clickable(ShowDropdown)); - Add(m_SeparateDropdownArea); - } - m_SeparateDropdownArea.Add(m_DropdownIcon); - AddToClassList(k_HasSeparateDropdownClass); - UIUtils.SetElementDisplay(m_SeparateDropdownArea, true); - } - else - { - m_MainButton.Add(m_DropdownIcon); - RemoveFromClassList(k_HasSeparateDropdownClass); - UIUtils.SetElementDisplay(m_SeparateDropdownArea, false); - } - } - - public void ClearClickedEvents() - { - if (m_Clicked == null) - return; - - m_Clicked = null; - RefreshDropdownIcon(); - } - - private void OnMainButtonClicked() - { - if (m_Clicked != null) - m_Clicked.Invoke(); - else - ShowDropdown(); - } + protected override int numDropdownItems => menu?.Count ?? 0; - private void ShowDropdown() + protected override void ShowDropdown() { onBeforeShowDropdown?.Invoke(); if (menu != null) diff --git a/Modules/PackageManagerUI/Editor/UI/Common/UIUtils.cs b/Modules/PackageManagerUI/Editor/UI/Common/UIUtils.cs index 61924b2f35..af62263c19 100644 --- a/Modules/PackageManagerUI/Editor/UI/Common/UIUtils.cs +++ b/Modules/PackageManagerUI/Editor/UI/Common/UIUtils.cs @@ -27,6 +27,19 @@ public static bool IsElementVisible(VisualElement element) return element?.resolvedStyle.visibility == Visibility.Visible && element.resolvedStyle.display != DisplayStyle.None; } + public static void AppendAction(this GenericDropdownMenu menu, string itemName, bool enabled, Action action, string tooltip = null, bool isChecked = false) + { + if (enabled) + menu.AddItem(itemName, isChecked, action, null); + else + menu.AddDisabledItem(itemName, isChecked); + if (string.IsNullOrEmpty(tooltip)) + return; + var lastItem = menu.items.LastOrDefault(x => x.name == itemName); + if (lastItem != null) + lastItem.element.tooltip = tooltip; + } + public static VisualElement FindNextSibling(VisualElement element, bool reverseOrder, Func matchFunc = null) { if (element == null) diff --git a/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectFoldout.cs b/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectFoldout.cs index 108d18b91b..e129dc02f7 100644 --- a/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectFoldout.cs +++ b/Modules/PackageManagerUI/Editor/UI/MultiSelect/MultiSelectFoldout.cs @@ -18,7 +18,7 @@ internal class MultiSelectFoldout : VisualElement, IMultiSelectFoldoutElement public PackageAction action { get; } private Toggle m_Toggle; - private PackageToolBarButton m_Button; + private IPackageToolBarButton m_Button; private VisualElement m_Container; public MultiSelectFoldout(PackageAction action = null) @@ -36,7 +36,7 @@ public MultiSelectFoldout(PackageAction action = null) return; m_Button = new PackageToolBarSimpleButton(action); - m_Toggle.Add(m_Button); + m_Toggle.Add(m_Button.element); } public virtual void Refresh() diff --git a/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionHistoryItem.cs b/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionHistoryItem.cs index 4c381e31ce..995395a5da 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionHistoryItem.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageDetailsTabs/PackageDetailsVersionHistoryItem.cs @@ -17,7 +17,7 @@ internal class PackageDetailsVersionHistoryItem : VisualElement public PackageAction action { get; } private IPackageVersion m_Version; - private readonly PackageToolBarButton m_Button; + private readonly IPackageToolBarButton m_Button; private readonly IPackageDatabase m_PackageDatabase; private readonly IPackageOperationDispatcher m_OperationDispatcher; private readonly IUpmCache m_UpmCache; @@ -67,7 +67,7 @@ public PackageDetailsVersionHistoryItem(IResourceLoader resourceLoader, if (action != null) { m_Button = new PackageToolBarSimpleButton(action); - versionHistoryItemToggleRightContainer.Add(m_Button); + versionHistoryItemToggleRightContainer.Add(m_Button.element); } Refresh(multipleVersionsVisible, isLatestVersion); } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageItem.cs b/Modules/PackageManagerUI/Editor/UI/PackageItem.cs index 32d3ce18f3..3634ec664c 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageItem.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageItem.cs @@ -2,7 +2,6 @@ // Copyright (c) Unity Technologies. For terms of use, see // https://unity3d.com/legal/licenses/Unity_Reference_Only_License -using System.Linq; using UnityEngine.UIElements; namespace UnityEditor.PackageManager.UI.Internal @@ -60,27 +59,16 @@ private void BuildMainItem(bool isFeature) m_LeftContainer = new VisualElement {name = "leftContainer", classList = {"left"}}; m_MainItem.Add(m_LeftContainer); - m_DependencyIcon = new Label { name = "dependencyIcon" }; - m_DependencyIcon.tooltip = "Installed as dependency"; - m_LeftContainer.Add(m_DependencyIcon); - - m_LockedIcon = new Label { name = "lockedIcon" }; - m_LeftContainer.Add(m_LockedIcon); - - m_DeprecationIcon = new Label { name = "deprecatedIcon" }; - m_DeprecationIcon.tooltip = L10n.Tr("Deprecated"); - m_LeftContainer.Add(m_DeprecationIcon); - - m_ExpanderHidden = new Label {name = "expanderHidden", classList = {"expanderHidden"}}; - m_LeftContainer.Add(m_ExpanderHidden); + m_PackageTypeIcon = new Label { name = "packageTypeIcon" }; + m_LeftContainer.Add(m_PackageTypeIcon); m_NameLabel = new Label {name = "packageName", classList = {"name"}}; if (isFeature) { m_MainItem.AddToClassList("feature"); - m_NumPackagesInFeature = new Label() { name = "numPackages" }; + m_NumPackagesInFeature = new Label { name = "numPackages" }; - var leftMiddleContainer = new VisualElement() { name = "leftMiddleContainer" }; + var leftMiddleContainer = new VisualElement { name = "leftMiddleContainer" }; leftMiddleContainer.Add(m_NameLabel); leftMiddleContainer.Add(m_NumPackagesInFeature); m_LeftContainer.Add(leftMiddleContainer); @@ -118,6 +106,8 @@ private void BuildMainItem(bool isFeature) m_InfoStateIcon = new VisualElement { name = "versionState" }; m_StateContainer.Add(m_InfoStateIcon); } + + UIUtils.SetElementDisplay(m_PackageTypeIcon, true); } public void UpdateVisualState(VisualState newVisualState) @@ -144,7 +134,6 @@ public void Refresh(VisualState newVisualState = null) m_TagLabel.Refresh(package.versions.primary); - RefreshLeftStateIcons(); RefreshRightStateIcons(); RefreshSelection(); RefreshEntitlement(); @@ -156,32 +145,12 @@ public void SetPackage(IPackage package) name = package?.displayName ?? package?.uniqueId ?? string.Empty; } - private void RefreshLeftStateIcons() - { - var showLockIcon = visualState.isLocked; - var showDeprecationIcon = package.isDeprecated; - - var targetVersion = this.targetVersion; - var showDependencyIcon = targetVersion != null && - !showLockIcon && - targetVersion.isInstalled && - !targetVersion.isDirectDependency && - !targetVersion.HasTag(PackageTag.Feature); - - var showExpanderHidden = !showLockIcon && !showDeprecationIcon && !showDependencyIcon; - - UIUtils.SetElementDisplay(m_LockedIcon, showLockIcon); - UIUtils.SetElementDisplay(m_DeprecationIcon, showDeprecationIcon); - UIUtils.SetElementDisplay(m_DependencyIcon, showDependencyIcon); - UIUtils.SetElementDisplay(m_ExpanderHidden, showExpanderHidden); - } - public void RefreshRightStateIcons() { if (RefreshSpinner()) return; - var state = package?.state ?? PackageState.None; + var state = GetCurrentPackageState(); var stateClass = state != PackageState.None ? state.ToString().ToLower() : null; if (!string.IsNullOrEmpty(m_CurrentStateClass)) m_StateIcon.RemoveFromClassList(m_CurrentStateClass); @@ -195,6 +164,13 @@ public void RefreshRightStateIcons() RefreshFeatureState(); } + private PackageState GetCurrentPackageState() + { + return package?.state == PackageState.Locked && visualState.userUnlocked + ? PackageState.UnlockedByUser + : package?.state ?? PackageState.None; + } + // Returns true if package is in progress and spinner is visible private bool RefreshSpinner() { @@ -293,10 +269,7 @@ private void StopSpinner() private Label m_EntitlementLabel; private Label m_VersionLabel; private LoadingSpinner m_Spinner; - private Label m_LockedIcon; - private Label m_DeprecationIcon; - private Label m_DependencyIcon; - private Label m_ExpanderHidden; + private Label m_PackageTypeIcon; private VisualElement m_LeftContainer; private VisualElement m_RightContainer; private Label m_NumPackagesInFeature; @@ -305,8 +278,7 @@ private void StopSpinner() { "", L10n.Tr("This {0} is installed."), - // Keep the error message for `installed` and `installedAsDependency` the same for now as requested by the designer - L10n.Tr("This {0} is installed."), + L10n.Tr("This {0} is installed as a dependency."), L10n.Tr("This {0} is available for download."), L10n.Tr("This {0} is available for import."), L10n.Tr("There are assets in your project that are imported from this {0}."), @@ -314,7 +286,9 @@ private void StopSpinner() L10n.Tr("A newer version of this {0} is available."), "", L10n.Tr("There are errors with this {0}. Read the {0} details for further guidance."), - L10n.Tr("There are warnings with this {0}. Read the {0} details for further guidance.") + L10n.Tr("There are warnings with this {0}. Read the {0} details for further guidance."), + L10n.Tr("This {0} is installed by a feature."), + L10n.Tr("This {0} is unlocked. You can now change its version.") }; public string GetTooltipByState(PackageState state) diff --git a/Modules/PackageManagerUI/Editor/UI/PackageManagerToolbar.cs b/Modules/PackageManagerUI/Editor/UI/PackageManagerToolbar.cs index 1fa7c8474d..65a5353651 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageManagerToolbar.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageManagerToolbar.cs @@ -294,11 +294,9 @@ private void SetupAddMenu() return; } - - if (m_OperationDispatcher.isInstallOrUninstallInProgress) + if (!m_OperationDispatcher.InstallFromPath(m_IOProxy.GetParentDirectory(path), out var tempPackageId)) return; - m_OperationDispatcher.InstallFromPath(m_IOProxy.GetParentDirectory(path), out var tempPackageId); PackageManagerWindowAnalytics.SendEvent("addFromDisk"); SelectPackageInProject(tempPackageId); } @@ -314,9 +312,10 @@ private void SetupAddMenu() dropdownItem.action = () => { var path = m_Application.OpenFilePanelWithFilters(L10n.Tr("Select package on disk"), "", new[] { "Package tarball", "tgz, tar.gz" }); - if (string.IsNullOrEmpty(path) || m_OperationDispatcher.isInstallOrUninstallInProgress) + + if ((string.IsNullOrEmpty(path)) || !m_OperationDispatcher.InstallFromPath(path, out var tempPackageId)) return; - m_OperationDispatcher.InstallFromPath(path, out var tempPackageId); + PackageManagerWindowAnalytics.SendEvent("addFromTarball"); SelectPackageInProject(tempPackageId); }; @@ -334,9 +333,9 @@ private void SetupAddMenu() submitButtonText = L10n.Tr("Install"), onInputSubmitted = url => { - if (m_OperationDispatcher.isInstallOrUninstallInProgress) + if (!m_OperationDispatcher.InstallFromUrl(url)) return; - m_OperationDispatcher.InstallFromUrl(url); + PackageManagerWindowAnalytics.SendEvent("addFromGitUrl", url); SelectPackageInProject(url); }, @@ -364,7 +363,7 @@ private void SetupAddMenu() // relation to package manager we can compensate this by subtracting contextual menu origin. rect.y -= worldBound.yMax; - var dropdown = new AddPackageByNameDropdown(m_ResourceLoader, m_UpmClient, m_PackageDatabase, m_PageManager, PackageManagerWindow.instance) { position = rect }; + var dropdown = new AddPackageByNameDropdown(m_ResourceLoader, m_UpmClient, m_PackageDatabase, m_PageManager, m_OperationDispatcher, PackageManagerWindow.instance) { position = rect }; DropdownContainer.ShowDropdown(dropdown); }; } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageManagerWindow.cs b/Modules/PackageManagerUI/Editor/UI/PackageManagerWindow.cs index 2ef5f096e9..c50b1eef02 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageManagerWindow.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageManagerWindow.cs @@ -97,6 +97,7 @@ private void BuildGUI() var upmClient = container.Resolve(); var assetStoreCachePathProxy = container.Resolve(); var pageRefreshHandler = container.Resolve(); + var operationDispatcher = container.Resolve(); // Adding the ScrollView object here because it really need to be the first child under rootVisualElement for it to work properly. // Since the StyleSheet is added to PackageManagerRoot, the css is exceptionally added directly to the object @@ -108,7 +109,7 @@ private void BuildGUI() flexGrow = 1 } }; - m_Root = new PackageManagerWindowRoot(resourceLoader, extensionManager, selection, packageManagerPrefs, packageDatabase, pageManager, settingsProxy, unityConnectProxy, applicationProxy, upmClient, assetStoreCachePathProxy, pageRefreshHandler); + m_Root = new PackageManagerWindowRoot(resourceLoader, extensionManager, selection, packageManagerPrefs, packageDatabase, pageManager, settingsProxy, unityConnectProxy, applicationProxy, upmClient, assetStoreCachePathProxy, pageRefreshHandler, operationDispatcher); try { m_Root.OnEnable(); diff --git a/Modules/PackageManagerUI/Editor/UI/PackageManagerWindowRoot.cs b/Modules/PackageManagerUI/Editor/UI/PackageManagerWindowRoot.cs index 03631c4a0b..9ff2cdd56f 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageManagerWindowRoot.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageManagerWindowRoot.cs @@ -31,6 +31,7 @@ internal class PackageManagerWindowRoot : VisualElement, IWindow private IUpmClient m_UpmClient; private IAssetStoreCachePathProxy m_AssetStoreCachePathProxy; private IPageRefreshHandler m_PageRefreshHandler; + private IPackageOperationDispatcher m_OperationDispatcher; private void ResolveDependencies(IResourceLoader resourceLoader, IExtensionManager extensionManager, @@ -43,7 +44,8 @@ private void ResolveDependencies(IResourceLoader resourceLoader, IApplicationProxy applicationProxy, IUpmClient upmClient, IAssetStoreCachePathProxy assetStoreCachePathProxy, - IPageRefreshHandler pageRefreshHandler) + IPageRefreshHandler pageRefreshHandler, + IPackageOperationDispatcher packageOperationDispatcher) { m_ResourceLoader = resourceLoader; m_ExtensionManager = extensionManager; @@ -57,6 +59,7 @@ private void ResolveDependencies(IResourceLoader resourceLoader, m_UpmClient = upmClient; m_AssetStoreCachePathProxy = assetStoreCachePathProxy; m_PageRefreshHandler = pageRefreshHandler; + m_OperationDispatcher = packageOperationDispatcher; } public PackageManagerWindowRoot(IResourceLoader resourceLoader, @@ -70,9 +73,10 @@ public PackageManagerWindowRoot(IResourceLoader resourceLoader, IApplicationProxy applicationProxy, IUpmClient upmClient, IAssetStoreCachePathProxy assetStoreCachePathProxy, - IPageRefreshHandler pageRefreshHandler) + IPageRefreshHandler pageRefreshHandler, + IPackageOperationDispatcher packageOperationDispatcher) { - ResolveDependencies(resourceLoader, extensionManager, selection, packageManagerPrefs, packageDatabase, pageManager, settingsProxy, unityConnectProxy, applicationProxy, upmClient, assetStoreCachePathProxy, pageRefreshHandler); + ResolveDependencies(resourceLoader, extensionManager, selection, packageManagerPrefs, packageDatabase, pageManager, settingsProxy, unityConnectProxy, applicationProxy, upmClient, assetStoreCachePathProxy, pageRefreshHandler, packageOperationDispatcher); } public void OnEnable() @@ -400,7 +404,7 @@ public void SelectPackageAndPage(string packageToSelect = null, string pageId = public AddPackageByNameDropdown OpenAddPackageByNameDropdown(string url, EditorWindow anchorWindow) { - var dropdown = new AddPackageByNameDropdown(m_ResourceLoader, m_UpmClient, m_PackageDatabase, m_PageManager, anchorWindow); + var dropdown = new AddPackageByNameDropdown(m_ResourceLoader, m_UpmClient, m_PackageDatabase, m_PageManager, m_OperationDispatcher, anchorWindow); var packageNameAndVersion = url.Replace(PackageManagerWindow.k_UpmUrl, string.Empty); var packageName = string.Empty; diff --git a/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs b/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs index 66a529f8a0..4c4cbf22d7 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageSelectionEditor.cs @@ -153,8 +153,9 @@ public override void OnInspectorGUI() var dependenciesTitleText = EditorGUIUtility.TrTextContent( m_Version.HasTag(PackageTag.Feature) ? "Packages included" : "Dependencies"); GUILayout.Label(dependenciesTitleText, EditorStyles.boldLabel); - m_List.DoLayoutList(); + GUI.enabled = IsPackageEditable(); + m_List.DoLayoutList(); GUI.enabled = previousEnabled; } @@ -255,6 +256,17 @@ private void DrawDependencyListElement(Rect rect, int index, bool isActive, bool rect.width = w / 3 - 4; EditorGUI.SelectableLabel(rect, versionString); } + + private bool IsPackageEditable() + { + if (m_Version == null || !m_Version.HasTag(PackageTag.Custom)) + return false; + + var packageInfo = m_UpmCache.GetBestMatchPackageInfo(m_Version.name, m_Version.isInstalled, m_Version.versionString); + var manifest = m_AssetDatabase.LoadAssetAtPath($"{packageInfo.assetPath}/package.json"); + + return m_Selection.activeObject == manifest; + } private void DoPackageInformationLayout() { @@ -276,7 +288,12 @@ private void DoPackageInformationLayout() contents.Add(m_Version.version.ToString()); contents.Add(m_Version.category); + var previousEnabled = GUI.enabled; + GUI.enabled = IsPackageEditable(); + SelectableLabelFields(labels, contents); + + GUI.enabled = previousEnabled; } } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageDynamicTagLabel.cs b/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageDynamicTagLabel.cs index 26a75ea585..5949a285e0 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageDynamicTagLabel.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageTagLabel/PackageDynamicTagLabel.cs @@ -6,6 +6,8 @@ namespace UnityEditor.PackageManager.UI.Internal { internal class PackageDynamicTagLabel : PackageBaseTagLabel { + public const string k_DisableEllipsisClass = "disable-ellipsis"; + private PackageTag m_Tag; private bool m_IsVersionItem; public PackageDynamicTagLabel(bool isVersionItem = false) @@ -70,6 +72,11 @@ private void UpdateTag(PackageTag newTag) tooltip = string.Empty; break; } + + // Sometimes the UI Element layout engine would calculate the size to be 1px less than it should be, causing + // the tag to show up as just ellipsis in some cases. We are adding the special handling here so that short + // tags never show ellipsis + EnableInClassList(k_DisableEllipsisClass, text.Length <= 3); } public override void Refresh(IPackageVersion version) diff --git a/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowData.cs b/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowData.cs index 68b39c9d22..54b114a24a 100644 --- a/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowData.cs +++ b/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowData.cs @@ -33,7 +33,8 @@ internal class Node public string headerTitle; public string headerDescription; public string actionLabel; - public List nodes = new(); + private List m_Nodes = new(); + public IReadOnlyList nodes => m_Nodes; // This node is not created through the SelectionWindowData.CreateNode function, because we don't want it to be // part of the final visible tree. We set the index to `-1` such that if it accidentally end up in the final tree, @@ -49,6 +50,8 @@ internal class Node .Select(index => nodes[index].asset).ToArray(); public IReadOnlyList assets => nodes.Where(n => !n.isFolder).Select(n => n.asset).ToArray(); + public int selectedNodesCount => m_SelectedIndexes.Count; + // This constructor only constructs an instance of SelectionWindowData for the remove case. public SelectionWindowData(IEnumerable assetsList, string packageName, string description) { @@ -148,7 +151,7 @@ private Node AddNode(Node parentNode, string name) name = name, }; - nodes.Add(newNode); + m_Nodes.Add(newNode); m_SelectedIndexes.Add(newNode.index); parentNode.childIndexes.Add(newNode.index); newNode.parentIndex = parentNode.index; diff --git a/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowFooter.cs b/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowFooter.cs index 97eaf75554..da5833387b 100644 --- a/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowFooter.cs +++ b/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowFooter.cs @@ -14,6 +14,8 @@ internal class SelectionWindowFooter : VisualElement public event Action onActionButtonClicked = delegate {}; public event Action onCancelButtonClicked = delegate {}; + private Button m_AllButton; + private Button m_NoneButton; private Button m_ActionButton; public SelectionWindowFooter() @@ -27,13 +29,13 @@ public SelectionWindowFooter() var leftSection = new VisualElement { name = "leftSection", classList = { "left-section" } }; footer.Add(leftSection); - var allButton = new Button { name = "allButton", text = "All", tabIndex = -1, displayTooltipWhenElided = true }; - allButton.clicked += () => onAllButtonClicked?.Invoke(); - leftSection.Add(allButton); + m_AllButton = new Button { name = "allButton", text = "All", tabIndex = -1, displayTooltipWhenElided = true }; + m_AllButton.clicked += () => onAllButtonClicked?.Invoke(); + leftSection.Add(m_AllButton); - var noneButton = new Button { name = "noneButton", text = "None", tabIndex = -1, displayTooltipWhenElided = true }; - noneButton.clicked += () => onNoneButtonClicked?.Invoke(); - leftSection.Add(noneButton); + m_NoneButton = new Button { name = "noneButton", text = "None", tabIndex = -1, displayTooltipWhenElided = true }; + m_NoneButton.clicked += () => onNoneButtonClicked?.Invoke(); + leftSection.Add(m_NoneButton); var rightSection = new VisualElement { name = "rightSection", classList = { "right-section" } }; footer.Add(rightSection); @@ -52,8 +54,10 @@ public void SetData(string actionName) m_ActionButton.text = actionName; } - public void SetActionEnabled(bool isEnabled) + public void RefreshButtons(int selectedItemsCount, int totalItemsCount) { - m_ActionButton.SetEnabled(isEnabled); + m_ActionButton.SetEnabled(selectedItemsCount > 0); + m_NoneButton.SetEnabled(selectedItemsCount > 0); + m_AllButton.SetEnabled(selectedItemsCount < totalItemsCount); } } diff --git a/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowRoot.cs b/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowRoot.cs index f552db3b69..0f458e446a 100644 --- a/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowRoot.cs +++ b/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowRoot.cs @@ -58,7 +58,7 @@ public void SetData(SelectionWindowData data, bool resetExpansion) private void RefreshItems() { m_TreeView.RefreshItems(); - m_Footer.SetActionEnabled(m_WindowData.selectedAssets.Any()); + m_Footer.RefreshButtons(m_WindowData.selectedNodesCount, m_WindowData.nodes.Count); } private VisualElement MakeItem() diff --git a/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowTreeView.cs b/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowTreeView.cs index 7ec8481ad2..f9df14a3b5 100644 --- a/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowTreeView.cs +++ b/Modules/PackageManagerUI/Editor/UI/SelectionWindow/SelectionWindowTreeView.cs @@ -49,7 +49,7 @@ private void ResetExpansionAndScroll() private static List> CreateTreeViewData(SelectionWindowData data, SelectionWindowData.Node parentNode) { - if (data.nodes?.Any() != true) + if (data?.nodes == null || data.nodes.Count == 0) return new List>(); var results = new List>(); diff --git a/Modules/PackageManagerUI/Editor/UI/ToolBar/Interfaces/IPackageToolBarButton.cs b/Modules/PackageManagerUI/Editor/UI/ToolBar/Interfaces/IPackageToolBarButton.cs new file mode 100644 index 0000000000..9b3c1f3f14 --- /dev/null +++ b/Modules/PackageManagerUI/Editor/UI/ToolBar/Interfaces/IPackageToolBarButton.cs @@ -0,0 +1,18 @@ +// Unity C# reference source +// Copyright (c) Unity Technologies. For terms of use, see +// https://unity3d.com/legal/licenses/Unity_Reference_Only_License + +using System.Collections.Generic; +using UnityEngine.UIElements; +using System; + +namespace UnityEditor.PackageManager.UI.Internal +{ + internal interface IPackageToolBarButton + { + void Refresh(IPackageVersion version); + void Refresh(IEnumerable packages); + event Action onActionTriggered; + VisualElement element { get; } + } +} diff --git a/Modules/PackageManagerUI/Editor/UI/ToolBar/LegacyFormatDropdownButton.cs b/Modules/PackageManagerUI/Editor/UI/ToolBar/LegacyFormatDropdownButton.cs index b263183631..c2b0da058f 100644 --- a/Modules/PackageManagerUI/Editor/UI/ToolBar/LegacyFormatDropdownButton.cs +++ b/Modules/PackageManagerUI/Editor/UI/ToolBar/LegacyFormatDropdownButton.cs @@ -10,14 +10,15 @@ namespace UnityEditor.PackageManager.UI.Internal; -internal class LegacyFormatDropdownButton : PackageToolBarButton +internal class LegacyFormatDropdownButton : BaseDropdownButton, IPackageToolBarButton { private static readonly string k_InProjectText = L10n.Tr("In Project"); - private readonly DropdownButton m_DropdownButton; + protected override int numDropdownItems => menu?.items.Count ?? 0; + protected override void ShowDropdown() => menu?.DropDown(worldBound, this, true, true); private readonly IList m_Actions; - public override event Action onActionTriggered + public event Action onActionTriggered { add { @@ -31,6 +32,8 @@ public override event Action onActionTriggered } } + public VisualElement element => this; + public LegacyFormatDropdownButton(IPackageOperationDispatcher operationDispatcher, IAssetStoreDownloadManager assetStoreDownloadManager, IUnityConnectProxy unityConnect, @@ -51,11 +54,9 @@ public LegacyFormatDropdownButton(IPackageOperationDispatcher operationDispatche }; name = "legacyFormatDropdownButton"; - m_DropdownButton = new DropdownButton(); - Add(m_DropdownButton); } - public override void Refresh(IPackageVersion version) + public void Refresh(IPackageVersion version) { // We do this early return for performance reasons. This avoids doing expensive calls to GetActionState for multiple actions. if (version?.HasTag(PackageTag.LegacyFormat) != true) @@ -71,17 +72,17 @@ public override void Refresh(IPackageVersion version) return; } UIUtils.SetElementDisplay(this, true); - m_DropdownButton.ClearClickedEvents(); + ClearClickedEvents(); var mainActionIndex = FindMainActionIndex(visibleItems, true); if (mainActionIndex == -1) { if (version.importedAssets?.Any() == true) { - m_DropdownButton.SetIcon(Icon.Installed); - m_DropdownButton.text = k_InProjectText; - m_DropdownButton.mainButton.tooltip = string.Empty; - m_DropdownButton.mainButton.SetEnabled(true); + SetIcon(Icon.Installed); + text = k_InProjectText; + mainButton.tooltip = string.Empty; + mainButton.SetEnabled(true); } else // It is not possible that FindMainActionIndex returns -1 for both when isRecommended is true and false, so we can know for sure that @@ -92,28 +93,26 @@ public override void Refresh(IPackageVersion version) if (mainActionIndex != -1) { var mainItem = visibleItems[mainActionIndex]; - m_DropdownButton.clicked += () => mainItem.action.TriggerAction(version); - m_DropdownButton.text = mainItem.text; - m_DropdownButton.SetIcon(mainItem.action.icon); - m_DropdownButton.mainButton.tooltip = mainItem.tooltip; - m_DropdownButton.mainButton.SetEnabled((mainItem.state & PackageActionState.Disabled) == PackageActionState.None); + clicked += () => mainItem.action.TriggerAction(version); + text = mainItem.text; + SetIcon(mainItem.action.icon); + mainButton.tooltip = mainItem.tooltip; + mainButton.SetEnabled((mainItem.state & PackageActionState.Disabled) == PackageActionState.None); } // We need to create a new DropdownMenu every time instead of using the "Hidden" status of DropdownMenuAction, // because there's no API to change the DropdownMenuAction class after creating it. - var dropdownMenu = new DropdownMenu(); + var dropdownMenu = new GenericDropdownMenu(); for (var i = 0; i < visibleItems.Count; ++i) { if (i == mainActionIndex) continue; var item = visibleItems[i]; - dropdownMenu.AppendAction(item.text, _ => item.action.TriggerAction(version), a => - { - return (item.state & PackageActionState.Disabled) == PackageActionState.None ? DropdownMenuAction.Status.Normal : DropdownMenuAction.Status.Disabled; - }); + var itemEnabled = (item.state & PackageActionState.Disabled) == PackageActionState.None; + dropdownMenu.AppendAction(item.text, itemEnabled, _ => item.action.TriggerAction(version), tooltip: item.tooltip); } - m_DropdownButton.menu = dropdownMenu; + menu = dropdownMenu; } private List<(PackageAction action, string text, string tooltip, PackageActionState state)> FindVisibleActions(IPackageVersion version) @@ -140,7 +139,7 @@ private int FindMainActionIndex(IList<(PackageAction action, string text, string } [ExcludeFromCodeCoverage] - public override void Refresh(IEnumerable packages) + public 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 0fd287c7d6..37e0c63b25 100644 --- a/Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBar.cs +++ b/Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBar.cs @@ -41,8 +41,8 @@ private void ResolveDependencies() private IPackage m_Package; private IPackageVersion m_Version; - private IList m_BuiltInToolBarButtons; - private IList m_ProgressControlButtons; + private IList m_BuiltInToolBarButtons; + private IList m_ProgressControlButtons; private VisualElement m_MainContainer; private VisualElement m_ProgressContainer; @@ -85,7 +85,7 @@ public PackageToolbar() private void InitializeButtons() { - m_BuiltInToolBarButtons = new PackageToolBarButton[] + m_BuiltInToolBarButtons = new IPackageToolBarButton[] { new PackageToolBarSimpleButton(new UnlockAction(m_PageManager)), new PackageToolBarSimpleButton(new SignInAction(m_UnityConnect, m_Application)), @@ -101,11 +101,11 @@ private void InitializeButtons() foreach (var button in m_BuiltInToolBarButtons) { button.onActionTriggered += Refresh; - m_BuiltInActionsContainer.Add(button); + m_BuiltInActionsContainer.Add(button.element); } // Since pause, resume, cancel buttons are only used to control the download progress, we want to put them in the progress container instead - m_ProgressControlButtons = new PackageToolBarButton[] + m_ProgressControlButtons = new IPackageToolBarButton[] { new PackageToolBarIconOnlyButton(new ResumeDownloadAction(m_OperationDispatcher, m_AssetStoreDownloadManager, m_Application)), new PackageToolBarIconOnlyButton(new PauseDownloadAction(m_OperationDispatcher, m_AssetStoreDownloadManager, m_Application)), @@ -115,7 +115,7 @@ private void InitializeButtons() foreach (var button in m_ProgressControlButtons) { button.onActionTriggered += Refresh; - m_ProgressContainer.Add(button); + m_ProgressContainer.Add(button.element); } } diff --git a/Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBarButton.cs b/Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBarButtonSingleAction.cs similarity index 89% rename from Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBarButton.cs rename to Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBarButtonSingleAction.cs index 6b00494c2d..a5ec303a08 100644 --- a/Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBarButton.cs +++ b/Modules/PackageManagerUI/Editor/UI/ToolBar/PackageToolBarButtonSingleAction.cs @@ -9,15 +9,7 @@ namespace UnityEditor.PackageManager.UI.Internal { - internal abstract class PackageToolBarButton : VisualElement - { - public abstract void Refresh(IPackageVersion version); - - public abstract void Refresh(IEnumerable packages); - public abstract event Action onActionTriggered; - } - - internal abstract class PackageToolBarButtonSingleAction : PackageToolBarButton + internal abstract class PackageToolBarButtonSingleAction : VisualElement, IPackageToolBarButton { private readonly List m_Versions = new(); private readonly PackageAction m_Action; @@ -28,12 +20,14 @@ protected PackageToolBarButtonSingleAction(PackageAction action) protected abstract string text { set; } - public override event Action onActionTriggered + public event Action onActionTriggered { add => m_Action.onActionTriggered += value; remove => m_Action.onActionTriggered -= value; } + public VisualElement element => this; + private void SetPackageVersion(IPackageVersion version) { m_Versions.Clear(); @@ -46,7 +40,7 @@ private void SetPackageVersions(IEnumerable versions) m_Versions.AddRange(versions); } - public override void Refresh(IEnumerable packages) + public void Refresh(IEnumerable packages) { SetPackageVersions(packages.Select(p => p.versions.primary)); if (m_Versions.Count == 0) @@ -62,7 +56,7 @@ public override void Refresh(IEnumerable packages) tooltip = temporaryDisableCondition?.tooltip ?? string.Empty; } - public override void Refresh(IPackageVersion version) + public void Refresh(IPackageVersion version) { SetPackageVersion(version); diff --git a/Modules/Physics/ScriptBindings/Physics.bindings.cs b/Modules/Physics/ScriptBindings/Physics.bindings.cs index f945fb444d..7e5b578f0f 100644 --- a/Modules/Physics/ScriptBindings/Physics.bindings.cs +++ b/Modules/Physics/ScriptBindings/Physics.bindings.cs @@ -55,7 +55,8 @@ public enum SupportedUnityFeatures CharacterControllerSupport = 1 << 6 }; - const uint k_InvalidID = 0; + public const uint k_InvalidID = 0; + public const uint k_FallbackIntegrationId = 0xDECAFBAD; [FieldOffset(0)] public readonly uint Id; diff --git a/Modules/PhysicsEditor/PhysicsManagerInspector.cs b/Modules/PhysicsEditor/PhysicsManagerInspector.cs index 9d26838d75..69e3c94d58 100644 --- a/Modules/PhysicsEditor/PhysicsManagerInspector.cs +++ b/Modules/PhysicsEditor/PhysicsManagerInspector.cs @@ -45,6 +45,16 @@ static class UXMLPath const string k_layerMatrixFoldoutPref = "project-settings-collision-matrix-unfold"; const int k_MaxLayers = 32; + static class Content + { + public static readonly string classicWarning = EditorGUIUtility.TrTextContent("You have changed the active physics SDK integration. For the change to take effect please restart the Editor.").text; + public static readonly string classicFallbackWarning = EditorGUIUtility.TrTextContent($"{classicWarning} \nNote: Setting this value to 'None' will cause all physics APIs and Components to no longer work.").text; + + public static readonly string classicDropDownTooltip = EditorGUIUtility.TrTextContent($"The current physics SDK integration used by Unity's GameObject API. {dropDownTooltipBase}").text; + public static readonly string entitiesDropDownTooltip = EditorGUIUtility.TrTextContent($"The current physics SDK integration used by Unity's Entities API. {dropDownTooltipBase}").text; + const string dropDownTooltipBase = "Changing this value to another SDK integration has the potential to change the behavior of your physics Components. \nTweaking your physics simulation might be necessary due to behavior differences between different physics SDKs."; + } + static SerializedObject LoadGameManagerAssetAtPath(string path) { var found = AssetDatabase.LoadAllAssetsAtPath(path); @@ -84,57 +94,59 @@ static SettingsProvider CreatePhysicsSettingsItemProvider() var classicEngineDropdown = rootElement.Q(name: "classic-dropdown"); var classicEngineHelpboxWarning = rootElement.Q(name: "classic-helpbox-warning"); - classicEngineHelpboxWarning.text = "You've changed the active physics SDK integration. This requires a restart of the Editor for the change to take effect."; - classicEngineHelpboxWarning.visible = false; int currentChoiceIndex = 0; + uint currentSerializedId = serializedObject.FindProperty("m_CurrentBackendId").uintValue; uint currentId = Physics.GetCurrentIntegrationId(); + for (int i = 0; i < infos.Length; ++i) { IntegrationInfo info = infos[i]; classicEngineDropdown.choices.Add(info.Name); - if (currentId == info.Id) + if (currentSerializedId == info.Id) currentChoiceIndex = i; } classicEngineDropdown.value = classicEngineDropdown.choices[currentChoiceIndex]; + classicEngineDropdown.tooltip = Content.classicDropDownTooltip; - if (!Unsupported.IsDeveloperMode() || Application.isPlaying) - classicEngineDropdown.SetEnabled(false); - else + classicEngineHelpboxWarning.text = currentSerializedId == IntegrationInfo.k_FallbackIntegrationId ? Content.classicFallbackWarning : Content.classicWarning; + classicEngineHelpboxWarning.visible = currentId != currentSerializedId; + + classicEngineDropdown.RegisterValueChangedCallback((evt) => { - classicEngineDropdown.RegisterValueChangedCallback((evt) => - { - if (evt.newValue == evt.previousValue) - return; + if (evt.newValue == evt.previousValue) + return; - uint oldIntegrationId = Physics.GetCurrentIntegrationId(); - uint newIntegrationId = 0; - ReadOnlySpan integrationInfos = Physics.GetIntegrationInfos(); - for (int i = 0; i < integrationInfos.Length; ++i) + uint oldIntegrationId = Physics.GetCurrentIntegrationId(); + uint newIntegrationId = 0; + ReadOnlySpan integrationInfos = Physics.GetIntegrationInfos(); + for (int i = 0; i < integrationInfos.Length; ++i) + { + IntegrationInfo info = integrationInfos[i]; + if (info.Name == evt.newValue) { - IntegrationInfo info = integrationInfos[i]; - if (info.Name == evt.newValue) - { - newIntegrationId = info.Id; - } + newIntegrationId = info.Id; } + } - var idProp = serializedObject.FindProperty("m_CurrentBackendId"); - idProp.uintValue = newIntegrationId; + var idProp = serializedObject.FindProperty("m_CurrentBackendId"); + idProp.uintValue = newIntegrationId; - //force apply the property here as we want to ensure that the change is done immediately - serializedObject.ApplyModifiedProperties(); + //force apply the property here as we want to ensure that the change is done immediately + serializedObject.ApplyModifiedProperties(); - //enable warning box if we are swapping - classicEngineHelpboxWarning.visible = newIntegrationId != Physics.GetCurrentIntegrationId(); - }); - } + //enable warning box if we are swapping and set the correct text depending on integration + classicEngineHelpboxWarning.text = newIntegrationId == IntegrationInfo.k_FallbackIntegrationId? Content.classicFallbackWarning : Content.classicWarning; + classicEngineHelpboxWarning.visible = newIntegrationId != Physics.GetCurrentIntegrationId(); + }); var ecsEngineDropdown = rootElement.Q(name: "ecs-dropdown"); var ecsEngineHelpboxInfo = rootElement.Q(name: "ecs-helpbox-info"); var ecsEngineHelpboxWarning = rootElement.Q(name: "ecs-helpbox-warning"); + ecsEngineDropdown.tooltip = Content.entitiesDropDownTooltip; + if (EcsExtension != null) { EcsExtension.SetupMainPageItems(ecsEngineDropdown, ecsEngineHelpboxInfo, ecsEngineHelpboxWarning, serializedObject); @@ -490,7 +502,7 @@ static void SetupECSTab(TabView tabs, SerializedObject serializedObject) if (EcsExtension == null) return; - var tab = new Tab() { label = "ECS", name = "tab__ecs" }; + var tab = new Tab() { label = "Entities", name = "tab__ecs" }; var tabContent = new VisualElement() { name = "tab-content__ecs" }; tabContent.AddToClassList("project-settings__physics__tab-content"); diff --git a/Modules/QuickSearch/Editor/Providers/AssetProvider.cs b/Modules/QuickSearch/Editor/Providers/AssetProvider.cs index 53a815cb87..10238ee9fe 100644 --- a/Modules/QuickSearch/Editor/Providers/AssetProvider.cs +++ b/Modules/QuickSearch/Editor/Providers/AssetProvider.cs @@ -67,7 +67,7 @@ public Type type { if (!m_HasType) { - if (source.EndsWith("prefab", StringComparison.OrdinalIgnoreCase)) + if (source.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase)) m_Type = AssetDatabase.GetTypeFromPathAndFileID(source, (long)gid.targetObjectId); else if (flags.HasAll(SearchDocumentFlags.Nested | SearchDocumentFlags.Asset)) { diff --git a/Modules/TextCoreTextEngine/Managed/TextGenerator/TextGeneratorParsing.cs b/Modules/TextCoreTextEngine/Managed/TextGenerator/TextGeneratorParsing.cs index 477d28ab14..6d197b73c9 100644 --- a/Modules/TextCoreTextEngine/Managed/TextGenerator/TextGeneratorParsing.cs +++ b/Modules/TextCoreTextEngine/Managed/TextGenerator/TextGeneratorParsing.cs @@ -765,43 +765,6 @@ public void ParsingPhase(TextInfo textInfo, TextGenerationSettings generationSet { textInfo.textElementInfo[m_CharacterCount].isVisible = true; - #region Experimental Margin Shaper - - //Vector2 shapedMargins; - //if (marginShaper) - //{HorizontalAlignmentOption - // shapedMargins = m_marginShaper.GetShapedMargins(textInfo.textElementInfo[m_CharacterCount].baseLine); - // if (shapedMargins.x < margins.x) - // { - // shapedMargins.x = m_MarginLeft; - // } - // else - // { - // shapedMargins.x += m_MarginLeft - margins.x; - // } - // if (shapedMargins.y < margins.z) - // { - // shapedMargins.y = m_MarginRight; - // } - // else - // { - // shapedMargins.y += m_MarginRight - margins.z; - // } - //} - //else - //{ - // shapedMargins.x = m_MarginLeft; - // shapedMargins.y = m_MarginRight; - //} - //width = marginWidth + 0.0001f - shapedMargins.x - shapedMargins.y; - //if (m_Width != -1 && m_Width < width) - //{ - // width = m_Width; - //} - //textInfo.lineInfo[m_LineNumber].marginLeft = shapedMargins.x; - - #endregion - float marginLeft = m_MarginLeft; float marginRight = m_MarginRight; @@ -1327,7 +1290,6 @@ public void ParsingPhase(TextInfo textInfo, TextGenerationSettings generationSet if (isWhiteSpace) { textInfo.textElementInfo[m_CharacterCount].isVisible = false; - m_LastVisibleCharacterOfLine = m_CharacterCount; m_LineVisibleSpaceCount = textInfo.lineInfo[m_LineNumber].spaceCount += 1; textInfo.lineInfo[m_LineNumber].marginLeft = marginLeft; textInfo.lineInfo[m_LineNumber].marginRight = marginRight; @@ -1432,7 +1394,6 @@ public void ParsingPhase(TextInfo textInfo, TextGenerationSettings generationSet marginRight = textInfo.lineInfo[m_LineNumber].marginRight; } - float textHeight = m_MaxAscender - (m_MaxLineDescender - m_LineOffset) + (m_LineOffset > 0 && m_IsDrivenLineSpacing == false ? m_MaxLineAscender - m_StartOfLineAscender : 0); float textWidth = Mathf.Abs(m_XAdvance) + (!generationSettings.isRightToLeft ? m_Ellipsis.character.m_Glyph.metrics.horizontalAdvance : 0) * (1 - m_CharWidthAdjDelta) * scale; float widthOfTextAreaForEllipsis = m_Width != -1 ? Mathf.Min(marginWidth + 0.0001f - marginLeft - marginRight, m_Width) : marginWidth + 0.0001f - marginLeft - marginRight; @@ -1679,9 +1640,6 @@ public void ParsingPhase(TextInfo textInfo, TextGenerationSettings generationSet m_MeshExtents.max.x = Mathf.Max(m_MeshExtents.max.x, textInfo.textElementInfo[m_CharacterCount].topRight.x); m_MeshExtents.max.y = Mathf.Max(m_MeshExtents.max.y, textInfo.textElementInfo[m_CharacterCount].topRight.y); - - //m_MeshExtents.min = new Vector2(Mathf.Min(m_MeshExtents.min.x, textInfo.textElementInfo[m_CharacterCount].bottomLeft.x), Mathf.Min(m_MeshExtents.min.y, textInfo.textElementInfo[m_CharacterCount].bottomLeft.y)); - //m_MeshExtents.max = new Vector2(Mathf.Max(m_MeshExtents.max.x, textInfo.textElementInfo[m_CharacterCount].topRight.x), Mathf.Max(m_MeshExtents.max.y, textInfo.textElementInfo[m_CharacterCount].topRight.y)); } #endregion Track Text Extents @@ -1696,11 +1654,15 @@ public void ParsingPhase(TextInfo textInfo, TextGenerationSettings generationSet if ((isWhiteSpace || charCode == k_ZeroWidthSpace || (charCode == k_HyphenMinus && (m_CharacterCount <= 0 || char.IsWhiteSpace((char)textInfo.textElementInfo[m_CharacterCount - 1].character) == false)) || charCode == k_SoftHyphen) && (!m_IsNonBreakingSpace || ignoreNonBreakingSpace) && charCode != k_NoBreakSpace && charCode != k_FigureSpace && charCode != k_NonBreakingHyphen && charCode != k_NarrowNoBreakSpace && charCode != k_WordJoiner) { - isFirstWordOfLine = false; - shouldSaveHardLineBreak = true; + // Ignore Hyphen (0x2D) when preceded by a whitespace + if ((charCode == k_HyphenMinus && m_CharacterCount > 0 && char.IsWhiteSpace((char)textInfo.textElementInfo[m_CharacterCount - 1].character)) == false) + { + isFirstWordOfLine = false; + shouldSaveHardLineBreak = true; - //Reset soft line breaking point since we now have a valid hard break point. - m_SavedSoftLineBreakState.previousWordBreak = -1; + //Reset soft line breaking point since we now have a valid hard break point. + m_SavedSoftLineBreakState.previousWordBreak = -1; + } } // Handling for East Asian scripts else if (m_IsNonBreakingSpace == false && (TextGeneratorUtilities.IsHangul(charCode) && textSettings.lineBreakingRules.useModernHangulLineBreakingRules == false || TextGeneratorUtilities.IsCJK(charCode))) diff --git a/Modules/TextCoreTextEngine/Managed/TextGenerator/TextGeneratorPreferredValues.cs b/Modules/TextCoreTextEngine/Managed/TextGenerator/TextGeneratorPreferredValues.cs index db70060fbe..a7b1b6f33d 100644 --- a/Modules/TextCoreTextEngine/Managed/TextGenerator/TextGeneratorPreferredValues.cs +++ b/Modules/TextCoreTextEngine/Managed/TextGenerator/TextGeneratorPreferredValues.cs @@ -662,23 +662,11 @@ protected virtual Vector2 CalculatePreferredValues(ref float fontSize, Vector2 m if (charCode == k_Tab || charCode == k_ZeroWidthSpace || ((textWrapMode == TextWrappingMode.PreserveWhitespace || textWrapMode == TextWrappingMode.PreserveWhitespaceNoWrap) && (isWhiteSpace || charCode == k_ZeroWidthSpace)) || (isWhiteSpace == false && charCode != k_ZeroWidthSpace && charCode != k_SoftHyphen && charCode != k_EndOfText) || (charCode == k_SoftHyphen && isSoftHyphenIgnored == false) || m_TextElementType == TextElementType.Sprite) { - //float marginLeft = m_MarginLeft; - //float marginRight = m_MarginRight; - - // Injected characters do not override margins - //if (isInjectedCharacter) - //{ - // marginLeft = textInfo.lineInfo[m_LineNumber].marginLeft; - // marginRight = textInfo.lineInfo[m_LineNumber].marginRight; - //} - widthOfTextArea = m_Width != -1 ? Mathf.Min(marginWidth + 0.0001f - m_MarginLeft - m_MarginRight, m_Width) : marginWidth + 0.0001f - m_MarginLeft - m_MarginRight; // Calculate the line breaking width of the text. textWidth = Mathf.Abs(m_XAdvance) + currentGlyphMetrics.horizontalAdvance * (1 - m_CharWidthAdjDelta) * (charCode == k_SoftHyphen ? currentElementUnmodifiedScale : currentElementScale); - int testedCharacterCount = m_CharacterCount; - // Handling of Horizontal Bounds #region Current Line Horizontal Bounds Check @@ -867,7 +855,13 @@ protected virtual Vector2 CalculatePreferredValues(ref float fontSize, Vector2 m } else if (m_MonoSpacing != 0) { - m_XAdvance += (m_MonoSpacing - monoAdvance + ((m_CurrentFontAsset.regularStyleSpacing + characterSpacingAdjustment) * currentEmScale) + m_CSpacing) * (1 - m_CharWidthAdjDelta); + float monoAdjustment; + if (m_DuoSpace && (charCode == '.' || charCode == ':' || charCode == ',')) + monoAdjustment = m_MonoSpacing / 2 - monoAdvance; + else + monoAdjustment = m_MonoSpacing - monoAdvance; + + m_XAdvance += (monoAdjustment + ((m_CurrentFontAsset.regularStyleSpacing + characterSpacingAdjustment) * currentEmScale) + m_CSpacing) * (1 - m_CharWidthAdjDelta); if (isWhiteSpace || charCode == k_ZeroWidthSpace) m_XAdvance += generationSettings.wordSpacing * currentEmScale; @@ -1082,9 +1076,11 @@ protected virtual Vector2 CalculatePreferredValues(ref float fontSize, Vector2 m renderedHeight += generationSettings.margins.y > 0 ? generationSettings.margins.y : 0; renderedHeight += generationSettings.margins.w > 0 ? generationSettings.margins.w : 0; - // Round Preferred Values to nearest 5/100. - renderedWidth = (int)(renderedWidth * 100 + 1f) / 100f; - renderedHeight = (int)(renderedHeight * 100 + 1f) / 100f; + // Round Preferred Values to nearest 1/100. + if (renderedWidth != 0.0f) + renderedWidth = (int)(renderedWidth * 100 + 1f) / 100f; + if (renderedHeight != 0.0f) + renderedHeight = (int)(renderedHeight * 100 + 1f) / 100f; Profiler.EndSample(); diff --git a/Modules/UIBuilder/Editor/Builder/BuilderSelection.cs b/Modules/UIBuilder/Editor/Builder/BuilderSelection.cs index d27c22705b..3381eeac56 100644 --- a/Modules/UIBuilder/Editor/Builder/BuilderSelection.cs +++ b/Modules/UIBuilder/Editor/Builder/BuilderSelection.cs @@ -138,6 +138,16 @@ public BuilderSelection(VisualElement root, BuilderPaneWindow paneWindow) m_Root.Add(m_DummyElementForStyleChangeNotifications); } + internal VisualElement GetFirstSelectedElement() + { + foreach (var element in m_Selection) + { + return element; + } + + return null; + } + public void AssignNotifiers(IEnumerable notifiers) { m_Notifiers.Clear(); diff --git a/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorerItem.cs b/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorerItem.cs index df59fce2ea..a923973b99 100644 --- a/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorerItem.cs +++ b/Modules/UIBuilder/Editor/Builder/Explorer/BuilderExplorerItem.cs @@ -66,6 +66,12 @@ public bool IsRenamingActive() void FocusOnRenameTextField() { + if (IsRenamingActive()) + { + m_RenameTextField.Focus(); + return; + } + var nameLabel = this.Q