11// Copyright (c) Microsoft Corporation. All rights reserved.
22// Licensed under the MIT License. See LICENSE in the project root for license information.
33
4+ using Microsoft . MixedReality . Toolkit . Core . Definitions ;
45using Microsoft . MixedReality . Toolkit . Core . Extensions . EditorClassExtensions ;
6+ using Microsoft . MixedReality . Toolkit . Core . Services ;
7+ using Microsoft . MixedReality . Toolkit . Core . Utilities . Async ;
58using Microsoft . MixedReality . Toolkit . Core . Utilities . Editor . Setup ;
69using UnityEditor ;
710using UnityEngine ;
@@ -10,6 +13,8 @@ namespace Microsoft.MixedReality.Toolkit.Core.Inspectors.Profiles
1013{
1114 public abstract class MixedRealityBaseConfigurationProfileInspector : BaseMixedRealityInspector
1215 {
16+ private const string IsCustomProfileProperty = "isCustomProfile" ;
17+
1318 private static readonly GUIContent NewProfileContent = new GUIContent ( "+" , "Create New Profile" ) ;
1419
1520 [ SerializeField ]
@@ -18,6 +23,10 @@ public abstract class MixedRealityBaseConfigurationProfileInspector : BaseMixedR
1823 [ SerializeField ]
1924 private Texture2D logoDarkTheme = null ;
2025
26+ private static BaseMixedRealityProfile profile ;
27+ private static SerializedObject targetProfile ;
28+ private static BaseMixedRealityProfile profileToCopy ;
29+
2130 protected virtual void Awake ( )
2231 {
2332 if ( logoLightTheme == null )
@@ -31,6 +40,68 @@ protected virtual void Awake()
3140 }
3241 }
3342
43+ protected virtual void OnEnable ( )
44+ {
45+ targetProfile = serializedObject ;
46+ profile = target as BaseMixedRealityProfile ;
47+ }
48+
49+ [ MenuItem ( "CONTEXT/BaseMixedRealityProfile/Create Copy from Profile Values" , false , 0 ) ]
50+ protected static async void CreateCopyProfileValues ( )
51+ {
52+ profileToCopy = profile ;
53+ ScriptableObject newProfile = CreateInstance ( profile . GetType ( ) . ToString ( ) ) ;
54+ profile = newProfile . CreateAsset ( "Assets/MixedRealityToolkit-Generated/CustomProfiles" ) as BaseMixedRealityProfile ;
55+ Debug . Assert ( profile != null ) ;
56+
57+ await new WaitUntil ( ( ) => profileToCopy != profile ) ;
58+
59+ Selection . activeObject = null ;
60+ PasteProfileValues ( ) ;
61+ Selection . activeObject = profile ;
62+
63+ if ( ! profileToCopy . IsCustomProfile )
64+ {
65+ // For now we only replace it if it's the master configuration profile.
66+ // Sub-profiles are easy to update in the master configuration inspector.
67+ if ( MixedRealityToolkit . Instance . ActiveProfile . GetType ( ) == profile . GetType ( ) )
68+ {
69+ MixedRealityToolkit . Instance . ActiveProfile = profile as MixedRealityToolkitConfigurationProfile ;
70+ }
71+ }
72+ }
73+
74+ [ MenuItem ( "CONTEXT/BaseMixedRealityProfile/Copy Profile Values" , false , 1 ) ]
75+ private static void CopyProfileValues ( )
76+ {
77+ profileToCopy = profile ;
78+ }
79+
80+ [ MenuItem ( "CONTEXT/BaseMixedRealityProfile/Paste Profile Values" , true ) ]
81+ private static bool PasteProfileValuesValidation ( )
82+ {
83+ return profile != null &&
84+ targetProfile != null &&
85+ profileToCopy != null &&
86+ targetProfile . FindProperty ( IsCustomProfileProperty ) . boolValue &&
87+ profile . GetType ( ) == profileToCopy . GetType ( ) ;
88+ }
89+
90+ [ MenuItem ( "CONTEXT/BaseMixedRealityProfile/Paste Profile Values" , false , 2 ) ]
91+ private static void PasteProfileValues ( )
92+ {
93+ Undo . RecordObject ( profile , "Paste Profile Values" ) ;
94+ bool targetIsCustom = targetProfile . FindProperty ( IsCustomProfileProperty ) . boolValue ;
95+ string originalName = targetProfile . targetObject . name ;
96+ EditorUtility . CopySerialized ( profileToCopy , targetProfile . targetObject ) ;
97+ targetProfile . Update ( ) ;
98+ targetProfile . FindProperty ( IsCustomProfileProperty ) . boolValue = targetIsCustom ;
99+ targetProfile . ApplyModifiedProperties ( ) ;
100+ targetProfile . targetObject . name = originalName ;
101+ Debug . Assert ( targetProfile . FindProperty ( IsCustomProfileProperty ) . boolValue == targetIsCustom ) ;
102+ AssetDatabase . SaveAssets ( ) ;
103+ }
104+
34105 /// <summary>
35106 /// Render the Mixed Reality Toolkit Logo.
36107 /// </summary>
@@ -44,6 +115,15 @@ protected void RenderMixedRealityToolkitLogo()
44115 GUILayout . Space ( 12f ) ;
45116 }
46117
118+ protected static void CheckProfileLock ( Object target )
119+ {
120+ if ( MixedRealityPreferences . LockProfiles && ! ( ( BaseMixedRealityProfile ) target ) . IsCustomProfile )
121+ {
122+ EditorGUILayout . HelpBox ( "This profile is part of the default set from the Mixed Reality Toolkit SDK. You can make a copy of this profile, and customize it if needed." , MessageType . Warning ) ;
123+ GUI . enabled = false ;
124+ }
125+ }
126+
47127 protected static bool RenderProfile ( SerializedProperty property )
48128 {
49129 bool changed = false ;
@@ -52,19 +132,50 @@ protected static bool RenderProfile(SerializedProperty property)
52132
53133 if ( property . objectReferenceValue == null )
54134 {
55- if ( GUILayout . Button ( NewProfileContent , EditorStyles . miniButton , GUILayout . Width ( 32f ) ) )
135+ if ( GUILayout . Button ( NewProfileContent , EditorStyles . miniButton , GUILayout . Width ( 20f ) ) )
56136 {
57137 var profileTypeName = property . type . Replace ( "PPtr<$" , string . Empty ) . Replace ( ">" , string . Empty ) ;
58138 Debug . Assert ( profileTypeName != null , "No Type Found" ) ;
59- ScriptableObject profile = CreateInstance ( profileTypeName ) ;
60- profile . CreateAsset ( AssetDatabase . GetAssetPath ( Selection . activeObject ) ) ;
61- property . objectReferenceValue = profile ;
139+ ScriptableObject instance = CreateInstance ( profileTypeName ) ;
140+ var newProfile = instance . CreateAsset ( AssetDatabase . GetAssetPath ( Selection . activeObject ) ) as BaseMixedRealityProfile ;
141+ property . objectReferenceValue = newProfile ;
142+ property . serializedObject . ApplyModifiedProperties ( ) ;
62143 changed = true ;
63144 }
64145 }
146+ else
147+ {
148+ var renderedProfile = property . objectReferenceValue as BaseMixedRealityProfile ;
149+ Debug . Assert ( renderedProfile != null ) ;
150+
151+ if ( ! renderedProfile . IsCustomProfile && profile . IsCustomProfile )
152+ {
153+ if ( GUILayout . Button ( new GUIContent ( "</>" , "Replace with a copy of the default profile." ) , EditorStyles . miniButton , GUILayout . Width ( 32f ) ) )
154+ {
155+ profileToCopy = renderedProfile ;
156+ var profileTypeName = property . type . Replace ( "PPtr<$" , string . Empty ) . Replace ( ">" , string . Empty ) ;
157+ Debug . Assert ( profileTypeName != null , "No Type Found" ) ;
158+
159+ ScriptableObject instance = CreateInstance ( profileTypeName ) ;
160+ var newProfile = instance . CreateAsset ( AssetDatabase . GetAssetPath ( Selection . activeObject ) ) as BaseMixedRealityProfile ;
161+ property . objectReferenceValue = newProfile ;
162+ property . serializedObject . ApplyModifiedProperties ( ) ;
163+ PasteProfileValuesDelay ( newProfile ) ;
164+ changed = true ;
165+ }
166+ }
167+ }
65168
66169 EditorGUILayout . EndHorizontal ( ) ;
67170 return changed ;
68171 }
172+
173+ private static async void PasteProfileValuesDelay ( BaseMixedRealityProfile newProfile )
174+ {
175+ await new WaitUntil ( ( ) => profile == newProfile ) ;
176+ Selection . activeObject = null ;
177+ PasteProfileValues ( ) ;
178+ Selection . activeObject = newProfile ;
179+ }
69180 }
70- }
181+ }
0 commit comments