/// <inheritdoc /> protected override void InitializeFolderNodeLabels(FolderNodeState state, IFoldingView foldingView, INode viewNode, INode masterNode) { state.ClearLabels(); if (CopyLabels) { var labels = masterNode.Labels; if (labels.Count > 0) { for (var i = 0; i < labels.Count; i++) { var label = labels[i]; // If the node is a choreographyNode, just copy all Labels if (masterNode.Style is ChoreographyNodeStyle) { state.AddLabel(label.Text, label.LayoutParameter, label.Style, label.PreferredSize, label.Tag); } else { // if subProcessNode, create new Layout & Style var labelStyle = CreateLabelStyle(foldingView, null, label); var labelModel = new InteriorStretchLabelModel { Insets = new InsetsD(3, 3, 3, 3) }; var labelLayoutParameter = labelModel.CreateParameter(InteriorStretchLabelModel.Position.Center); state.AddLabel(label.Text, labelLayoutParameter ?? label.LayoutParameter, labelStyle ?? label.Style, label.PreferredSize, label.Tag); } } } } }
protected virtual VisualToggleButton CreateButton(IRenderContext context, INode item, Visual collapsedVisual, Visual expandedVisual) { var button = new VisualToggleButton { CommandParameter = item, Command = GraphCommands.ToggleExpansionState, CheckedVisual = collapsedVisual, UncheckedVisual = expandedVisual, Background = iconBrush }; bool expanded = true; var canvas = context != null ? context.CanvasControl : null; if (canvas != null) { button.CommandTarget = canvas; IGraph graph = canvas.Lookup(typeof(IGraph)) as IGraph; if (graph != null) { IFoldingView foldingView = graph.Lookup <IFoldingView>(); if (foldingView != null && foldingView.Graph.Contains(item)) { expanded = foldingView.IsExpanded(item); } } } else { button.Content = "+"; } button.IsChecked = !expanded; return(button); }
/// <inheritdoc /> protected override void InitializeFolderNodePorts(FolderNodeState state, IFoldingView foldingView, INode viewNode, INode masterNode) { foreach (var port in viewNode.Ports) { var masterPort = foldingView.GetMasterItem(port); var newStyle = CreatePortStyle(foldingView, port, masterPort); var portState = state.GetFoldingPortState(masterPort); if (newStyle != null) { portState.Style = newStyle; } var newLocationParameter = CreatePortLocationParameter(foldingView, port, masterPort); if (newLocationParameter != null) { portState.LocationParameter = newLocationParameter; } if (masterPort.Labels.Count > 0) { for (var i = 0; i < masterPort.Labels.Count; i++) { var label = masterPort.Labels[i]; var labelStyle = CreateLabelStyle(foldingView, null, label); var labelLayoutParameter = CreateLabelLayoutParameter(foldingView, null, label); portState.AddLabel(label.Text, labelLayoutParameter ?? label.LayoutParameter, labelStyle ?? label.Style, label.PreferredSize, label.Tag); } } } }
/// <summary> /// Helper method for the <see cref="ShowContentsCommand"/> binding. /// </summary> private void OnCanShowContentsExecuted(object sender, CanExecuteRoutedEventArgs e) { if (graphControl == null) { e.Handled = false; return; } // see if we can execute the command... IFoldingView graph = graphControl.Graph.Lookup <IFoldingView>(); if (graph != null) { INode node = FindNode(graph, e.Parameter); if (node != null) { // yes, we found a node - notify the binding. e.CanExecute = true; e.Handled = true; } } else { e.Handled = false; } }
/// <summary> /// Helper method that identifies the node to show the contents of /// if <see cref="ShowContentsCommand"/> is executed. /// </summary> /// <remarks> /// This method will use the parameter as the return value or the currently selected node /// if it's a group node. /// </remarks> private INode FindNode(IFoldingView foldingView, object parameter) { INode node = parameter as INode; if (node != null && foldingView.Graph.Contains(node) && !foldingView.Manager.MasterGraph.IsGroupNode(foldingView.GetMasterItem(node))) { node = null; } if (node == null) { IEnumerator <INode> selectedNodes = graphControl.Selection.SelectedNodes.GetEnumerator(); while (selectedNodes.MoveNext()) { node = selectedNodes.Current; if (foldingView.Graph.Contains(node) && foldingView.Manager.MasterGraph.IsGroupNode(foldingView.GetMasterItem(node))) { break; } else { node = null; } } } return(node); }
/// <summary> /// Creates a new instance and installs it on the given <see cref="GraphControl"/>. /// </summary> /// <param name="graphControl">The control to install the z-order support on.</param> public ZOrderSupport(GraphControl graphControl) { GraphControl = graphControl; // make this ZOrderSupport available via lookup of the view graph and master graph AddZOrderSupportLookup(graphControl.Graph, this); FoldingView = graphControl.Graph.GetFoldingView(); MasterGraph = FoldingView.Manager.MasterGraph; MasterGroupingSupport = MasterGraph.GetGroupingSupport(); AddZOrderSupportLookup(MasterGraph, this); // use this ZOrderSupport as node comparer for the visualization graphControl.GraphModelManager = new ZOrderGraphModelManager(graphControl, this); // keep labels at their owners for this demo graphControl.GraphModelManager.LabelLayerPolicy = LabelLayerPolicy.AtOwner; // set a custom GraphMLIOHandler that supports writing and parsing node z-orders to/from GraphML graphControl.GraphMLIOHandler = new ZOrderGraphMLIOHandler(); // use a custom edit mode to keep z-order consistent during grouping/folding/reparenting gestures graphControl.InputMode = new ZOrderGraphEditorInputMode(this); graphControl.Graph.GetDecorator().NodeDecorator.PositionHandlerDecorator.SetFactory(node => new ZOrderNodePositionHandler(node)); // use a custom clipboard that transfers the relative z-order of copied/cut nodes graphControl.Clipboard = new ZOrderGraphClipboard(this); // listen for new nodes to assign an initial z-order MasterGraph.NodeCreated += OnNodeCreated; AddZOrderForNewNodes = true; }
/// <summary> /// Helper method for the <see cref="ShowContentsCommand"/> binding. /// </summary> private void OnShowContentsExecuted(object sender, ExecutedRoutedEventArgs e) { if (graphControl == null) { e.Handled = false; return; } // get the IFoldingView instance IFoldingView graph = graphControl.Graph.Lookup <IFoldingView>(); if (graph != null) { // find the node to show the contents for INode node = FindNode(graph, e.Parameter); // if we found one if (node != null) { // show it ShowContents(graph.GetMasterItem(node)); e.Handled = true; } } else { e.Handled = false; } }
public override void UpdateFolderNodeState(FolderNodeState state, IFoldingView foldingView, INode viewNode, INode masterNode) { SynchronizeLabels(state, foldingView, viewNode, masterNode); // Copys the changed master Style to the state state.Style = masterNode.Style; }
/// <summary> /// Helper method that creates a window that displays an alternative view of the /// MasterGraph using a separate FoldingManager and therefor a separate set of /// dummy items. /// </summary> /// <remarks> /// This allows for using different visualizations of the folding edges and collapsed group nodes. /// </remarks> /// <param name="foldingEdgeConverter">The edge converter to use</param> private void ShowAdditionalManager(IFoldingEdgeConverter foldingEdgeConverter) { // create the GraphControl GraphControl graphControl = new GraphControl(); // create a new manager for the same master graph. FoldingManager manager = new FoldingManager(foldingManager.MasterGraph); // assign the provided converter manager.FoldingEdgeConverter = foldingEdgeConverter; // create a view IFoldingView foldingView = manager.CreateFoldingView(); // make the view disappear once it becomes invalid foldingView.AutoSwitchToAncestor = false; // set the graph graphControl.Graph = foldingView.Graph; // and edit mode graphControl.InputMode = CreateEditorMode(); // share the clipboard with the rest of the windows graphControl.Clipboard = this.graphControl.Clipboard; // create the form Form form = new Form(); graphControl.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; form.Size = new Size(300, 300); graphControl.Location = new Point(0, 0); graphControl.Size = form.Size; form.Text = "Separate FoldingManager using " + foldingEdgeConverter; form.SuspendLayout(); form.Controls.Add(graphControl); form.ResumeLayout(); form.Visible = true; form.Owner = this; // fit the bounds graphControl.FitGraphBounds(); // setup delegate to dispose the window once the view becomes invalid foldingView.PropertyChanged += delegate(object _sender, PropertyChangedEventArgs _e) { if (_e.PropertyName == "Invalid" && foldingView.Invalid) { manager.Dispose(); form.Close(); form.Dispose(); } }; }
/// <summary> /// Change the default style for group nodes. /// </summary> /// <remarks>We use <see cref="CollapsibleNodeStyleDecorator"/> to wrap the /// <see cref="PanelNodeStyle"/> from the last demo, since we want to have nice /// +/- buttons for collapse/expand. Note that if you haven't defined /// a custom group node style, you don't have to do anything at all, since /// <see cref="FoldingManager"/> already /// provides such a decorated group node style by default.</remarks> private void WrapGroupNodeStyles() { IFoldingView foldingView = graphControl.Graph.GetFoldingView(); if (foldingView != null) { //PanelNodeStyle is a nice style especially suited for group nodes PanelNodeStyle style = new PanelNodeStyle { Color = Colors.LightBlue }; //Wrap the style with CollapsibleNodeStyleDecorator foldingView.Graph.GroupNodeDefaults.Style = new CollapsibleNodeStyleDecorator(style); } }
/// <summary> /// Helper method that creates a window that displays an alternative view of the /// MasterGraph using a separate FoldingManager and therefore a separate set of /// dummy items. /// </summary> /// <remarks> /// This allows for using different visualizations of the folding edges and collapsed group nodes. /// </remarks> /// <param name="foldingEdgeConverter">The edge converter to use</param> private void ShowAdditionalManager(IFoldingEdgeConverter foldingEdgeConverter) { // create the window Window window = new Window(); window.Title = "Separate FoldingManager using " + foldingEdgeConverter; // create the GraphControl GraphControl graphControl = new GraphControl(); // create a new manager for the same master graph. FoldingManager manager = new FoldingManager(foldingManager.MasterGraph); // assign the provided converter manager.FoldingEdgeConverter = foldingEdgeConverter; // create a view IFoldingView foldingView = manager.CreateFoldingView(); // make the view disappear once it becomes invalid foldingView.AutoSwitchToAncestor = false; // set the graph graphControl.Graph = foldingView.Graph; // and edit mode graphControl.InputMode = CreateEditorMode(); // share the clipboard with the rest of the windows graphControl.Clipboard = this.graphControl.Clipboard; // show the window window.Content = graphControl; window.Width = window.Height = 300; window.Owner = this; window.Show(); // fit the bounds graphControl.FitGraphBounds(); // setup delegate to dispose the window once the view becomes invalid foldingView.PropertyChanged += delegate(object _sender, PropertyChangedEventArgs _e) { if (_e.PropertyName == "Invalid" && foldingView.Invalid) { manager.Dispose(); window.Close(); } }; }
private void ShowContents(INode localRoot) { GraphControl groupContentsGraphControl = new GraphControl(); // now obtain a view for the given node from the manager IFoldingView foldingView = foldingManager.CreateFoldingView(localRoot); // instead of switching to the ancestor if the localRoot is removed from the graph, // we want to dispose the window, instead. foldingView.AutoSwitchToAncestor = false; // assign the graph and input mode groupContentsGraphControl.Graph = foldingView.Graph; groupContentsGraphControl.InputMode = CreateEditorMode(); // share the clipboard so that we can cut and copy between the windows groupContentsGraphControl.Clipboard = this.graphControl.Clipboard; groupContentsGraphControl.SmoothingMode = this.graphControl.SmoothingMode; // Create the form Form form = new Form(); form.Load += delegate { groupContentsGraphControl.FitGraphBounds(); }; // show the master graph groupContentsGraphControl.Dock = DockStyle.Fill; form.ClientSize = new Size(300, 300); form.Text = "Contents of " + localRoot; form.SuspendLayout(); form.Controls.Add(groupContentsGraphControl); form.ResumeLayout(); form.Owner = this; form.Visible = true; // setup delegate to dispose the window once the view becomes invalid foldingView.PropertyChanged += delegate(object _sender, PropertyChangedEventArgs _e) { if (_e.PropertyName == "Invalid" && foldingView.Invalid) { foldingView.Dispose(); form.Close(); form.Dispose(); } }; }
private bool IsExpanded(IRenderContext context, INode node) { CanvasControl canvas = context != null ? context.CanvasControl : null; if (canvas != null) { IGraph graph = canvas.Lookup(typeof(IGraph)) as IGraph; if (graph != null) { IFoldingView foldedGraph = graph.Lookup <IFoldingView>(); if (foldedGraph != null && foldedGraph.Graph.Contains(node)) { return(foldedGraph.IsExpanded(node)); } } } return(true); }
/// <summary> /// Initializes the graph instance setting default styles /// and creating a small sample graph. /// </summary> protected virtual void InitializeGraph() { // Create the folding manager foldingManager = new FoldingManager(); // initialize it with some default for this demo. InitializeFoldingManager(); // initialize the master graph foldingManager.MasterGraph.GroupNodeDefaults.Style = new CollapsibleNodeStyleDecorator(new PanelNodeStyle { Color = Colors.LightSkyBlue }); foldingManager.MasterGraph.NodeDefaults.Style = new BevelNodeStyle { Color = Colors.Black }; // enable undoability on the master graph foldingManager.MasterGraph.SetUndoEngineEnabled(true); // create a managed view IFoldingView view = foldingManager.CreateFoldingView(); view.EnqueueNavigationalUndoUnits = true; // and display it graphControl.Graph = view.Graph; IGraph graph = foldingManager.MasterGraph; // try loading the initial sample graph try { string s = Environment.CurrentDirectory; graphControl.ImportFromGraphML(new FileInfo(s + "\\sample.graphml")); } catch (IOException) { // create initial sample data in our model CreateInitialModelGraph(graph); } }
public override IVisual CreateVisual(IRenderContext context) { collapsedIcon.SetBounds(new RectD(Bounds.GetTopLeft(), Bounds.GetSize())); expandedIcon.SetBounds(new RectD(Bounds.GetTopLeft(), Bounds.GetSize())); bool expanded = true; CanvasControl canvas = context != null ? context.CanvasControl : null; if (canvas != null) { IGraph graph = canvas.Lookup(typeof(IGraph)) as IGraph; if (graph != null) { IFoldingView foldedGraph = graph.Lookup <IFoldingView>(); if (foldedGraph != null && foldedGraph.Graph.Contains(node)) { expanded = foldedGraph.IsExpanded(node); } } } return(expanded ? expandedIcon.CreateVisual(context) : collapsedIcon.CreateVisual(context)); }
private void ShowContents(INode localRoot) { Window window = new Window(); window.Title = "Contents of " + localRoot; // we create a new control GraphControl groupContentsGraphControl = new GraphControl(); // now obtain a view for the given node from the manager IFoldingView foldingView = foldingManager.CreateFoldingView(localRoot); // instead of switching to the ancestor if the localRoot is removed from the graph, // we want to dispose the window, instead. foldingView.AutoSwitchToAncestor = false; // assign the graph and input mode groupContentsGraphControl.Graph = foldingView.Graph; groupContentsGraphControl.InputMode = CreateEditorMode(); // share the clipboard so that we can cut and copy between the windows groupContentsGraphControl.Clipboard = this.graphControl.Clipboard; // show the window window.Content = groupContentsGraphControl; window.Width = window.Height = 300; window.Owner = this; window.Show(); // and fit the bounds window.Dispatcher.BeginInvoke(new Action(() => groupContentsGraphControl.FitGraphBounds())); // register a delegate that will dispose the window when the view gets invalid foldingView.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "Invalid" && foldingView.Invalid) { window.Close(); } }; }
internal static TierType GetTierType(INode node, IFoldingView foldingView, IGraph graph) { if (graph.IsGroupNode(node) // node is an expanded group node || foldingView.IsInFoldingState(node)) { string labelText = (node.Labels.Count > 0) ? node.Labels[0].Text : ""; switch (labelText) { case "left": return(TierType.LeftTreeGroupNode); case "right": return(TierType.RightTreeGroupNode); default: return(TierType.CommonNode); } } return(TierType.CommonNode); }
/// <summary> /// Initializes the graph instance, setting default styles /// and creating a small sample graph. /// </summary> protected virtual void InitializeGraph() { // create the manager for the folding operations FoldingManager foldingManager = new FoldingManager(); // create a view foldingView = foldingManager.CreateFoldingView(); // and set it to the GraphControl graphControl.Graph = foldingView.Graph; // decorate the behavior of nodes NodeDecorator nodeDecorator = graphControl.Graph.GetDecorator().NodeDecorator; // adjust the insets so that labels are considered nodeDecorator.InsetsProviderDecorator.SetImplementationWrapper( delegate(INode node, INodeInsetsProvider insetsProvider) { if (insetsProvider != null) { InsetsD insets = insetsProvider.GetInsets(node); return(new LabelInsetsProvider(insets)); } else { return(new LabelInsetsProvider()); } }); //Constrain group nodes to at least the size of their labels nodeDecorator.SizeConstraintProviderDecorator.SetImplementationWrapper( (node, oldImpl) => new LabelSizeConstraintProvider(oldImpl)); fixedGroupNodeLayout = graphControl.Graph.MapperRegistry.CreateMapper <INode, RectD?>("NodeLayouts"); ReadSampleGraph(); incrementalNodes.UnionWith(graphControl.Graph.Nodes); }
/// <summary> /// Called by <see cref="UpdateFolderNodeState" /> to synchronize all labels, if <see cref="CopyLabels" /> /// is enabled. Also synchronizes all port labels of ports connected to the node. /// </summary> /// <remarks>This will adjust the label text property.</remarks> /// <param name="state">The node view state whose labels should be synchronized.</param> /// <param name="foldingView">The folding view.</param> /// <param name="viewNode">The local node instance.</param> /// <param name="masterNode">The master node.</param> protected override void SynchronizeLabels(FolderNodeState state, IFoldingView foldingView, INode viewNode, INode masterNode) { if (CopyLabels) { if (masterNode.Labels.Count > 0 && state.Labels.Count > 0) { for (var i = 0; i < masterNode.Labels.Count; i++) { var masterLabel = masterNode.Labels[i]; var labelViewState = state.Labels[i]; labelViewState.Text = masterLabel.Text; labelViewState.PreferredSize = masterLabel.PreferredSize; labelViewState.Tag = masterLabel.Tag; } } if (masterNode.Ports.Count > 0) { for (var j = 0; j < masterNode.Ports.Count; j++) { var port = masterNode.Ports[j]; if (port.Labels.Count > 0) { for (var i = 0; i < port.Labels.Count; i++) { var masterLabel = port.Labels[i]; var labelViewState = state.Ports[j].Labels[i]; labelViewState.Text = masterLabel.Text; labelViewState.PreferredSize = masterLabel.PreferredSize; labelViewState.Tag = masterLabel.Tag; } } } } } }
private void ArrangeItems(List <INode> newMasterItems, IFoldingView foldingView) { // sort new items by the relative z-order transferred in OnCopiedFromClipboard newMasterItems.Sort((node1, node2) => GetZOrder(node1) - GetZOrder(node2)); var gmm = Support.GraphControl.GraphModelManager; // group new nodes by common parent canvas object groups of their main canvas objects var itemsNotInView = new List <INode>(); var groupToItems = new Dictionary <ICanvasObjectGroup, List <INode> >(); foreach (var masterItem in newMasterItems) { var viewItem = foldingView != null?foldingView.GetViewItem(masterItem) : masterItem; if (viewItem == null) { // new item is not in view (e.g. child of a collapsed folder node) itemsNotInView.Add(masterItem); } else { var co = gmm.GetMainCanvasObject(viewItem); if (co == null) { itemsNotInView.Add(masterItem); } else { var coGroup = co.Group; List <INode> newNodesInGroup; if (!groupToItems.TryGetValue(coGroup, out newNodesInGroup)) { newNodesInGroup = new List <INode>(); groupToItems[coGroup] = newNodesInGroup; } newNodesInGroup.Add(viewItem); } } } // set z-order items not in view just in ascending order for (var i = 0; i < itemsNotInView.Count; i++) { Support.SetZOrder(itemsNotInView[i], i); } // for each common parent set ascending z-orders for new nodes foreach (var groupItemsPair in groupToItems) { var itemsInGroup = groupItemsPair.Value; // find the top-most node that wasn't just added and lookup its z-order INode topNodeNotJustAdded = null; ICanvasObject walker = groupItemsPair.Key.Last; while (walker != null) { var node = gmm.GetModelItem(walker) as INode; if (node != null && !itemsInGroup.Contains(node)) { topNodeNotJustAdded = node; break; } walker = walker.Previous; } var nextZOrder = topNodeNotJustAdded != null?GetZOrder(topNodeNotJustAdded) + 1 : 0; // set new z-orders starting from nextZOrder foreach (var node in itemsInGroup) { Support.SetZOrder(node, nextZOrder++); } // update the view using the new z-orders foreach (var node in itemsInGroup) { Support.Update(node); } } }
public MasterViewConversionMapper(IGraph viewGraph) { this.viewGraph = viewGraph; foldingView = viewGraph.GetFoldingView(); masterGraph = foldingView.Manager.MasterGraph; }
public static T GetMaster <T>(this IFoldingView fv, T item) where T : class, IModelItem { return(fv.GetMasterItem(item)); }