-
Notifications
You must be signed in to change notification settings - Fork 870
Expand file tree
/
Copy pathDisplayWindow.EnvironmentLibrarySidePanel.cs
More file actions
494 lines (442 loc) · 21.9 KB
/
DisplayWindow.EnvironmentLibrarySidePanel.cs
File metadata and controls
494 lines (442 loc) · 21.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
using System;
using System.Collections.Generic;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.Rendering.LookDev
{
/// <summary>Interface that must implement the EnvironmentLibrary view to communicate with the data management</summary>
public interface IEnvironmentDisplayer
{
/// <summary>Repaint the UI</summary>
void Repaint();
/// <summary>Callback on Environment change in the Library</summary>
event Action<EnvironmentLibrary> OnChangingEnvironmentLibrary;
}
partial class DisplayWindow : IEnvironmentDisplayer
{
static partial class Style
{
internal static readonly Texture2D k_AddIcon = CoreEditorUtils.LoadIcon(Style.k_IconFolder, "Add", forceLowRes: true);
internal static readonly Texture2D k_RemoveIcon = CoreEditorUtils.LoadIcon(Style.k_IconFolder, "Remove", forceLowRes: true);
internal static readonly Texture2D k_DuplicateIcon = CoreEditorUtils.LoadIcon(Style.k_IconFolder, "Duplicate", forceLowRes: true);
internal const string k_DragAndDropLibrary = "Drag and drop EnvironmentLibrary here";
}
VisualElement m_EnvironmentContainer;
ListView m_EnvironmentList;
EnvironmentElement m_EnvironmentInspector;
UIElements.Toolbar m_EnvironmentListToolbar;
UIElements.ObjectField m_LibraryField;
//event Action<UnityEngine.Object> OnAddingEnvironmentInternal;
//event Action<UnityEngine.Object> IEnvironmentDisplayer.OnAddingEnvironment
//{
// add => OnAddingEnvironmentInternal += value;
// remove => OnAddingEnvironmentInternal -= value;
//}
//event Action<int> OnRemovingEnvironmentInternal;
//event Action<int> IEnvironmentDisplayer.OnRemovingEnvironment
//{
// add => OnRemovingEnvironmentInternal += value;
// remove => OnRemovingEnvironmentInternal -= value;
//}
event Action<EnvironmentLibrary> OnChangingEnvironmentLibraryInternal;
event Action<EnvironmentLibrary> IEnvironmentDisplayer.OnChangingEnvironmentLibrary
{
add => OnChangingEnvironmentLibraryInternal += value;
remove => OnChangingEnvironmentLibraryInternal -= value;
}
static int FirstVisibleIndex(ListView listView)
=> (int)(listView.Q<ScrollView>().scrollOffset.y / (int)listView.fixedItemHeight);
void CreateEnvironment()
{
if (m_MainContainer == null || m_MainContainer.Equals(null))
throw new System.MemberAccessException("m_MainContainer should be assigned prior CreateEnvironment()");
m_EnvironmentContainer = new VisualElement() { name = Style.k_EnvironmentContainerName };
m_MainContainer.Add(m_EnvironmentContainer);
if (sidePanel == SidePanel.Environment)
m_MainContainer.AddToClassList(Style.k_ShowEnvironmentPanelClass);
m_EnvironmentInspector = new EnvironmentElement(withPreview: false, () =>
{
LookDev.SaveContextChangeAndApply(ViewIndex.First);
LookDev.SaveContextChangeAndApply(ViewIndex.Second);
});
m_EnvironmentList = new ListView();
m_EnvironmentList.AddToClassList("list-environment");
m_EnvironmentList.selectionType = SelectionType.Single;
m_EnvironmentList.fixedItemHeight = EnvironmentElement.k_SkyThumbnailHeight;
m_EnvironmentList.makeItem = () =>
{
var preview = new Image();
preview.AddManipulator(new EnvironmentPreviewDragger(this, m_ViewContainer));
return preview;
};
m_EnvironmentList.bindItem = (e, i) =>
{
if (LookDev.currentContext.environmentLibrary == null)
return;
(e as Image).image = EnvironmentElement.GetLatLongThumbnailTexture(
LookDev.currentContext.environmentLibrary[i],
EnvironmentElement.k_SkyThumbnailWidth);
};
#if UNITY_2022_2_OR_NEWER
m_EnvironmentList.selectionChanged += objects =>
{
bool empty = !objects.GetEnumerator().MoveNext();
if (empty || (LookDev.currentContext.environmentLibrary?.Count ?? 0) == 0)
#elif UNITY_2020_1_OR_NEWER
m_EnvironmentList.onSelectionChange += objects =>
{
bool empty = !objects.GetEnumerator().MoveNext();
if (empty || (LookDev.currentContext.environmentLibrary?.Count ?? 0) == 0)
#else
m_EnvironmentList.onSelectionChanged += objects =>
{
if (objects.Count == 0 || (LookDev.currentContext.environmentLibrary?.Count ?? 0) == 0)
#endif
{
m_EnvironmentInspector.style.visibility = Visibility.Hidden;
m_EnvironmentInspector.style.height = 0;
}
else
{
m_EnvironmentInspector.style.visibility = Visibility.Visible;
m_EnvironmentInspector.style.height = new StyleLength(StyleKeyword.Auto);
int firstVisibleIndex = FirstVisibleIndex(m_EnvironmentList);
Environment environment = LookDev.currentContext.environmentLibrary[m_EnvironmentList.selectedIndex];
var container = m_EnvironmentList.Q("unity-content-container");
if (m_EnvironmentList.selectedIndex - firstVisibleIndex >= container.childCount || m_EnvironmentList.selectedIndex < firstVisibleIndex)
{
m_EnvironmentList.ScrollToItem(m_EnvironmentList.selectedIndex);
firstVisibleIndex = FirstVisibleIndex(m_EnvironmentList);
}
Image deportedLatLong = container[m_EnvironmentList.selectedIndex - firstVisibleIndex] as Image;
m_EnvironmentInspector.Bind(environment, deportedLatLong);
}
};
#if UNITY_2022_2_OR_NEWER
m_EnvironmentList.itemsChosen += objCollection =>
{
foreach (var obj in objCollection)
EditorGUIUtility.PingObject(LookDev.currentContext.environmentLibrary ? [(int)obj]);
};
#elif UNITY_2020_1_OR_NEWER
m_EnvironmentList.onItemsChosen += objCollection =>
{
foreach (var obj in objCollection)
EditorGUIUtility.PingObject(LookDev.currentContext.environmentLibrary ? [(int)obj]);
};
#else
m_EnvironmentList.onItemChosen += obj =>
EditorGUIUtility.PingObject(LookDev.currentContext.environmentLibrary?[(int)obj]);
#endif
m_NoEnvironmentList = new Label(Style.k_DragAndDropLibrary);
m_NoEnvironmentList.style.flexGrow = 1;
m_NoEnvironmentList.style.unityTextAlign = TextAnchor.MiddleCenter;
m_EnvironmentContainer.Add(m_EnvironmentInspector);
m_EnvironmentListToolbar = new UIElements.Toolbar();
ToolbarButton addEnvironment = new ToolbarButton(() =>
{
if (LookDev.currentContext.environmentLibrary == null)
return;
LookDev.currentContext.environmentLibrary.Add();
RefreshLibraryDisplay();
m_EnvironmentList.ScrollToItem(-1); //-1: scroll to end
m_EnvironmentList.selectedIndex = LookDev.currentContext.environmentLibrary.Count - 1;
ScrollToEnd();
})
{
name = "add",
tooltip = "Add new empty environment"
};
addEnvironment.Add(new Image() { image = Style.k_AddIcon });
ToolbarButton removeEnvironment = new ToolbarButton(() =>
{
if (m_EnvironmentList.selectedIndex == -1 || LookDev.currentContext.environmentLibrary == null)
return;
LookDev.currentContext.environmentLibrary?.Remove(m_EnvironmentList.selectedIndex);
RefreshLibraryDisplay();
m_EnvironmentList.selectedIndex = -1;
})
{
name = "remove",
tooltip = "Remove environment currently selected"
};
removeEnvironment.Add(new Image() { image = Style.k_RemoveIcon });
ToolbarButton duplicateEnvironment = new ToolbarButton(() =>
{
if (m_EnvironmentList.selectedIndex == -1 || LookDev.currentContext.environmentLibrary == null)
return;
LookDev.currentContext.environmentLibrary.Duplicate(m_EnvironmentList.selectedIndex);
RefreshLibraryDisplay();
m_EnvironmentList.ScrollToItem(-1); //-1: scroll to end
m_EnvironmentList.selectedIndex = LookDev.currentContext.environmentLibrary.Count - 1;
ScrollToEnd();
})
{
name = "duplicate",
tooltip = "Duplicate environment currently selected"
};
duplicateEnvironment.Add(new Image() { image = Style.k_DuplicateIcon });
m_EnvironmentListToolbar.Add(addEnvironment);
m_EnvironmentListToolbar.Add(removeEnvironment);
m_EnvironmentListToolbar.Add(duplicateEnvironment);
m_EnvironmentListToolbar.AddToClassList("list-environment-overlay");
var m_EnvironmentInspectorSeparator = new VisualElement() { name = "separator-line" };
m_EnvironmentInspectorSeparator.Add(new VisualElement() { name = "separator" });
m_EnvironmentContainer.Add(m_EnvironmentInspectorSeparator);
VisualElement listContainer = new VisualElement();
listContainer.AddToClassList("list-environment");
listContainer.Add(m_EnvironmentList);
listContainer.Add(m_EnvironmentListToolbar);
m_LibraryField = new ObjectField("Library")
{
tooltip = "The currently used library"
};
m_LibraryField.allowSceneObjects = false;
m_LibraryField.objectType = typeof(EnvironmentLibrary);
m_LibraryField.SetValueWithoutNotify(LookDev.currentContext.environmentLibrary);
m_LibraryField.RegisterValueChangedCallback(evt =>
{
m_EnvironmentList.selectedIndex = -1;
OnChangingEnvironmentLibraryInternal?.Invoke(evt.newValue as EnvironmentLibrary);
RefreshLibraryDisplay();
});
var environmentListCreationToolbar = new UIElements.Toolbar()
{
name = "environmentListCreationToolbar"
};
environmentListCreationToolbar.Add(m_LibraryField);
environmentListCreationToolbar.Add(new ToolbarButton(()
=> EnvironmentLibraryCreator.CreateAndAssignTo(m_LibraryField))
{
text = "New",
tooltip = "Create a new EnvironmentLibrary"
});
m_EnvironmentContainer.Add(listContainer);
m_EnvironmentContainer.Add(m_NoEnvironmentList);
m_EnvironmentContainer.Add(environmentListCreationToolbar);
//add ability to unselect
m_EnvironmentList.RegisterCallback<MouseDownEvent>(evt =>
{
var clickedIndex = (int)(evt.localMousePosition.y / (int)m_EnvironmentList.fixedItemHeight);
if (clickedIndex >= m_EnvironmentList.itemsSource.Count)
{
m_EnvironmentList.selectedIndex = -1;
evt.StopPropagation();
}
});
RefreshLibraryDisplay();
}
//necessary as the scrollview need to be updated which take some editor frames.
void ScrollToEnd(int attemptRemaining = 5)
{
m_EnvironmentList.ScrollToItem(-1); //-1: scroll to end
if (attemptRemaining > 0)
EditorApplication.delayCall += () => ScrollToEnd(--attemptRemaining);
}
void RefreshLibraryDisplay()
{
if (m_LibraryField != null)
m_LibraryField.SetValueWithoutNotify(LookDev.currentContext.environmentLibrary);
if (m_EnvironmentInspector != null && m_EnvironmentList != null)
{
int itemMax = LookDev.currentContext.environmentLibrary?.Count ?? 0;
if (itemMax == 0 || m_EnvironmentList.selectedIndex == -1)
{
m_EnvironmentInspector.style.visibility = Visibility.Hidden;
m_EnvironmentInspector.style.height = 0;
}
else
{
m_EnvironmentInspector.style.visibility = Visibility.Visible;
m_EnvironmentInspector.style.height = new StyleLength(StyleKeyword.Auto);
}
var items = new List<int>(itemMax);
for (int i = 0; i < itemMax; i++)
items.Add(i);
m_EnvironmentList.itemsSource = items;
if (LookDev.currentContext.environmentLibrary == null)
{
m_EnvironmentList
.Q(className: "unity-scroll-view__vertical-scroller")
.Q("unity-dragger")
.style.visibility = Visibility.Hidden;
m_EnvironmentListToolbar.style.visibility = Visibility.Hidden;
m_NoEnvironmentList.style.display = DisplayStyle.Flex;
}
else
{
m_EnvironmentList
.Q(className: "unity-scroll-view__vertical-scroller")
.Q("unity-dragger")
.style.visibility = itemMax == 0
? Visibility.Hidden
: Visibility.Visible;
m_EnvironmentListToolbar.style.visibility = Visibility.Visible;
m_NoEnvironmentList.style.display = DisplayStyle.None;
}
m_EnvironmentList.RefreshItems();
}
}
DraggingContext StartDragging(VisualElement item, Vector2 worldPosition)
=> new DraggingContext(
rootVisualElement,
item as Image,
//note: this even can come before the selection event of the
//ListView. Reconstruct index by looking at target of the event.
(int)item.layout.y / (int)m_EnvironmentList.fixedItemHeight,
worldPosition);
void EndDragging(DraggingContext context, Vector2 mouseWorldPosition)
{
Environment environment = LookDev.currentContext.environmentLibrary?[context.draggedIndex];
if (environment == null)
return;
if (m_Views[(int)ViewIndex.First].ContainsPoint(mouseWorldPosition))
{
if (viewLayout == Layout.CustomSplit)
OnChangingEnvironmentInViewInternal?.Invoke(environment, ViewCompositionIndex.Composite, mouseWorldPosition);
else
OnChangingEnvironmentInViewInternal?.Invoke(environment, ViewCompositionIndex.First, mouseWorldPosition);
m_NoEnvironment1.style.visibility = environment == null || environment.Equals(null) ? Visibility.Visible : Visibility.Hidden;
}
else
{
OnChangingEnvironmentInViewInternal?.Invoke(environment, ViewCompositionIndex.Second, mouseWorldPosition);
m_NoEnvironment2.style.visibility = environment == null || environment.Equals(null) ? Visibility.Visible : Visibility.Hidden;
}
}
class DraggingContext : IDisposable
{
const string k_CursorFollowerName = "cursorFollower";
public readonly int draggedIndex;
readonly Image cursorFollower;
readonly Vector2 cursorOffset;
readonly VisualElement windowContent;
public DraggingContext(VisualElement windowContent, Image draggedElement, int draggedIndex, Vector2 worldPosition)
{
this.windowContent = windowContent;
this.draggedIndex = draggedIndex;
cursorFollower = new Image()
{
name = k_CursorFollowerName,
image = draggedElement.image
};
cursorFollower.tintColor = new Color(1f, 1f, 1f, .5f);
windowContent.Add(cursorFollower);
cursorOffset = draggedElement.WorldToLocal(worldPosition);
cursorFollower.style.position = Position.Absolute;
UpdateCursorFollower(worldPosition);
}
public void UpdateCursorFollower(Vector2 mouseWorldPosition)
{
Vector2 windowLocalPosition = windowContent.WorldToLocal(mouseWorldPosition);
cursorFollower.style.left = windowLocalPosition.x - cursorOffset.x;
cursorFollower.style.top = windowLocalPosition.y - cursorOffset.y;
}
public void Dispose()
{
if (windowContent.Contains(cursorFollower))
windowContent.Remove(cursorFollower);
}
}
class EnvironmentPreviewDragger : Manipulator
{
VisualElement m_DropArea;
DisplayWindow m_Window;
//Note: static as only one drag'n'drop at a time
static DraggingContext s_Context;
public EnvironmentPreviewDragger(DisplayWindow window, VisualElement dropArea)
{
m_Window = window;
m_DropArea = dropArea;
}
protected override void RegisterCallbacksOnTarget()
{
target.RegisterCallback<MouseDownEvent>(OnMouseDown);
target.RegisterCallback<MouseUpEvent>(OnMouseUp);
}
protected override void UnregisterCallbacksFromTarget()
{
target.UnregisterCallback<MouseDownEvent>(OnMouseDown);
target.UnregisterCallback<MouseUpEvent>(OnMouseUp);
}
void Release()
{
target.UnregisterCallback<MouseMoveEvent>(OnMouseMove);
s_Context?.Dispose();
target.ReleaseMouse();
s_Context = null;
}
void OnMouseDown(MouseDownEvent evt)
{
if (evt.button == 0)
{
target.CaptureMouse();
target.RegisterCallback<MouseMoveEvent>(OnMouseMove);
s_Context = m_Window.StartDragging(target, evt.mousePosition);
//do not stop event as we still need to propagate it to the ListView for selection
}
}
void OnMouseUp(MouseUpEvent evt)
{
if (evt.button != 0)
return;
if (m_DropArea.ContainsPoint(m_DropArea.WorldToLocal(Event.current.mousePosition)))
{
m_Window.EndDragging(s_Context, evt.mousePosition);
evt.StopPropagation();
}
Release();
}
void OnMouseMove(MouseMoveEvent evt)
{
evt.StopPropagation();
s_Context.UpdateCursorFollower(evt.mousePosition);
}
}
void IEnvironmentDisplayer.Repaint()
{
//can be unsync if library asset is destroy by user, so if null force sync
if (LookDev.currentContext.environmentLibrary == null)
m_LibraryField.value = null;
RefreshLibraryDisplay();
}
void OnFocus()
{
//OnFocus is called before OnEnable that open backend if not already opened, so only sync if backend is open
if (LookDev.open && LookDev.currentContext != null)
{
//If EnvironmentLibrary asset as been edited by the user (deletion),
//update all view to use null environment if it was not temporary ones
if (LookDev.currentContext.HasLibraryAssetChanged(m_LibraryField.value as EnvironmentLibrary))
{
ViewContext viewContext = LookDev.currentContext.GetViewContent(ViewIndex.First);
if (!(viewContext.environment?.isCubemapOnly ?? false))
OnChangingEnvironmentInViewInternal?.Invoke(viewContext.environment, ViewCompositionIndex.First, default);
viewContext = LookDev.currentContext.GetViewContent(ViewIndex.Second);
if (!(viewContext.environment?.isCubemapOnly ?? false))
OnChangingEnvironmentInViewInternal?.Invoke(viewContext.environment, ViewCompositionIndex.Second, default);
}
//If Cubemap asset as been edited by the user (deletion),
//update all views to use null environment if it was temporary ones
//and update all other views' environment to not use cubemap anymore
foreach (ViewContext viewContext in LookDev.currentContext.viewContexts)
{
if (viewContext.environment == null || !viewContext.environment.HasCubemapAssetChanged(viewContext.environment.cubemap))
continue;
if (viewContext.environment.isCubemapOnly)
viewContext.UpdateEnvironment(null);
else
viewContext.environment.cubemap = null;
}
((IEnvironmentDisplayer)this).Repaint();
}
}
void FullRefreshEnvironmentList()
{
if (LookDev.currentContext.environmentLibrary != null)
LookDev.currentContext.FullReimportEnvironmentLibrary();
((IEnvironmentDisplayer)this).Repaint();
}
}
}