Skip to content

Commit a8889d1

Browse files
committed
[selection] Handle selection history in Shader Graph and VFX Graph
1 parent 7467ed4 commit a8889d1

File tree

4 files changed

+129
-27
lines changed

4 files changed

+129
-27
lines changed

com.unity.shadergraph/Editor/Drawing/MaterialGraphEditWindow.cs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -487,20 +487,19 @@ public void UpdateTitle()
487487
title = title + " (deleted)";
488488
}
489489

490-
// get window icon
491490
bool isSubGraph = graphObject?.graph?.isSubGraph ?? false;
492-
Texture2D icon;
493-
{
494-
string theme = EditorGUIUtility.isProSkin ? "_dark" : "_light";
495-
if (isSubGraph)
496-
icon = Resources.Load<Texture2D>("Icons/sg_subgraph_icon_gray" + theme);
497-
else
498-
icon = Resources.Load<Texture2D>("Icons/sg_graph_icon_gray" + theme);
499-
}
500-
491+
Texture2D icon = LoadWindowIcon(isSubGraph);
501492
titleContent = new GUIContent(title, icon);
502493
}
503494

495+
internal static Texture2D LoadWindowIcon(bool isSubGraph)
496+
{
497+
var theme = EditorGUIUtility.isProSkin ? "dark" : "light";
498+
var kind = isSubGraph ? "subgraph" : "graph";
499+
var path = $"Icons/sg_{kind}_icon_gray_{theme}";
500+
return Resources.Load<Texture2D>(path);
501+
}
502+
504503
void OnDestroy()
505504
{
506505
// Prompting the user if they want to close is mostly handled via the EditorWindow's system (hasUnsavedChanges).

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

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.IO;
43
using System.Linq;
54
using UnityEngine;
65
using UnityEditor.Graphing;
@@ -415,13 +414,75 @@ void CreateMasterPreview()
415414
m_MasterPreviewView.previewResizeBorderFrame.OnResizeFinished += UpdateSerializedWindowLayout;
416415
}
417416

417+
const string kSelectionKey = "Unity.ShaderGraphHistory";
418+
418419
void CreateInspector()
419420
{
420421
var inspectorViewModel = new InspectorViewModel() { parentView = this.graphView };
421422
m_InspectorView = new InspectorView(inspectorViewModel);
422423
graphView.OnSelectionChange += m_InspectorView.TriggerInspectorUpdate;
423424
// Undo/redo actions that only affect selection don't trigger the above callback for some reason, so we also have to do this
424425
Undo.undoRedoPerformed += (() => { m_InspectorView?.TriggerInspectorUpdate(graphView?.selection); });
426+
427+
graphView.OnSelectionChange += RecordSelectionHistory;
428+
Selection.RegisterCustomHandler(kSelectionKey, CustomSelectionHandler, MaterialGraphEditWindow.LoadWindowIcon(false));
429+
}
430+
431+
static bool s_ApplyingSelection;
432+
static void CustomSelectionHandler(string data, Object active, Object[] selected)
433+
{
434+
var info = GraphSelection.FromJson(data);
435+
if (info == null)
436+
return;
437+
438+
var window = EditorWindow.focusedWindow as MaterialGraphEditWindow;
439+
var gv = window?.graphEditorView?.m_GraphView;
440+
if (gv == null)
441+
return;
442+
443+
// apply selection to that graph view
444+
s_ApplyingSelection = true;
445+
info.ApplyToGraphView(gv, null);
446+
window.graphEditorView.m_InspectorView.TriggerInspectorUpdate(gv.selection);
447+
s_ApplyingSelection = false;
448+
}
449+
450+
void RecordSelectionHistory(IEnumerable<ISelectable> selectionList)
451+
{
452+
if (s_ApplyingSelection || m_GraphView == null || m_GraphView.graph == null)
453+
return;
454+
var info = new GraphSelection();
455+
var selNames = new List<string>();
456+
var numEdges = 0;
457+
foreach (var sel in selectionList)
458+
{
459+
if (sel is not GraphElement e)
460+
continue;
461+
// In some cases (e.g. window is being hidden), elements are removed from selection,
462+
// but selection changed callback is invoked with the old selection set. The elements
463+
// themselves are un-selected already though. Skip over those.
464+
if (!e.selected)
465+
continue;
466+
info.elements.Add(e.viewDataKey);
467+
// Figure out a suitable string name to show in history UI
468+
if (e is Node node)
469+
selNames.Add(node is IShaderNodeView nv ? nv.node.name : node.GetType().Name);
470+
else if (e is SGBlackboardField field)
471+
selNames.Add(field.text);
472+
else if (e is StickyNote sn)
473+
selNames.Add(sn.title);
474+
else if (e is Edge)
475+
++numEdges;
476+
}
477+
if (info.empty)
478+
return;
479+
480+
if (selNames.Count > 3) selNames = selNames.Take(3).Append("...").ToList();
481+
if (numEdges > 0)
482+
selNames.Add($"{numEdges} edges");
483+
484+
var label = string.Join(", ", selNames);
485+
Selection.SetCustomSelection(kSelectionKey, label, EditorJsonUtility.ToJson(info));
425486
}
426487

427488
void OnKeyDown(KeyDownEvent evt)

com.unity.visualeffectgraph/Editor/GraphView/Views/VFXAttachPanel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ void UpdateAttachedLabel()
8484
{
8585
m_VFXIcon.style.display = DisplayStyle.Flex;
8686
m_pickedObjectLabel[0].style.paddingLeft = 18;
87-
m_VFXIcon.style.backgroundImage = VFXView.LoadImage(EditorGUIUtility.isProSkin ? "vfx_graph_icon_gray_dark" : "vfx_graph_icon_gray_light");
87+
m_VFXIcon.style.backgroundImage = VFXView.LoadWindowIcon();
8888
}
8989
else
9090
{

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

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.IO;
66
using System.Linq;
77
using System.Reflection;
8-
98
using UnityEditor.Experimental;
109

1110
using UnityEditor.Experimental.GraphView;
@@ -17,7 +16,7 @@
1716
using UnityEngine.UIElements;
1817
using UnityEditor.UIElements;
1918
using UnityEngine.Profiling;
20-
19+
using Object = UnityEngine.Object;
2120
using PositionType = UnityEngine.UIElements.Position;
2221
using Task = UnityEditor.VersionControl.Task;
2322

@@ -271,6 +270,8 @@ void DisconnectController(VFXViewController previousController)
271270
SceneView.duringSceneGui -= OnSceneGUI;
272271
}
273272

273+
const string kSelectionKey = "Unity.VisualEffectGraphHistory";
274+
274275
void ConnectController()
275276
{
276277
schedule.Execute(() =>
@@ -310,8 +311,27 @@ void ConnectController()
310311
}
311312

312313
SceneView.duringSceneGui += OnSceneGUI;
314+
Selection.RegisterCustomHandler(kSelectionKey, CustomSelectionHandler, LoadWindowIcon());
315+
}
316+
317+
static void CustomSelectionHandler(string data, Object active, Object[] selected)
318+
{
319+
var info = GraphSelection.FromJson(data);
320+
if (info == null)
321+
return;
322+
323+
var window = EditorWindow.focusedWindow as VFXViewWindow;
324+
var gv = window?.graphView;
325+
if (gv?.controller == null)
326+
return;
327+
328+
// apply selection
329+
info.ApplyToGraphView(gv, gv.blackboard);
330+
Selection.activeObject = active;
331+
Selection.objects = selected;
313332
}
314333

334+
315335
IEnumerable<Type> GetAcceptedTypeNodes()
316336
{
317337
if (!controller.model.isSubgraph)
@@ -489,10 +509,15 @@ public static VisualTreeAsset LoadUXML(string text)
489509

490510
public static Texture2D LoadImage(string text)
491511
{
492-
string path = string.Format("{0}/VFX/{1}.png", VisualEffectAssetEditorUtility.editorResourcesPath, text);
512+
string path = $"{VisualEffectAssetEditorUtility.editorResourcesPath}/VFX/{text}.png";
493513
return EditorGUIUtility.LoadIcon(path);
494514
}
495515

516+
internal static Texture2D LoadWindowIcon()
517+
{
518+
return LoadImage(EditorGUIUtility.isProSkin ? "vfx_graph_icon_gray_dark" : "vfx_graph_icon_gray_light");
519+
}
520+
496521
SelectionDragger m_SelectionDragger;
497522
RectangleSelector m_RectangleSelector;
498523

@@ -1986,22 +2011,39 @@ public void UpdateGlobalSelection()
19862011
{
19872012
if (controller == null) return;
19882013

1989-
var objectSelected = selection.OfType<VFXNodeUI>().Select(t => t.controller.model).Concat(selection.OfType<VFXContextUI>().Select(t => t.controller.model).Cast<VFXModel>()).Where(t => t != null).ToArray();
1990-
1991-
if (objectSelected.Length > 0)
2014+
var toSelect = new List<Object>();
2015+
var sel = new GraphSelection();
2016+
var selNames = new List<string>();
2017+
foreach (var s in selection)
19922018
{
1993-
Selection.objects = objectSelected;
1994-
Selection.objects = objectSelected;
1995-
return;
2019+
if (s is VFXNodeUI node)
2020+
{
2021+
var obj = node.controller.model;
2022+
if (obj != null)
2023+
{
2024+
toSelect.Add(obj);
2025+
sel.elements.Add(node.viewDataKey);
2026+
selNames.Add(!string.IsNullOrEmpty(obj.name) ? obj.name : obj.GetType().Name);
2027+
}
2028+
}
2029+
else if (s is BlackboardField field)
2030+
{
2031+
var obj = field.GetFirstAncestorOfType<VFXBlackboardRow>().controller.model;
2032+
if (obj != null)
2033+
{
2034+
toSelect.Add(obj);
2035+
sel.elements.Add(field.viewDataKey);
2036+
selNames.Add(obj.exposedName);
2037+
}
2038+
}
19962039
}
19972040

1998-
var blackBoardSelected = selection.OfType<BlackboardField>().Select(t => t.GetFirstAncestorOfType<VFXBlackboardRow>().controller.model).ToArray();
1999-
2000-
if (blackBoardSelected.Length > 0)
2001-
{
2002-
Selection.objects = blackBoardSelected;
2041+
if (sel.empty)
20032042
return;
2004-
}
2043+
2044+
if (selNames.Count > 3) selNames = selNames.Take(3).Append("...").ToList();
2045+
var label = string.Join(", ", selNames);
2046+
Selection.SetCustomSelection(kSelectionKey, label, EditorJsonUtility.ToJson(sel), null, toSelect.ToArray());
20052047
}
20062048

20072049
internal void SelectAsset()

0 commit comments

Comments
 (0)