Search Unity

Bare Bones GraphView Example?

Discussion in 'UI Toolkit' started by paladinrose, Nov 16, 2019.

  1. paladinrose

    paladinrose

    Joined:
    Aug 1, 2010
    Posts:
    11
    Hey all,

    I'm presently converting many of my editor tools over to use the new UIElements.

    Many of my tools use node based graphs and I'm eager to make use of the experimental GraphView system to handle those tools, since it has support for tons of features that my own graphs didn't (like good looking zooming! :D )

    I'll be honest: I'm out of my depth. I've seen rygo6's example system, and I've been picking my way through the code on the Shader Graph and VFX Graph githubs, but it is a lot to take in.

    Here's what I was hoping: Is there anyone who can provide me a thorough, but bare-bones example?
    How would I get this example code working to the point that I can see a GraphView with a boring old labeled node?
    Code (CSharp):
    1. public class TestGraphWindow : EditorWindow
    2. {
    3.     public static void OpenWindow()
    4.     {
    5.         TestGraphWindow wnd = GetWindow<TestGraphWindow>();
    6.         wnd.titleContent = new GUIContent("Test Graph Window");
    7.        
    8.         wnd.CreateElement();
    9.     }
    10.  
    11.     private void CreateElement()
    12.     {
    13.  
    14.         TestGraphView graphView = new TestGraphView() { name = "Graph View" };
    15.  
    16.         graphView.styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/UI/TestGraphView.uss"));
    17.  
    18.         GridBackground gridBackground = new GridBackground();
    19.         gridBackground.name = "Grid";
    20.         graphView.Add(gridBackground);
    21.  
    22.         graphView.SetupZoom(0.05f, ContentZoomer.DefaultMaxScale);
    23.         graphView.AddManipulator(new ContentDragger());
    24.         graphView.AddManipulator(new SelectionDragger());
    25.         graphView.AddManipulator(new RectangleSelector());
    26.         graphView.AddManipulator(new ClickSelector());
    27.      
    28.         rootVisualElement.Add(graphView);
    29.  
    30.         TestNode exampleNode = new TestNode() { name = "Example Node" };
    31.  
    32.         exampleNode.styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/UI/TestNode.uss"));
    33.  
    34.         graphView.AddElement(exampleNode);
    35.     }
    36.  
    37. }
    Right now, this seems to be showing me the gray background of the grid background, but no node. I have experimented enough to find that I can add a button to the node and if I hunt, I can find that button and successfully click it... I just can't see the node at all.

    So that's as far as I'm trying get right now. No ports, inputs, outputs, or edges. Even the graph view manipulators are extra: I don't mind removing them if that helps me get this first part working.
    So far, I just want to make a GraphView named "GraphView", with a grid background and an example node called "Example Node".
    I just want a gray box of a node with a label that reads "Example Node". And that's all. Just so I have a good toe in the water to start from.

    A few questions:
    -What, if any, UXML files might I need?
    -What info do I need in TestGraphView.uss and TestNode.uss?

    Thank you, genuinely, to any kind soul that can help.
     
    ModLunar likes this.
  2. paladinrose

    paladinrose

    Joined:
    Aug 1, 2010
    Posts:
    11
    Well, no replies so far. I'm going to try again to build a working example, and I'll post my notes and progress in this thread, throughout, in case it's a help to anyone else, moving forward.

    My first guess is that the style sheet properties - particularly for the node - are not set, so there's nothing to show... which is maybe a bit of an odd default state, but hey! Who am I to judge, huh?
    I'm going to start my work by getting a complete list of the visual elements in my test node. Then I'm going to start at the top of the list and set the style sheet settings explicitly for each of them until I've got something visible.

    As always if anyone has any recommendations, please post! I'd love to get any feedback I can.
     
    MikeyMyk likes this.
  3. paladinrose

    paladinrose

    Joined:
    Aug 1, 2010
    Posts:
    11
    Some starting success!

    First, our data objects. These are presently empty placeholders and you can absolutely omit them and this still works. Later, they'll be responsible for holding all of our graphs serialized info:
    Code (CSharp):
    1. [System.Serializable]
    2. public class TestNode { }
    3.  
    4. [System.Serializable]
    5. public class TestGraph { }
    6.  
    7. [CreateAssetMenu(menuName ="Ideam Tests/Test Graph Object")]
    8. public class TestGraphObject : ScriptableObject
    9. {
    10.  
    11.     public TestGraph[] graphs = new TestGraph[0];
    12.  
    13. }
    Next, some example editors:
    Code (CSharp):
    1. public class TestNodeElement : Node
    2. {
    3.     TestNode node;
    4.     public TestNodeElement(TestNode testNode)
    5.     {
    6.         node = testNode;
    7.     }
    8.  
    9.     public void InitializeNode()
    10.     {
    11.         //This was a big part of the issue, right here. In custom nodes, this doesn't get called automatically.
    12.         //Short of supplying your own stylesheet that covers all the bases, this needs to be explicitly called to give a node visible attributes.
    13.         UseDefaultStyling();
    14.  
    15.         VisualElement contents = this.Q<VisualElement>("contents");
    16.  
    17.         Button contentsButton = new Button(() => { Debug.Log("Clicked!"); });
    18.         contentsButton.text = contentsButton.name = "Test Button";
    19.         contents.Add(contentsButton);
    20.         title = "Test Node";
    21.        
    22.         SetPosition(new Rect(50, 50, 0, 0));
    23.        
    24.         MarkDirtyRepaint();
    25.     }
    26. }
    27.  
    28. public class TestGraphView : GraphView
    29. {
    30.     public TestGraph graph;
    31.     public TestGraphView() { }
    32. }
    33.  
    There's also an editor for the TestGraphObject, but all it does is provide a button that opens the TestGraphWindow.

    Lastly, our example window brings everything together:
    Code (CSharp):
    1. public class TestGraphWindow : EditorWindow
    2. {
    3.     public static void OpenWindow(TestGraphObject graphObject)
    4.     {
    5.         TestGraphWindow wnd = GetWindow<TestGraphWindow>();
    6.         wnd.titleContent = new GUIContent("Test Graph Window");
    7.         wnd.graphObject = graphObject;
    8.         wnd.CreateElement();
    9.     }
    10.  
    11.     TestGraphObject graphObject;
    12.  
    13.     private void CreateElement()
    14.     {
    15.         rootVisualElement.Clear();
    16.  
    17.         if (graphObject.graphs.Length == 0) { graphObject.graphs = new TestGraph[1]; graphObject.graphs[0] = new TestGraph(); }
    18.  
    19.         TestGraphView graphView = new TestGraphView() { name = "Test Graph", viewDataKey = "TestGraphView", graph = graphObject.graphs[0] };
    20.  
    21.         graphView.SetupZoom(0.05f, ContentZoomer.DefaultMaxScale);
    22.  
    23.         graphView.AddManipulator(new ContentDragger());
    24.         graphView.AddManipulator(new SelectionDragger());
    25.         graphView.AddManipulator(new RectangleSelector());
    26.         graphView.AddManipulator(new ClickSelector());
    27.        
    28.         graphView.RegisterCallback<KeyDownEvent>(KeyDown);
    29.  
    30.         graphView.graphViewChanged = GraphViewChanged;
    31.  
    32.         rootVisualElement.Add(graphView);
    33.         graphView.StretchToParentSize();
    34.  
    35.  
    36.         GridBackground gridBackground = new GridBackground() { name = "Grid" };
    37.         graphView.Add(gridBackground);
    38.         gridBackground.SendToBack();
    39.  
    40.  
    41.         TestNode eNode = new TestNode();
    42.  
    43.         TestNodeElement exampleNode = new TestNodeElement(eNode) {name = "Example Node" };
    44.         graphView.AddElement(exampleNode);
    45.         exampleNode.InitializeNode();
    46.  
    47.         rootVisualElement.MarkDirtyRepaint();
    48.  
    49.     }
    50.  
    51.     //Placeholder functions
    52.     private GraphViewChange GraphViewChanged(GraphViewChange graphViewChange)
    53.     {
    54.        
    55.  
    56.         return graphViewChange;
    57.     }
    58.  
    59.  
    60.     private void KeyDown(KeyDownEvent evt)
    61.     {
    62.        
    63.     }
    64. }
    65.  

    And my results:
    SmallVictories001.jpg
     
    NVriezen, NotaNaN, ModLunar and 7 others like this.