Browse Source

Object graph - refactored TreeLayouter.

pull/15/head
mkonicek 15 years ago
parent
commit
4897789b4e
  1. 18
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Drawing/GraphDrawer.cs
  2. 11
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml
  3. 7
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml.cs
  4. 3
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/GraphEdgeRouter.cs
  5. 98
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/Tree/TreeLayouter.cs
  6. 3
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/NodeControlCache.cs

18
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Drawing/GraphDrawer.cs

@ -39,22 +39,10 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -39,22 +39,10 @@ namespace Debugger.AddIn.Visualizers.Graph
/// <param name="diff"></param>
public void StartAnimation(PositionedGraph oldGraph, PositionedGraph newGraph, GraphDiff diff)
{
if (oldGraph != null)
{
foreach (var oldNode in oldGraph.Nodes)
{
foreach (var newNode in newGraph.Nodes)
{
if (oldNode.NodeVisualControl == newNode.NodeVisualControl)
{
ClearCanvas();
}
}
}
}
// account for that the visual controls could have been reused (we are not reusing controls now - NodeControlCache does nothing)
this.canvas.Width = newGraph.BoundingRect.Width;
this.canvas.Height = newGraph.BoundingRect.Height;
// this.canvas.Width = newGraph.BoundingRect.Width;
// this.canvas.Height = newGraph.BoundingRect.Height;
if (oldGraph == null)
{

11
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml

@ -13,7 +13,11 @@ @@ -13,7 +13,11 @@
</UserControl.Resources>
<aero:SystemDropShadowChrome>
<Grid>
<StackPanel Orientation="Vertical">
<!--
<Border Background="#ddeeff" BorderThickness="1,1,1,0" BorderBrush="DarkGray" HorizontalAlignment="Stretch" Padding="1">
<TextBlock>Hello</TextBlock>
</Border> -->
<ListView Name="listView" ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListView.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
@ -51,8 +55,7 @@ @@ -51,8 +55,7 @@
<GridView>
<GridView.ColumnHeaderContainerStyle>
<Style>
<!--
<Setter Property="FrameworkElement.Visibility" Value="Collapsed"/> -->
<!-- <Setter Property="FrameworkElement.Visibility" Value="Collapsed"/> -->
<Setter Property="FrameworkElement.Height" Value="1"/>
</Style>
</GridView.ColumnHeaderContainerStyle>
@ -98,6 +101,6 @@ @@ -98,6 +101,6 @@
</GridView>
</ListView.View>
</ListView>
</Grid>
</StackPanel>
</aero:SystemDropShadowChrome>
</UserControl>

7
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml.cs

@ -59,16 +59,15 @@ namespace Debugger.AddIn.Visualizers.Graph.Drawing @@ -59,16 +59,15 @@ namespace Debugger.AddIn.Visualizers.Graph.Drawing
{
this.root = value;
this.view = getInitialView(this.root);
// data virtualization, PropertyNodeViewModel implements IEvaluate
// data virtualization, ContentPropertyNode implements IEvaluate
this.listView.ItemsSource = new VirtualizingObservableCollection<ContentNode>(this.view);
int maxLen = this.view.MaxOrDefault(contentNode => { return contentNode.Name.Length; }, 0);
/*int maxLen = this.view.MaxOrDefault(contentNode => { return contentNode.Name.Length; }, 0);
int spaces = Math.Max((int)(maxLen * 1.8 - 3), 0);
string addedSpaces = StringHelper.Repeat(' ', spaces);
GridView gv = listView.View as GridView;
// hack - autosize Name column
gv.Columns[1].Header = "Name" + addedSpaces;
gv.Columns[1].Header = "Name" + addedSpaces;*/
//AutoSizeColumns();

3
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/GraphEdgeRouter.cs

@ -21,7 +21,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -21,7 +21,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
{
}
public PositionedGraph RouteEdges(PositionedGraph posGraph)
public void RouteEdges(PositionedGraph posGraph)
{
List<RoutedEdge> routedEdges = router.RouteEdges(posGraph.Nodes, posGraph.Edges);
int i = 0;
@ -30,7 +30,6 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -30,7 +30,6 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
SetEdgeSplinePoints(edge, routedEdges[i]);
i++;
}
return posGraph;
}
void SetEdgeSplinePoints(PositionedEdge edge, RoutedEdge routedEdge)

98
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/Tree/TreeLayouter.cs

@ -17,10 +17,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -17,10 +17,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
private static readonly double horizNodeMargin = 30;
private static readonly double vertNodeMargin = 30;
private LayoutDirection layoutDirection = LayoutDirection.TopBottom;
HashSet<PositionedGraphNode> seenNodes = new HashSet<PositionedGraphNode>();
Dictionary<ObjectGraphNode, PositionedGraphNode> treeNodeFor = new Dictionary<ObjectGraphNode, PositionedGraphNode>();
GraphEdgeRouter edgeRouter = new GraphEdgeRouter();
public TreeLayouter()
{
@ -33,113 +30,89 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -33,113 +30,89 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// <returns></returns>
public PositionedGraph CalculateLayout(ObjectGraph objectGraph, LayoutDirection direction, Expanded expanded)
{
layoutDirection = direction;
treeNodeFor = new Dictionary<ObjectGraphNode, PositionedGraphNode>();
seenNodes = new HashSet<PositionedGraphNode>();
//TreeGraphNode tree = buildTreeRecursive(objectGraph.Root, expandedNodes);
// convert ObjectGraph to PositionedGraph with TreeEdges
var resultGraph = buildTreeGraph(objectGraph, expanded);
// first layout pass
calculateSubtreeSizes((TreeGraphNode)resultGraph.Root);
// second layout pass
calculateNodePosRecursive((TreeGraphNode)resultGraph.Root, 0, 0);
//var neatoRouter = new NeatoEdgeRouter();
//resultGraph = neatoRouter.CalculateEdges(resultGraph);
resultGraph = new GraphEdgeRouter().RouteEdges(resultGraph);
var positionedGraph = BuildPositionedGraph(objectGraph, direction, expanded);
CalculateLayout(positionedGraph);
this.edgeRouter.RouteEdges(positionedGraph);
return resultGraph;
return positionedGraph;
}
private PositionedGraph buildTreeGraph(ObjectGraph objectGraph, Expanded expanded)
PositionedGraph BuildPositionedGraph(ObjectGraph objectGraph, LayoutDirection direction, Expanded expanded)// Expanded is passed so that the correct ContentNodes are expanded in the PositionedNode
{
var treeNodeFor = new Dictionary<ObjectGraphNode, PositionedGraphNode>();
var resultGraph = new PositionedGraph();
// create empty PosNodes
foreach (ObjectGraphNode objectGraphNode in objectGraph.ReachableNodes)
{
TreeGraphNode posNode = createNewTreeGraphNode(objectGraphNode);
// create empty PositionedNodes
foreach (ObjectGraphNode objectGraphNode in objectGraph.ReachableNodes) {
TreeGraphNode posNode = TreeGraphNode.Create(direction, objectGraphNode);
posNode.InitContentFromObjectNode(expanded);
posNode.HorizontalMargin = horizNodeMargin;
posNode.VerticalMargin = vertNodeMargin;
resultGraph.AddNode(posNode);
treeNodeFor[objectGraphNode] = posNode;
posNode.InitContentFromObjectNode(expanded);
}
// create edges
foreach (PositionedGraphNode posNode in resultGraph.Nodes)
{
// create edges outgoing from this posNode
foreach (PositionedNodeProperty property in posNode.Properties)
{
//property.IsPropertyExpanded = expanded.Expressions.IsExpanded(property.Expression);
if (property.ObjectGraphProperty.TargetNode != null)
{
foreach (PositionedNodeProperty property in posNode.Properties) {
if (property.ObjectGraphProperty.TargetNode != null) {
ObjectGraphNode targetObjectNode = property.ObjectGraphProperty.TargetNode;
PositionedGraphNode edgeTarget = treeNodeFor[targetObjectNode];
property.Edge = new TreeGraphEdge
{ IsTreeEdge = false, Name = property.Name, Source = property, Target = edgeTarget };
{ IsTreeEdge = false, Name = property.Name, Source = property, Target = edgeTarget };
}
}
}
resultGraph.Root = treeNodeFor[objectGraph.Root];
return resultGraph;
}
void CalculateLayout(PositionedGraph resultGraph)
{
HashSet<PositionedGraphNode> seenNodes = new HashSet<PositionedGraphNode>();
// first layout pass
CalculateSubtreeSizes((TreeGraphNode)resultGraph.Root, seenNodes);
// second layout pass
CalculateNodePosRecursive((TreeGraphNode)resultGraph.Root, 0, 0);
}
// determines which edges are tree edges, and calculates subtree size for each node
private void calculateSubtreeSizes(TreeGraphNode root)
private void CalculateSubtreeSizes(TreeGraphNode root, HashSet<PositionedGraphNode> seenNodes)
{
seenNodes.Add(root);
double subtreeSize = 0;
foreach (PositionedNodeProperty property in root.Properties)
{
foreach (PositionedNodeProperty property in root.Properties) {
var edge = property.Edge as TreeGraphEdge; // we know that these egdes are TreeEdges
if (edge != null)
{
if (edge != null) {
var neigborNode = (TreeGraphNode)edge.Target;
if (seenNodes.Contains(neigborNode))
{
if (seenNodes.Contains(neigborNode)) {
edge.IsTreeEdge = false;
}
else
{
} else {
edge.IsTreeEdge = true;
calculateSubtreeSizes(neigborNode);
CalculateSubtreeSizes(neigborNode, seenNodes);
subtreeSize += neigborNode.SubtreeSize;
}
}
}
root.Measure();
root.SubtreeSize = Math.Max(root.LateralSizeWithMargin, subtreeSize);
}
private TreeGraphNode createNewTreeGraphNode(ObjectGraphNode objectGraphNode)
{
var newGraphNode = TreeGraphNode.Create(this.layoutDirection, objectGraphNode);
newGraphNode.HorizontalMargin = horizNodeMargin;
newGraphNode.VerticalMargin = vertNodeMargin;
return newGraphNode;
}
/// <summary>
/// Given SubtreeSize for each node, positions the nodes, in a left-to-right or top-to-bottom fashion.
/// </summary>
/// <param name="node"></param>
/// <param name="lateralStart"></param>
/// <param name="mainStart"></param>
private void calculateNodePosRecursive(TreeGraphNode node, double lateralStart, double mainStart)
private void CalculateNodePosRecursive(TreeGraphNode node, double lateralStart, double mainStart)
{
double childsSubtreeSize = node.Childs.Sum(child => child.SubtreeSize);
// center this node
double center = node.ChildEdges.Count() == 0 ? 0 : 0.5 * (childsSubtreeSize - (node.LateralSizeWithMargin));
if (center < 0)
{
if (center < 0) {
// if root is larger than subtree, it would be shifted below lateralStart
// -> make whole layout start at lateralStart
lateralStart -= center;
@ -155,9 +128,8 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -155,9 +128,8 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
double childLateral = lateralStart;
double childsMainFixed = node.MainCoord + node.MainSizeWithMargin;
foreach (TreeGraphNode child in node.Childs)
{
calculateNodePosRecursive(child, childLateral, childsMainFixed);
foreach (TreeGraphNode child in node.Childs) {
CalculateNodePosRecursive(child, childLateral, childsMainFixed);
childLateral += child.SubtreeSize;
}
}

3
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/NodeControlCache.cs

@ -25,7 +25,8 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -25,7 +25,8 @@ namespace Debugger.AddIn.Visualizers.Graph
public void ReturnForReuse(PositionedGraphNodeControl controlToReuse)
{
controls.Push(controlToReuse);
// not used now, avoid leaking!
//controls.Push(controlToReuse);
}
public PositionedGraphNodeControl GetNodeControl()

Loading…
Cancel
Save