123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482 |
- 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 / listView.itemHeight);
- 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.itemHeight = 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_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_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 / m_EnvironmentList.itemHeight);
- 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;
- }
- }
- }
- 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 / m_EnvironmentList.itemHeight,
- 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)
- {
- //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();
- }
- }
- }
|