void ApplySerializewindowLayouts(GeometryChangedEvent evt)
        {
            UnregisterCallback <GeometryChangedEvent>(ApplySerializewindowLayouts);

            if (m_FloatingWindowsLayout != null)
            {
                // Restore blackboard layout, and make sure that it remains in the view.
                Rect blackboardRect = m_FloatingWindowsLayout.blackboardLayout.GetLayout(this.layout);

                // Make sure the dimensions are sufficiently large.
                blackboardRect.width  = Mathf.Clamp(blackboardRect.width, 160f, m_GraphView.contentContainer.layout.width);
                blackboardRect.height = Mathf.Clamp(blackboardRect.height, 160f, m_GraphView.contentContainer.layout.height);

                // Make sure that the positionining is on screen.
                blackboardRect.x = Mathf.Clamp(blackboardRect.x, 0f, Mathf.Max(1f, m_GraphView.contentContainer.layout.width - blackboardRect.width - blackboardRect.width));
                blackboardRect.y = Mathf.Clamp(blackboardRect.y, 0f, Mathf.Max(1f, m_GraphView.contentContainer.layout.height - blackboardRect.height - blackboardRect.height));

                // Set the processed blackboard layout.
                m_BlackboardProvider.blackboard.SetPosition(blackboardRect);
            }
            else
            {
                m_FloatingWindowsLayout = new FloatingWindowsLayout();
            }

            // After the layout is restored from the previous session, start tracking layout changes in the blackboard.
            m_BlackboardProvider.blackboard.RegisterCallback <GeometryChangedEvent>(StoreBlackboardLayoutOnGeometryChanged);

            // After the layout is restored, track changes in layout and make the blackboard have the same behavior as the preview w.r.t. docking.
            RegisterCallback <GeometryChangedEvent>(HandleEditorViewChanged);
        }
        void UpdateSerializedWindowLayout()
        {
            if (m_FloatingWindowsLayout == null)
            {
                m_FloatingWindowsLayout = new FloatingWindowsLayout();
            }

            m_FloatingWindowsLayout.blackboardLayout.CalculateDockingCornerAndOffset(m_BlackboardProvider.blackboard.layout, m_GraphView.layout);
            m_FloatingWindowsLayout.blackboardLayout.ClampToParentWindow();

            string serializedWindowLayout = JsonUtility.ToJson(m_FloatingWindowsLayout);

            EditorUserSettings.SetConfigValue(k_FloatingWindowsLayoutKey, serializedWindowLayout);
        }
        public GraphEditorView(EditorWindow editorWindow, AbstractNodeGraph graph)
        {
            m_Graph = graph;
            styleSheets.Add(Resources.Load <StyleSheet>("Styles/GraphEditorView"));

            string serializedWindowLayout = EditorUserSettings.GetConfigValue(k_FloatingWindowsLayoutKey);

            if (!string.IsNullOrEmpty(serializedWindowLayout))
            {
                m_FloatingWindowsLayout = JsonUtility.FromJson <FloatingWindowsLayout>(serializedWindowLayout);
            }


            var toolbar = new IMGUIContainer(() =>
            {
                GUILayout.BeginHorizontal(EditorStyles.toolbar);
                if (GUILayout.Button("Save Asset", EditorStyles.toolbarButton))
                {
                    if (saveRequested != null)
                    {
                        saveRequested();
                    }
                }
                GUILayout.Space(6);
                if (GUILayout.Button("Show In Project", EditorStyles.toolbarButton))
                {
                    if (showInProjectRequested != null)
                    {
                        showInProjectRequested();
                    }
                }
                GUILayout.FlexibleSpace();
                GUILayout.EndHorizontal();
            });

            Add(toolbar);

            var content = new VisualElement {
                name = "content"
            };

            {
                m_GraphView = new NodeGraphView(m_Graph)
                {
                    name = "GraphView", viewDataKey = "NodeGraphView"
                };
                m_GraphView.SetupZoom(0.05f, ContentZoomer.DefaultMaxScale);
                m_GraphView.AddManipulator(new ContentDragger());
                m_GraphView.AddManipulator(new SelectionDragger());
                m_GraphView.AddManipulator(new RectangleSelector());
                m_GraphView.AddManipulator(new ClickSelector());
                m_GraphView.RegisterCallback <KeyDownEvent>(OnSpaceDown);
                content.Add(m_GraphView);

                m_BlackboardProvider = new BlackboardProvider(graph);
                m_GraphView.Add(m_BlackboardProvider.blackboard);

                Rect blackboardLayout = m_BlackboardProvider.blackboard.layout;
                blackboardLayout.x = 10f;
                blackboardLayout.y = 10f;
                m_BlackboardProvider.blackboard.SetPosition(blackboardLayout);

                m_GraphView.graphViewChanged = GraphViewChanged;

                RegisterCallback <GeometryChangedEvent>(ApplySerializewindowLayouts);
            }

            m_SearchWindowProvider = ScriptableObject.CreateInstance <SearchWindowProvider>();
            m_SearchWindowProvider.Initialize(editorWindow, m_Graph, m_GraphView);
            m_GraphView.nodeCreationRequest = (c) =>
            {
                m_SearchWindowProvider.connectedPort = null;
                SearchWindow.Open(new SearchWindowContext(c.screenMousePosition), m_SearchWindowProvider);
            };

            m_EdgeConnectorListener = new EdgeConnectorListener(m_Graph, m_SearchWindowProvider);

            foreach (var node in graph.GetNodes <INode>())
            {
                AddNode(node);
            }

            foreach (var edge in graph.GetEdges())
            {
                AddEdge(edge);
            }

            Add(content);
        }