Skip to content

Commit d7fb00d

Browse files
CianNoonanUnityEvergreen
authored andcommitted
Selection History
1 parent 617dafe commit d7fb00d

7 files changed

Lines changed: 326 additions & 18 deletions

File tree

Packages/com.unity.shadergraph/Editor/Drawing/Blackboard/SGBlackboard.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,5 +623,10 @@ public override void Dispose()
623623
m_ScrollBoundaryTop = null;
624624
m_PathLabelTextField = null;
625625
}
626+
627+
internal void ScrollToItem(VisualElement ve)
628+
{
629+
m_ScrollView.ScrollTo(ve);
630+
}
626631
}
627632
}

Packages/com.unity.shadergraph/Editor/Drawing/Views/GraphEditorView.cs

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.IO;
43
using System.Linq;
54
using UnityEngine;
5+
using UnityEditor;
66
using UnityEditor.Graphing;
77
using UnityEditor.Graphing.Util;
88
using UnityEditor.ShaderGraph.Drawing.Inspector;
@@ -523,13 +523,120 @@ void CreateMasterPreview()
523523
m_MasterPreviewView.onResized += UpdateSerializedWindowLayout;
524524
}
525525

526+
const string kSelectionKey = "Unity.ShaderGraphHistory";
527+
526528
void CreateInspector()
527529
{
528530
var inspectorViewModel = new InspectorViewModel() { parentView = this.graphView };
529531
m_InspectorView = new InspectorView(inspectorViewModel);
530532
graphView.OnSelectionChange += m_InspectorView.TriggerInspectorUpdate;
531533
// Undo/redo actions that only affect selection don't trigger the above callback for some reason, so we also have to do this
532534
Undo.undoRedoPerformed += (() => { m_InspectorView?.TriggerInspectorUpdate(graphView?.selection); });
535+
536+
graphView.OnSelectionChange += RecordSelectionHistory;
537+
Selection.RegisterCustomHandler(kSelectionKey, CustomSelectionHandler, CustomValidator);
538+
}
539+
540+
static bool CustomValidator(string data, EditorWindow sourceWindow)
541+
{
542+
if (sourceWindow == null || sourceWindow is not MaterialGraphEditWindow graphWindow) return false;
543+
544+
var graphView = graphWindow.graphEditorView?.m_GraphView;
545+
if (graphView == null) return false;
546+
547+
var info = GraphSelection.FromJson(data);
548+
if (info == null) return false;
549+
550+
foreach (var id in info.elements)
551+
{
552+
if (graphView.GetElementByGuid(id) != null) return true;
553+
}
554+
555+
return false;
556+
}
557+
558+
bool m_ApplyingCustomSelection;
559+
static void CustomSelectionHandler(string data, EntityId[] _)
560+
{
561+
var info = GraphSelection.FromJson(data);
562+
if (info == null) return;
563+
564+
var window = EditorWindow.focusedWindow as MaterialGraphEditWindow;
565+
var graphEditorView = window?.graphEditorView;
566+
var graphView = graphEditorView?.m_GraphView;
567+
if (graphView == null) return;
568+
569+
var blackboard = window.graphEditorView.blackboardController?.blackboard;
570+
var fields = ListPool<SGBlackboardField>.Get();
571+
foreach (var id in info.elements)
572+
{
573+
var e = graphView.GetElementByGuid(id);
574+
if (e is SGBlackboardField field)
575+
{
576+
blackboard?.ScrollToItem(field);
577+
fields.Add(field);
578+
}
579+
}
580+
581+
if (fields.Count > 0)
582+
{
583+
EditorApplication.delayCall += () =>
584+
{
585+
try
586+
{
587+
graphEditorView.m_ApplyingCustomSelection = true;
588+
// info.ApplyToGraphView may have added this element to selection, before our delayCall executes, avoid duplication
589+
foreach(var e in fields)
590+
{
591+
if (e != null && !graphView.selection.Contains(e)) graphView.AddToSelectionNoUndoRecord(e);
592+
}
593+
594+
ListPool<SGBlackboardField>.Release(fields);
595+
}
596+
finally
597+
{
598+
graphEditorView.m_ApplyingCustomSelection = false;
599+
}
600+
};
601+
}
602+
else
603+
{
604+
ListPool<SGBlackboardField>.Release(fields);
605+
}
606+
607+
try
608+
{
609+
graphEditorView.m_ApplyingCustomSelection = true;
610+
info.ApplyToGraphView(graphView, null);
611+
window.graphEditorView.m_InspectorView.TriggerInspectorUpdate(graphView.selection);
612+
}
613+
finally
614+
{
615+
graphEditorView.m_ApplyingCustomSelection = false;
616+
}
617+
}
618+
619+
void RecordSelectionHistory(IEnumerable<ISelectable> selectionList)
620+
{
621+
if (m_ApplyingCustomSelection || m_GraphView == null || m_GraphView.graph == null)
622+
return;
623+
var info = new GraphSelection();
624+
foreach (var sel in selectionList)
625+
{
626+
if (sel is not GraphElement e)
627+
continue;
628+
// In some cases (e.g. window is being hidden), elements are removed from selection,
629+
// but selection changed callback is invoked with the old selection set. The elements
630+
// themselves are un-selected already though. Skip over those.
631+
if (!e.selected)
632+
continue;
633+
info.elements.Add(e.viewDataKey);
634+
}
635+
636+
if (info.isEmpty)
637+
return;
638+
639+
Selection.SetCustomSelection(kSelectionKey, EditorJsonUtility.ToJson(info));
533640
}
534641

535642
// a nice curve that scales well for various HID (touchpad and mice).

Packages/com.unity.shadergraph/Editor/Drawing/Views/MaterialGraphView.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ public override void AddToSelection(ISelectable selectable)
535535
}
536536

537537
// Replicating these private GraphView functions as we need them for our own purposes
538-
internal void AddToSelectionNoUndoRecord(GraphElement graphElement)
538+
internal new void AddToSelectionNoUndoRecord(GraphElement graphElement)
539539
{
540540
graphElement.selected = true;
541541
selection.Add(graphElement);
@@ -584,7 +584,7 @@ public override void ClearSelection()
584584
OnSelectionChange?.Invoke(selection);
585585
}
586586

587-
internal bool ClearSelectionNoUndoRecord()
587+
internal new bool ClearSelectionNoUndoRecord()
588588
{
589589
foreach (var graphElement in selection.OfType<GraphElement>())
590590
{

Packages/com.unity.visualeffectgraph/Editor/GraphView/Blackboard/VFXBlackboard.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,6 @@ private void OnSelectionChanged(IEnumerable<object> selectedItems)
374374
}
375375
}
376376
}
377-
378377
private DragVisualMode OnHandleDrop(HandleDragAndDropArgs arg)
379378
{
380379
if (arg.parentId < 0)
@@ -1562,5 +1561,11 @@ private string FilterOutReservedCategoryName(string category)
15621561

15631562
return category;
15641563
}
1564+
1565+
internal void ScrollToItem(string itemName)
1566+
{
1567+
var treeviewItem = m_ParametersController.SelectMany(GetDataRecursive).Single(x => string.Compare(x.data.title, itemName, StringComparison.OrdinalIgnoreCase) == 0);
1568+
m_Treeview.ScrollToItemById(treeviewItem.id);
1569+
}
15651570
}
15661571
}

Packages/com.unity.visualeffectgraph/Editor/GraphView/Views/VFXView.cs

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Buffers;
23
using System.Collections;
34
using System.Collections.ObjectModel;
45
using System.Collections.Generic;
@@ -16,7 +17,9 @@
1617
using UnityEngine.VFX;
1718
using UnityEngine.UIElements;
1819
using UnityEditor.UIElements;
20+
using UnityEngine.Pool;
1921
using UnityEngine.Profiling;
22+
using Object = UnityEngine.Object;
2023
using PositionType = UnityEngine.UIElements.Position;
2124
using Task = UnityEditor.VersionControl.Task;
2225

@@ -221,6 +224,8 @@ void DisconnectController(VFXViewController previousController)
221224
OnFocus();
222225
}
223226

227+
const string kSelectionKey = "Unity.VisualEffectGraphHistory";
228+
224229
void ConnectController()
225230
{
226231
schedule.Execute(() =>
@@ -253,6 +258,49 @@ void ConnectController()
253258
}
254259

255260
SceneView.duringSceneGui += OnSceneGUI;
261+
Selection.RegisterCustomHandler(kSelectionKey, CustomSelectionHandler);
262+
}
263+
264+
static void CustomSelectionHandler(string data, EntityId[] _)
265+
{
266+
var info = GraphSelection.FromJson(data);
267+
if (info == null) return;
268+
269+
var window = EditorWindow.focusedWindow as VFXViewWindow;
270+
var graphView = window?.graphView;
271+
if (graphView?.controller == null) return;
272+
273+
var blackboard = graphView.blackboard;
274+
var elements = ListPool<GraphElement>.Get();
275+
foreach (var id in info.elements)
276+
{
277+
var e = graphView.GetElementByGuid(id);
278+
if (e is VFXBlackboardField || e is VFXBlackboardAttributeField)
279+
{
280+
var tokens = id.Split(':', StringSplitOptions.RemoveEmptyEntries);
281+
blackboard.ScrollToItem(tokens.Length == 1 ? tokens[0] : tokens[1]);
282+
elements.Add(e);
283+
}
284+
}
285+
286+
if (elements.Count > 0)
287+
{
288+
EditorApplication.delayCall += () =>
289+
{
290+
// info.ApplyToGraphView may have added this element to selection, before our delayCall executes, avoid duplication
291+
foreach (var e in elements)
292+
{
293+
if (e != null && !graphView.selection.Contains(e)) graphView.AddToSelectionNoUndoRecord(e);
294+
}
295+
ListPool<GraphElement>.Release(elements);
296+
};
297+
}
298+
else
299+
{
300+
ListPool<GraphElement>.Release(elements);
301+
}
302+
303+
info.ApplyToGraphView(graphView, graphView.blackboard);
256304
}
257305

258306
IEnumerable<Type> GetAcceptedTypeNodes()
@@ -509,7 +557,7 @@ public static VisualTreeAsset LoadUXML(string text)
509557

510558
public static Texture2D LoadImage(string text)
511559
{
512-
string path = string.Format("{0}/VFX/{1}.png", VisualEffectAssetEditorUtility.editorResourcesPath, text);
560+
string path = $"{VisualEffectAssetEditorUtility.editorResourcesPath}/VFX/{text}.png";
513561
return EditorGUIUtility.LoadIcon(path);
514562
}
515563

@@ -2087,38 +2135,50 @@ public void UpdateGlobalSelection()
20872135
{
20882136
if (controller == null) return;
20892137

2090-
var objectsSelected = new List<UnityEngine.Object>();
2138+
using var _ = ListPool<EntityId>.Get(out var objectsSelected);
2139+
var sel = new GraphSelection();
20912140
var emptyBlackboardSelection = false;
20922141
foreach (var element in selection)
20932142
{
20942143
switch (element)
20952144
{
20962145
case VFXNodeUI nodeUI:
2097-
if (nodeUI.controller.model != null)
2146+
var nodeModel = nodeUI.controller.model;
2147+
if (nodeModel != null)
20982148
{
2099-
objectsSelected.Add(nodeUI.controller.model);
2149+
objectsSelected.Add(nodeModel.GetEntityId());
2150+
sel.elements.Add(nodeUI.viewDataKey);
21002151
emptyBlackboardSelection = true;
21012152
}
21022153
break;
21032154
case VFXBlackboardField blackboardField:
2104-
if (blackboardField.controller.model != null)
2155+
var blackboardModel = blackboardField.controller.model;
2156+
if (blackboardModel != null)
21052157
{
2106-
objectsSelected.Add(blackboardField.controller.model);
2158+
objectsSelected.Add(blackboardModel.GetEntityId());
2159+
sel.elements.Add(blackboardField.viewDataKey);
21072160
}
21082161
break;
2109-
case VFXBlackboardAttributeField aField:
2110-
var attributeField = aField;
2162+
case VFXBlackboardAttributeField attributeField:
21112163
var customAttribute = controller.graph.customAttributes.SingleOrDefault(x => string.Compare(attributeField.text, x.attributeName, StringComparison.OrdinalIgnoreCase) == 0);
2112-
objectsSelected.Add(customAttribute);
2113-
break;
2114-
case VFXBlackboardCategory category:
2164+
if (customAttribute != null) objectsSelected.Add(customAttribute.GetEntityId());
2165+
sel.elements.Add(attributeField.viewDataKey);
21152166
break;
21162167
}
21172168
}
21182169

2119-
if (objectsSelected.Count > 0)
2170+
if (sel.elements.Count > 0)
21202171
{
2121-
Selection.objects = objectsSelected.ToArray();
2172+
var rentedArray = ArrayPool<EntityId>.Shared.Rent(objectsSelected.Count);
2173+
try
2174+
{
2175+
objectsSelected.CopyTo(rentedArray, 0);
2176+
Selection.SetCustomSelection(kSelectionKey, EditorJsonUtility.ToJson(sel), rentedArray);
2177+
}
2178+
finally
2179+
{
2180+
ArrayPool<EntityId>.Shared.Return(rentedArray, clearArray: false);
2181+
}
21222182
if (emptyBlackboardSelection)
21232183
{
21242184
blackboard.EmptySelection();

0 commit comments

Comments
 (0)