7
7
using UnityEditor ;
8
8
using UnityEngine ;
9
9
using UnityEngine . UIElements ;
10
- using Object = UnityEngine . Object ;
11
10
12
11
13
12
namespace SatorImaging . UnitySourceGenerator
14
13
{
15
- internal class ProjectSettingsPanel : SettingsProvider
14
+ public class ProjectSettingsPanel : SettingsProvider
16
15
{
17
16
const float PADDING_WIDTH = 4 ;
18
17
const string DISPLAY_NAME = "Alternative Source Generator for Unity" ;
@@ -86,31 +85,38 @@ void OnGUI()
86
85
87
86
88
87
static ProjectSettingsData _settings = ProjectSettingsData . instance ;
89
- static string [ ] _generatorPaths = Array . Empty < string > ( ) ;
90
- static bool [ ] _isEmitterExists = Array . Empty < bool > ( ) ;
91
- static string [ ] _emitterPaths = Array . Empty < string > ( ) ;
92
- static string _generatorPathToShowEmitters = null ;
93
- static Dictionary < string , string > _generatorNameToOutputFileName = new ( ) ;
94
- // GUI classes cannot be initialized on field definition.
88
+ static Type _generatorTypeToShowEmittersInGUI = null ;
89
+ static Type [ ] _referencingEmittersToShowInGUI = Array . Empty < Type > ( ) ;
90
+ static Type [ ] _generatorTypes = Array . Empty < Type > ( ) ;
91
+ static bool [ ] _isGeneratorHasEmitters = Array . Empty < bool > ( ) ;
92
+ static Dictionary < Type , string > _targetClassToScriptFilePath = new ( ) ;
93
+ static Dictionary < Type , string [ ] > _targetClassToOutputFilePaths = new ( ) ;
94
+ static Dictionary < Type , string [ ] > _targetClassToOutputFileNames = new ( ) ;
95
+ // some GUI classes cannot be accessed on field definition.
95
96
static GUIContent gui_emittersBtn ;
96
97
static GUIContent gui_deleteBtn ;
97
98
static GUIContent gui_runBtn ;
98
99
static GUIContent gui_unveilBtn ;
99
- static GUILayoutOption gui_toggleWidth ;
100
- static GUILayoutOption gui_buttonWidth ;
101
100
static GUIStyle gui_noBGButtonStyle ;
102
101
static GUIStyle gui_deleteMiniLabel ;
102
+ static GUIContent gui_suspendAutoReloadLabel = new GUIContent ( " Suspend Auto Reload while Unity Editor in Background *experimental" ) ;
103
+ static GUIContent gui_autoRunLabel = new GUIContent ( " Auto Run Generators on Script Update / Reimport" ) ;
104
+ static GUIContent gui_buttonColumnLabel = new GUIContent ( "On Run" ) ;
105
+ static GUIContent gui_refEmittersLabel = new GUIContent ( "Referencing Emitters" ) ;
106
+ static GUIContent gui_multiGeneratorsLabel = new GUIContent ( "MULTIPLE GENERATORS" ) ;
107
+ static GUIContent gui_noSourceGenLabel = new GUIContent ( "NO SOURCE GENERATORS IN PROJECT" ) ;
108
+ static GUIContent gui_debugLabel = new GUIContent ( "DEBUG" ) ;
109
+ static GUILayoutOption gui_toggleWidth = GUILayout . Width ( 16 ) ;
110
+ static GUILayoutOption gui_buttonWidth = GUILayout . Width ( 32 ) ;
103
111
104
112
// NOTE: class is reference type and reference type variable is "passed by value".
105
113
// to take reference to newly created object, need `ref` chain.
106
114
static void Wakeup ( ref Editor cachedEditor )
107
115
{
108
116
gui_emittersBtn ??= new ( EditorGUIUtility . IconContent ( "d_icon dropdown" ) ) ;
109
117
gui_deleteBtn ??= new ( EditorGUIUtility . IconContent ( "d_TreeEditor.Trash" ) ) ;
110
- gui_runBtn ??= new ( EditorGUIUtility . IconContent ( "PlayButton On" ) ) ; //d_playLoopOff
111
- gui_unveilBtn ??= new ( EditorGUIUtility . IconContent ( "d_Linked" ) ) ; //SavePassive/SaveActive/SaveFromPlay/d_pick/
112
- gui_toggleWidth ??= GUILayout . Width ( 16 ) ;
113
- gui_buttonWidth ??= GUILayout . Width ( 32 ) ;
118
+ gui_runBtn ??= new ( EditorGUIUtility . IconContent ( "PlayButton On" ) ) ;
119
+ gui_unveilBtn ??= new ( EditorGUIUtility . IconContent ( "d_Linked" ) ) ;
114
120
if ( gui_noBGButtonStyle == null )
115
121
{
116
122
gui_noBGButtonStyle = new ( EditorStyles . iconButton ) ;
@@ -129,18 +135,36 @@ static void Wakeup(ref Editor cachedEditor)
129
135
_settings = ProjectSettingsData . instance ;
130
136
_settings . hideFlags = HideFlags . HideAndDontSave & ~ HideFlags . NotEditable ;
131
137
132
- _generatorPaths = USGEngine . TypeNameToInfo
133
- // remove emitter class. it can be access thru referencing emitter list.
134
- . Where ( static x => x . Value . TargetClass == null || x . Value . Attribute . GeneratorClass == null )
135
- . Select ( static x => USGUtility . GetAssetPathByName ( x . Key ) )
136
- //.Where(static x => x.StartsWith("Assets/"))
138
+ // caching heavy ops
139
+ _targetClassToOutputFilePaths = USGEngine . GeneratorInfoList
140
+ . ToLookup ( static x => x . TargetClass )
141
+ . ToDictionary (
142
+ static x => x . Key ,
143
+ static x => x . Select ( static x => USGEngine . GetGeneratorOutputPath ( x ) ) . ToArray ( ) ) ;
144
+ _targetClassToOutputFileNames = _targetClassToOutputFilePaths
145
+ . ToDictionary (
146
+ static x => x . Key ,
147
+ static x => x . Value . Select ( static x => Path . GetFileName ( x ) ) . ToArray ( ) ) ;
148
+
149
+ _generatorTypes = USGEngine . GeneratorInfoList
150
+ . Select ( static x => x . Attribute . GeneratorClass )
151
+ . Union ( _targetClassToOutputFileNames
152
+ . Where ( static x => x . Value . Length > 1 )
153
+ . Select ( static x => x . Key ) )
154
+ . Distinct ( )
155
+ . OrderBy ( static x => x . FullName )
137
156
. ToArray ( ) ;
138
- _isEmitterExists = _generatorPaths
139
- . Select ( static x => GetEmitters ( x ) . Length > 0 )
157
+ _isGeneratorHasEmitters = _generatorTypes
158
+ . Select ( static x => GetReferencingEmitters ( x ) . Length > 0 )
140
159
. ToArray ( ) ;
141
- _emitterPaths = GetEmitters ( null ) ; //clear
142
- _generatorNameToOutputFileName = USGEngine . TypeNameToInfo
143
- . ToDictionary ( static x => x . Key , static x => x . Value . OutputFileName ) ;
160
+ _referencingEmittersToShowInGUI = GetReferencingEmitters ( null ) ; // not only set variable, but clear ref emitters panel settings.
161
+
162
+ _targetClassToScriptFilePath = USGEngine . GeneratorInfoList
163
+ . Select ( static x => x . TargetClass )
164
+ . Union ( _generatorTypes )
165
+ . ToDictionary (
166
+ static x => x ,
167
+ static x => USGUtility . GetAssetPathByType ( x ) ?? throw new Exception ( ) ) ;
144
168
145
169
Editor . CreateCachedEditor ( _settings , null , ref cachedEditor ) ;
146
170
}
@@ -159,8 +183,8 @@ static void DrawEditor(Editor cachedEditor, ref Vector2 currentScroll)
159
183
EditorGUILayout . BeginVertical ( ) ;
160
184
{
161
185
EditorGUI . BeginChangeCheck ( ) ;
162
- var suspendAutoReload = EditorGUILayout . ToggleLeft ( " Suspend Auto Reload while Unity Editor in Background *experimental" , _settings . SuspendAutoReloadWhileEditorInBackground ) ;
163
- var autoEmit = EditorGUILayout . ToggleLeft ( " Auto Run Generators on Script Update / Reimport" , _settings . AutoEmitOnScriptUpdate ) ;
186
+ var suspendAutoReload = EditorGUILayout . ToggleLeft ( gui_suspendAutoReloadLabel , _settings . SuspendAutoReloadWhileEditorInBackground ) ;
187
+ var autoEmit = EditorGUILayout . ToggleLeft ( gui_autoRunLabel , _settings . AutoEmitOnScriptUpdate ) ;
164
188
if ( EditorGUI . EndChangeCheck ( ) )
165
189
{
166
190
_settings . SuspendAutoReloadWhileEditorInBackground = suspendAutoReload ;
@@ -169,28 +193,28 @@ static void DrawEditor(Editor cachedEditor, ref Vector2 currentScroll)
169
193
}
170
194
//EditorGUILayout.Space();
171
195
172
- EditorGUILayout . LabelField ( "On Run" , EditorStyles . miniLabel ) ;
173
- if ( _generatorPaths . Length == 0 )
174
- EditorGUILayout . LabelField ( "NO SOURCE GENERATORS IN PROJECT" ) ;
196
+ EditorGUILayout . LabelField ( gui_buttonColumnLabel , EditorStyles . miniLabel ) ;
197
+ if ( _generatorTypes . Length == 0 )
198
+ EditorGUILayout . LabelField ( gui_noSourceGenLabel ) ;
175
199
else
176
- for ( int i = 0 ; i < _generatorPaths . Length ; i ++ )
200
+ for ( int i = 0 ; i < _generatorTypes . Length ; i ++ )
177
201
{
178
- DrawGenerator ( _generatorPaths [ i ] , _isEmitterExists [ i ] ) ;
202
+ DrawGenerator ( _generatorTypes [ i ] , _isGeneratorHasEmitters [ i ] ) ;
179
203
}
180
204
EditorGUILayout . Space ( ) ;
181
205
182
- EditorGUILayout . LabelField ( "Referencing Emitters" ) ;
183
- if ( _generatorPathToShowEmitters != null )
206
+ if ( _generatorTypeToShowEmittersInGUI != null )
184
207
{
185
- for ( int i = 0 ; i < _emitterPaths . Length ; i ++ )
208
+ EditorGUILayout . LabelField ( gui_refEmittersLabel , EditorStyles . largeLabel ) ;
209
+ for ( int i = 0 ; i < _referencingEmittersToShowInGUI . Length ; i ++ )
186
210
{
187
- DrawGenerator ( _emitterPaths [ i ] , false ) ;
211
+ DrawGenerator ( _referencingEmittersToShowInGUI [ i ] , false ) ;
188
212
}
189
213
}
190
214
EditorGUILayout . Space ( ) ;
191
215
192
216
GUILayout . FlexibleSpace ( ) ;
193
- _debugFoldout = EditorGUILayout . Foldout ( _debugFoldout , "DEBUG" , true ) ;
217
+ _debugFoldout = EditorGUILayout . Foldout ( _debugFoldout , gui_debugLabel , true ) ;
194
218
if ( _debugFoldout )
195
219
{
196
220
cachedEditor . OnInspectorGUI ( ) ;
@@ -208,11 +232,12 @@ static void DrawEditor(Editor cachedEditor, ref Vector2 currentScroll)
208
232
}
209
233
210
234
211
- static void DrawGenerator ( string filePath , bool showEmitterBtn )
235
+ static void DrawGenerator ( Type t , bool showEmitterBtn ) // string filePath, bool showEmitterBtn)
212
236
{
213
237
EditorGUILayout . BeginHorizontal ( ) ;
214
238
{
215
- var fileName = Path . GetFileNameWithoutExtension ( filePath ) ;
239
+ // NOTE: USGUtility functions are heavy for use in GUI loops, cache it!!
240
+ var filePath = _targetClassToScriptFilePath [ t ] ;
216
241
217
242
EditorGUI . BeginChangeCheck ( ) ;
218
243
var isOn = EditorGUILayout . Toggle ( ! _settings . AutoEmitDisabledPaths . Contains ( filePath ) , gui_toggleWidth ) ;
@@ -229,53 +254,71 @@ static void DrawGenerator(string filePath, bool showEmitterBtn)
229
254
//run
230
255
if ( GUILayout . Button ( gui_runBtn , gui_buttonWidth ) )
231
256
{
232
- Debug . Log ( $ "[{ nameof ( UnitySourceGenerator ) } ] Generator running: { fileName } ") ;
233
- USGUtility . ForceGenerateByName ( fileName , false ) ;
257
+ Debug . Log ( $ "[{ nameof ( UnitySourceGenerator ) } ] Generator running: { t . FullName } ") ;
258
+ USGUtility . ForceGenerateByType ( t , false ) ;
234
259
}
235
260
236
261
//label
237
- if ( EditorGUILayout . LinkButton ( fileName ) )
262
+ if ( EditorGUILayout . LinkButton ( t . Name ) )
238
263
{
239
- EditorGUIUtility . PingObject ( AssetDatabase . LoadAssetAtPath < Object > ( filePath ) ) ;
264
+ EditorGUIUtility . PingObject ( AssetDatabase . LoadAssetAtPath < MonoScript > ( filePath ) ) ;
240
265
}
241
266
242
267
//emitters??
243
268
if ( showEmitterBtn )
244
269
{
245
270
if ( GUILayout . Button ( gui_emittersBtn , gui_noBGButtonStyle ) )
246
271
{
247
- _emitterPaths = GetEmitters ( filePath ) ;
272
+ _referencingEmittersToShowInGUI = GetReferencingEmitters ( t ) ;
248
273
}
249
274
}
250
275
//unveil??
251
276
else
252
277
{
253
- if ( GUILayout . Button ( gui_unveilBtn , gui_noBGButtonStyle ) )
254
- {
255
- EditorGUIUtility . PingObject ( AssetDatabase . LoadAssetAtPath < Object > (
256
- USGEngine . GetGeneratorOutputPath ( filePath , _generatorNameToOutputFileName [ fileName ] ) ) ) ;
257
- }
278
+ if ( _targetClassToOutputFilePaths . ContainsKey ( t ) )
279
+ for ( int i = 0 ; i < _targetClassToOutputFilePaths [ t ] . Length ; i ++ )
280
+ {
281
+ if ( GUILayout . Button ( gui_unveilBtn , gui_noBGButtonStyle ) )
282
+ {
283
+ EditorGUIUtility . PingObject (
284
+ AssetDatabase . LoadAssetAtPath < MonoScript > ( _targetClassToOutputFilePaths [ t ] [ i ] ) ) ;
285
+ }
286
+ }
258
287
}
259
288
260
289
//deleteBtn
261
- if ( _generatorNameToOutputFileName [ fileName ] ? . Length is > 0 )
290
+ if ( _targetClassToOutputFilePaths . ContainsKey ( t ) )
262
291
{
263
- GUILayout . FlexibleSpace ( ) ;
264
- if ( EditorGUIUtility . currentViewWidth > _settings . DenseViewWidthThreshold )
265
- GUILayout . Label ( _generatorNameToOutputFileName [ fileName ] , gui_deleteMiniLabel ) ;
266
- if ( GUILayout . Button ( gui_deleteBtn ) ) //, gui_noBGButtonStyle))
292
+ if ( _targetClassToOutputFilePaths [ t ] . Length == 1 )
293
+ {
294
+ GUILayout . FlexibleSpace ( ) ;
295
+ if ( EditorGUIUtility . currentViewWidth > _settings . DenseViewWidthThreshold )
296
+ GUILayout . Label ( _targetClassToOutputFileNames [ t ] [ 0 ] , gui_deleteMiniLabel ) ;
297
+ }
298
+ else
267
299
{
268
- var genFullPath = USGEngine . GetGeneratorOutputPath ( filePath , _generatorNameToOutputFileName [ fileName ] ) ;
269
- if ( EditorUtility . DisplayDialog ( nameof ( UnitySourceGenerator ) ,
270
- $ "Would you like to delete emitted file?\n " +
271
- $ "- { _generatorNameToOutputFileName [ fileName ] } \n " +
272
- $ "\n " +
273
- $ "File Path: { genFullPath } ",
274
- "Yes" , "cancel" ) )
300
+ GUILayout . FlexibleSpace ( ) ;
301
+ //if (EditorGUIUtility.currentViewWidth > _settings.DenseViewWidthThreshold)
302
+ // GUILayout.Label(gui_multiGeneratorsLabel, gui_deleteMiniLabel);
303
+ }
304
+
305
+ for ( int i = 0 ; i < _targetClassToOutputFilePaths [ t ] . Length ; i ++ )
306
+ {
307
+ if ( GUILayout . Button ( gui_deleteBtn ) )
275
308
{
276
- File . Delete ( genFullPath ) ;
277
- Debug . Log ( $ "[{ nameof ( UnitySourceGenerator ) } ] File is deleted: { genFullPath } ") ;
278
- AssetDatabase . Refresh ( ) ;
309
+ if ( File . Exists ( _targetClassToOutputFilePaths [ t ] [ i ] )
310
+ && EditorUtility . DisplayDialog (
311
+ nameof ( UnitySourceGenerator ) ,
312
+ $ "Would you like to delete emitted file?\n " +
313
+ $ "- { _targetClassToOutputFileNames [ t ] [ i ] } \n " +
314
+ $ "\n " +
315
+ $ "File Path: { _targetClassToOutputFilePaths [ t ] [ i ] } ",
316
+ "Yes" , "cancel" ) )
317
+ {
318
+ File . Delete ( _targetClassToOutputFilePaths [ t ] [ i ] ) ;
319
+ Debug . Log ( $ "[{ nameof ( UnitySourceGenerator ) } ] File is deleted: { _targetClassToOutputFilePaths [ t ] [ i ] } ") ;
320
+ AssetDatabase . Refresh ( ) ;
321
+ }
279
322
}
280
323
}
281
324
}
@@ -284,18 +327,22 @@ static void DrawGenerator(string filePath, bool showEmitterBtn)
284
327
}
285
328
286
329
287
- static string [ ] GetEmitters ( string generatorPath )
330
+ static Type [ ] GetReferencingEmitters ( Type t )
288
331
{
289
- _generatorPathToShowEmitters = generatorPath ;
290
- if ( string . IsNullOrEmpty ( generatorPath ) )
291
- return Array . Empty < string > ( ) ;
292
-
293
- var clsName = Path . GetFileNameWithoutExtension ( generatorPath ) ;
294
- return USGEngine . TypeNameToInfo
295
- . Where ( x => x . Value . Attribute . GeneratorClass ? . Name == clsName || x . Value . TargetClass ? . Name == clsName )
296
- . Select ( static x => USGUtility . GetAssetPathByName ( x . Key ) )
297
- . Where ( x => x != generatorPath ) // remove itself
332
+ _generatorTypeToShowEmittersInGUI = t ;
333
+ if ( t == null )
334
+ return Array . Empty < Type > ( ) ;
335
+
336
+ // NOTE: self-emit generator can have other target.
337
+ var ret = USGEngine . GeneratorInfoList
338
+ . Where ( x => x . Attribute . GeneratorClass == t )
339
+ . Select ( static x => x . TargetClass )
298
340
. ToArray ( ) ;
341
+
342
+ if ( ret . Length == 1 && ret [ 0 ] == t )
343
+ return Array . Empty < Type > ( ) ;
344
+
345
+ return ret ;
299
346
}
300
347
301
348
0 commit comments