public void ClickNode(NodeModel node)
        {
            if (!CtrlDown)
            {
                FocusedNodes.ForEach(n => n.Focused = false);
                FocusedNodes.Clear();
            }

            if (node == null)
                return;

            else if (node.Focused && CtrlDown)
            {
                node.Focused = false;

                FocusedNodes.Remove(node);
            }

            else
            {
                node.Focused = true;

                FocusedNodes.Add(node);

                MainUI.NavigatePanelTo(node);
            }

            DoRedraw = true;
            Renderer.ViewInvalidate();
        }
Beispiel #2
0
 public void DrawNode(Color color, RectangleF area, bool outside, NodeModel node, int depth)
 {
     if (outside)
         CurrentBuffer.FillPolygon(GetBrush(color), GetTriangleFromRect(area));
     else
         CurrentBuffer.FillRectangle(GetBrush(color), area);
 }
Beispiel #3
0
        public void DrawCallLine(Color color, int lineWidth, PointF start, PointF end, bool dashed, NodeModel source, NodeModel destination)
        {
            var pen = GetPen(color, lineWidth, dashed);

            if(dashed)
                pen.DashOffset = XRay.DashOffset * 3;

            CurrentBuffer.DrawLine(pen, start, end);
        }
Beispiel #4
0
        internal void AddIntermediateDependency(NodeModel sub)
        {
            if (DependencyChainOut == null)
                DependencyChainOut = new Dictionary<int, NodeModel>();
            DependencyChainOut[sub.ID] = sub;

            if (sub.DependencyChainIn == null)
                sub.DependencyChainIn = new Dictionary<int, NodeModel>();
            sub.DependencyChainIn[ID] = this;
        }
        public GraphSet(ViewModel model, NodeModel root, NodeModel container=null, int depth = -1)
        {
            Model = model;
            GraphMode = Model.GraphMode;
            GraphContainer = container;

            // iternate nodes at this zoom level
            if (GraphMode == CallGraphMode.Intermediates)
            {
                AddDependencyNodes();
            }

            else if (GraphMode == CallGraphMode.Layers)
            {
                foreach (var child in root.Nodes)
                    AddCalledNodes(child, true, 0);
            }

            else
            {
                AddCalledNodes(root, true, depth);

                if (GraphContainer == null)
                {
                    if (Model.ShowOutside || CenterMap.Count == 1) // prevent blank screen
                        AddCalledNodes(Model.InternalRoot, false);

                    if (Model.ShowExternal)
                        AddCalledNodes(Model.ExternalRoot, false);
                }
            }

            // process subsets before building graphs so we can prune empty subset graphs
            if (GraphMode == CallGraphMode.Layers)
            {
                foreach (var child in root.Nodes)
                    Subsets[child.ID] = new GraphSet(Model, child, child);
            }

            else if (GraphMode == CallGraphMode.Class &&
                     Model.ShowMethods &&
                     GraphContainer == null)
            {
                foreach (var classNode in PositionMap.Values)
                    Subsets[classNode.ID] = new GraphSet(Model, classNode, classNode, 1);
            }

            if (PositionMap.Count > 0)
            {
                BuildGraphs();

                if (Graphs.Count > 0)
                    LayoutGraphs();
            }
        }
Beispiel #6
0
        public void DrawCallLine(Color color, int lineWidth, PointF start, PointF end, bool dashed, NodeModel source, NodeModel destination)
        {
            var lineRect = new RectangleF(Math.Min(start.X, end.X), Math.Min(start.Y, end.Y), Math.Abs(end.X - start.X), Math.Abs(end.Y - start.Y));
            if (!ClientRect.IntersectsWith(lineRect))
                return;

            var a = new Vector3(start.X, start.Y, 0);
            var b = new Vector3(end.X, end.Y, 0);

            VertexBuffer vbo = null;

            if (!dashed)
                vbo = GetLineVbo(CallLines, lineWidth);
            else
                vbo = GetLineVbo(DashedCallLines, lineWidth);

            vbo.AddVerticies(color, Normal, a, b);
        }
        private void TestHovered(NodeModel node, Point loc)
        {
            if (!node.Show || !node.AreaF.Contains(loc.X, loc.Y))
                return;

            node.Hovered = true;
            GuiHovered.Add(node);

            foreach (var sub in node.Nodes)
                TestHovered(sub, loc);
        }
        public ViewModel(IMainUI mainUI, IColorProfile xColors)
        {
            MainUI = mainUI;
            XColors = xColors;

            NodeModels = new NodeModel[XRay.Nodes.Length];
            foreach (var node in XRay.Nodes)
                NodeModels[node.ID] = new NodeModel(this, XRay.Nodes[node.ID]);

            foreach (var uiNode in NodeModels)
            {
                if(uiNode.XNode.Parent != null)
                    uiNode.Parent = NodeModels[uiNode.XNode.Parent.ID];

                foreach (var subnode in uiNode.XNode.Nodes)
                    uiNode.Nodes.Add(NodeModels[subnode.ID]);
            }

            TopRoot =      NodeModels[XRay.RootNode.ID];
            InternalRoot = TopRoot.Nodes.First(n => n.ObjType == XObjType.Internal);
            ExternalRoot = TopRoot.Nodes.First(n => n.ObjType == XObjType.External);
            CurrentRoot =  InternalRoot;
        }
        public void RecalcCover(NodeModel root, bool rootShow=true)
        {
            root.Value = 0;
            root.SecondaryValue = 0;

            // if a leaf node - method or field
            if (root.ObjType == XObjType.Method || root.ObjType == XObjType.Field)
            {
                if (TwoDimensionalValues)
                {
                    root.Value = GetValueForLayout(root, SizeLayouts.Constant);
                    root.SecondaryValue = GetValueForLayout(root, SizeLayout);

                    if (root.SecondaryValue > MaxSecondaryValue)
                        MaxSecondaryValue = root.SecondaryValue;
                }
                else
                    root.Value = GetValueForLayout(root, SizeLayout);

                if ((ShowLayout == ShowNodes.Hit && !XRay.CoveredNodes[root.ID]) ||
                    (ShowLayout == ShowNodes.Unhit && XRay.CoveredNodes[root.ID]))
                    root.Value = 0;

                // processs subnodes because methods/fields can have anon sub classes
            }

            foreach (var node in root.Nodes)
            {
                bool nodeShow = rootShow;

                // show can only be set to false
                if (nodeShow)
                {
                    nodeShow =
                        ShowLayout == ShowNodes.All ||
                        ShowLayout == ShowNodes.Hit ||
                        ShowLayout == ShowNodes.Unhit ||
                        (ShowLayout == ShowNodes.Instances && (node.ObjType != XObjType.Class || (node.XNode.Record != null && node.XNode.Record.Created > 0)));

                    if ((node.ObjType == XObjType.Field && !ShowFields) ||
                        (node.ObjType == XObjType.Method && !ShowMethods) ||
                        (node.XNode.IsAnon && !ShowAnon))
                        nodeShow = false;

                    if (ShowThreads != null &&
                        (node.ObjType == XObjType.Method || node.ObjType == XObjType.Field) &&
                        (node.XNode.ThreadIDs == null || !node.XNode.ThreadIDs.Any(id => ShowThreads.Contains(id))))
                        nodeShow = false;
                }

                RecalcCover(node, nodeShow);

                // if filtering on threads, dont show empty classes in the class graph
                if (ShowThreads != null &&
                    (node.ObjType != XObjType.Method && node.ObjType != XObjType.Field) &&
                    node.Nodes.All(n => !n.Show))
                    nodeShow = false;

                if (nodeShow)
                {
                    root.Value += node.Value;
                    root.SecondaryValue += node.SecondaryValue;

                    if (node.Value == 0)
                    {
                        nodeShow = false;
                        Utilities.RecurseTree(node, n => n.Show = false, n => n.Nodes);
                    }
                }

                node.Show = nodeShow;
            }

            // when hide field/methods selected and user is viewing treemap - just show class map
            // make sure class graph still shows up with field/methods unselected
            // when show fields/methods is on we still want to hide certain classes that are filtered by thread for instance
            if (root.Value == 0 && !ShowFields && !ShowMethods &&
                (root.ObjType != XObjType.Method && root.ObjType != XObjType.Field) &&
                (ViewLayout == LayoutType.TreeMap ||
                 (ViewLayout == LayoutType.CallGraph && GraphMode != CallGraphMode.Method)))
            {
                root.Value = 1;
                // on return to calling function causes root.show = true
            }

            if (ViewLayout == LayoutType.CallGraph && SizeLayout == SizeLayouts.Constant)
                root.Value = 1;

            //XRay.LogError("Calc'd Node: {0}, Value: {1}", root.Name, root.Value);

            //Debug.Assert(root.Value >= 0);
        }
Beispiel #10
0
        public void DrawNodeLabel(string text, Font font, Color color, RectangleF rect, NodeModel node, int depth)
        {
            if (!ClientRect.IntersectsWith(rect))
                return;

            QFont qfont = GetQFont(font);

            qfont.PrintToVBO(text, QFontAlignment.Left, new Vector3(rect.X, rect.Y, 0), color, rect.Size);
        }
Beispiel #11
0
        public CallItem(FunctionCall call, NodeModel node, bool perCall)
        {
            Call = call;
            Node = node;
            Text = node.AppendClassName();

            if (call == null)
                return;

            if (call.StillInside > 0 )
                Text += " (" + call.StillInside.ToString() + " Still Inside)";

            SubItems.Add(call.TotalHits.ToString());

            Hits = call.TotalHits;
            Inside = call.TotalTimeInsideDest;
            Outside = call.TotalTimeOutsideDest;

            if (Hits == 0)
                return;

            if (perCall)
            {
                Inside /= Hits;
                Outside /= Hits;
            }

            SubItems.Add(Utilities.TicksToString(Inside));
            SubItems.Add(Utilities.TicksToString(Outside));

            Total = Inside + Outside;

            // show last cal info
            string callInfo = "";

            try
            {
                var lastParams = call.LastParameters;
                if (lastParams != null)
                    callInfo += "Params: " + string.Join(", ", lastParams.Select(p => (p == null) ? "<null>" : p.ToString()).ToArray());
            }
            catch (Exception x)
            {
                throw new Exception("AAA");
            }

            object lastReturnValue = null;
            try
            {
                lastReturnValue = call.LastReturnValue; // avoid thread from changing value out from under us

            }
            catch (Exception x)
            {
                throw new Exception("b1" + x.Message);
            }

            try
            {

                if (lastReturnValue != null)
                    callInfo += " Return: ";
            }
            catch (Exception x)
            {
                throw new Exception("b2" + x.Message);
            }

            try
            {

                if (lastReturnValue != null)
                    callInfo += lastReturnValue.ToString();
            }
            catch (Exception x)
            {
                throw new Exception("b3" + x.Message);
            }
            SubItems.Add(callInfo);
        }
        private float AvgPos(NodeModel node)
        {
            float sum = 0;
            float count = 0;

            if (node.EdgesOut != null)
                foreach (var destId in node.EdgesOut)
                    if (PositionMap.ContainsKey(destId))
                    {
                        if (node.Intermediates != null && node.Intermediates.ContainsKey(destId))
                            sum += node.Intermediates[destId][0].ScaledLocation.Y;
                        else
                            sum += PositionMap[destId].ScaledLocation.Y;

                        count++;
                    }

            if (node.EdgesIn != null)
                foreach (var source in node.EdgesIn)
                    if (PositionMap.ContainsKey(source))
                    {
                        var sourceNode = PositionMap[source];
                        if (sourceNode.Intermediates != null && sourceNode.Intermediates.ContainsKey(node.ID))
                            sum += sourceNode.Intermediates[node.ID].Last().ScaledLocation.Y;
                        else
                            sum += PositionMap[source].ScaledLocation.Y;

                        count++;
                    }

            // should only be attached to intermediate nodes
            if (node.Adjacents != null)
            {
                Debug.Assert(node.ID == 0); // adjacents should only be on temp nodes

                foreach (var adj in node.Adjacents)
                {
                    sum += adj.ScaledLocation.Y;
                    count++;
                }
            }

            if (count == 0)
                return node.ScaledLocation.Y;

            return sum / count;
        }
        private void AddEdges(NodeModel node, bool center, IEnumerable<int> callsIn, IEnumerable<int> callsOut)
        {
            if (center ||
                ((callsIn != null && callsIn.Any(source => CenterMap.Contains(source))) ||
                 (callsOut != null && callsOut.Any(dest => CenterMap.Contains(dest)))))
            {
                PositionMap[node.ID] = node;

                if(center)
                    CenterMap.Add(node.ID);

                node.EdgesIn = (callsIn != null) ? callsIn.ToArray() : null;
                node.EdgesOut = (callsOut != null) ? callsOut.ToArray() : null;
            }
        }
        public void DrawCallLine(Color color, int lineWidth, PointF start, PointF end, bool live, NodeModel source, NodeModel destination)
        {
            float height = live ? LiveCallHeight : CallHeight;

            var a = new Vector3(start.X, height, start.Y);
            var b = new Vector3(end.X, height, end.Y);

            var vbo = GetLineVbo(live ? DashedCallLines : CallLines, lineWidth * 2);

            var normal = new Vector3();

            vbo.AddVerticies(color, normal, a, b);
        }
        public void NavigateTo(NodeModel node)
        {
            if (node.ObjType == XObjType.Class)
            {
                SelectedNode = node;
                FieldFilter = null;
                SummaryLabel.Text = node.Name;
                SummaryLabel.ForeColor = ColorProfile.ClassColor;
                FieldsRadioButton.Visible = true;
                MethodsRadioButton.Visible = true;
            }
            else if (node.ObjType == XObjType.Field)
            {
                SelectedNode = node.GetParentClass(false);
                FieldFilter = node.XNode.UnformattedName;
                SummaryLabel.Text = node.Name;
                SummaryLabel.ForeColor = ColorProfile.FieldColor;
                FieldsRadioButton.Visible = false;
                MethodsRadioButton.Visible = false;
                FieldsRadioButton.Checked = true;
            }
            else
            {
                SummaryLabel.Text = "";
                return;
            }

            Model = new InstanceModel(SelectedNode.XNode, FieldFilter, GridModel_UpdateTree, GridModel_ExpandedField);

            XRay.UIs[Thread.CurrentThread.ManagedThreadId].CurrentInstance = Model;

            if (!Visible)
                return;

            CurrentDisplay = SelectedNode;

            FieldGrid.Nodes.Clear();
            FieldGrid.Columns.Clear();

            ModelRowMap = new Dictionary<int, FieldRow>();

            Model.BeginUpdateTree(false);

            RefreshSubnodesView();
        }
        public void DrawNodeOutline(Color color, int lineWidth, RectangleF area, bool outside, NodeModel node, int depth)
        {
            float x = area.X, z = area.Y, width = area.Width, length = area.Height;

            float floor  = depth * LevelSize;
            float height = GetNodeHeight(node);

            if (outside)
            {
                DrawPyramidOutline(color, lineWidth, x, z, width, length, floor, height);
            }
            else
            {
                DrawBoxOutline(color, lineWidth, x, z, width, length, floor, height);
            }
        }
        private void BuildGraphs()
        {
            foreach (var node in PositionMap.Values)
                node.Rank = null;

            do
            {
                // group nodes into connected graphs
                var graph = new Dictionary<int, NodeModel>();

                // add first unranked node to a graph
                var unrankedNode = PositionMap.Values.First(n => n.Rank == null);

                LayoutGraph(graph, unrankedNode, 0, new List<int>());

                // while group contains unranked nodes
                while (graph.Values.Any(n => n.Rank == null && n.EdgesOut != null))
                {
                    // head node to start traversal
                    unrankedNode = graph.Values.First(n => n.Rank == null && n.EdgesOut != null);

                    // only way node could be in group is if child added it, so there is a minrank
                    // min rank is 1 back from the lowest ranked child of the node
                    int? minRank = unrankedNode.EdgesOut.Min(dest =>
                    {
                        if (PositionMap.ContainsKey(dest))
                        {
                            var destNode = PositionMap[dest];
                            if (destNode.Rank.HasValue)
                                return destNode.Rank.Value;
                        }

                        return int.MaxValue;
                    });

                    LayoutGraph(graph, unrankedNode, minRank.Value - 1, new List<int>());
                }

                // remove graphs with 1 element
                if (graph.Count == 1)
                {
                    bool remove = false;
                    var onlyNode = graph.First().Value;

                    if (GraphMode == CallGraphMode.Dependencies || GraphMode == CallGraphMode.Method)
                        remove = true;

                    if(GraphMode == CallGraphMode.Class || GraphMode == CallGraphMode.Layers)
                    {
                        // dont remove method/field if alone as a graph because it may be still connect to other classes
                        if (onlyNode.ObjType == XObjType.Method || onlyNode.ObjType == XObjType.Field)
                        {
                            // in class mode edges between nodes set dynamically, in layers mode edges are based on calls
                            if ((GraphMode == CallGraphMode.Layers && onlyNode.XNode.CalledIn == null && onlyNode.XNode.CallsOut == null) ||
                                (GraphMode == CallGraphMode.Class && onlyNode.EdgesIn == null && onlyNode.EdgesOut == null))
                                remove = true;
                        }
                        // remove empty lonesome classes
                        else if (onlyNode.ObjType == XObjType.Class && !Model.ShowMethods && !Model.ShowFields)
                            remove = true;

                        // if node is by lonesome and has no sub-graphs inside of it
                        else if (Subsets.ContainsKey(onlyNode.ID) && Subsets[onlyNode.ID].Graphs.Count == 0)
                            remove = true;
                    }

                    if(remove)
                    {
                        PositionMap.Remove(onlyNode.ID);
                        CenterMap.Remove(onlyNode.ID);
                        continue;
                    }
                }

                // normalize ranks so sequential without any missing between
                int nextSequentialRank = -1;
                int currentRank = int.MinValue;
                foreach (var n in graph.Values.OrderBy(v => v.Rank))
                {
                    if (n.Rank != currentRank)
                    {
                        currentRank = n.Rank.Value;
                        nextSequentialRank++;
                    }

                    n.Rank = nextSequentialRank;
                }

                // put all nodes into a rank based multi-map
                Rank[] ranks = new Rank[nextSequentialRank + 1];
                for (int i = 0; i < ranks.Length; i++)
                    ranks[i] = new Rank();

                long graphWeight = 0;

                foreach (var source in graph.Values)
                {
                    graphWeight += source.Value;

                    ranks[source.Rank.Value].Column.Add(source);

                    if (source.EdgesOut == null)
                        continue;

                    foreach (var destId in source.EdgesOut)
                    {
                        if (!graph.ContainsKey(destId))
                            continue;

                        var destination = graph[destId];

                        // ranks are equal if nodes are outside zoom
                        if (source.ID == destination.ID || destination.Rank == source.Rank)
                            continue;

                        if (source.Intermediates != null)
                            source.Intermediates.Remove(destId);

                        // if destination is not 1 forward/1 back then create intermediate nodes
                        if (source.Rank != destination.Rank + 1 &&
                            source.Rank != destination.Rank - 1)
                        {
                            if (source.Intermediates == null)
                                source.Intermediates = new Dictionary<int, List<NodeModel>>();

                            source.Intermediates[destId] = new List<NodeModel>();

                            bool increase = destination.Rank > source.Rank;
                            int nextRank = increase ? source.Rank.Value + 1 : source.Rank.Value - 1;
                            var lastNode = source;

                            while (nextRank != destination.Rank)
                            {

                                // create new node
                                var intermediate = new NodeModel(Model);
                                intermediate.Rank = nextRank;
                                intermediate.Value = 10; // todo make smarter -
                                intermediate.Adjacents = new List<NodeModel>();

                                // add forward node to prev
                                if (lastNode != source)
                                    lastNode.Adjacents.Add(intermediate);

                                // add back node to curr
                                intermediate.Adjacents.Add(lastNode);

                                // add to temp path, rank map
                                source.Intermediates[destId].Add(intermediate);
                                ranks[nextRank].Column.Add(intermediate);
                                //PositionMap not needed because we dont need any mouse over events? just follow along and draw from list, not id

                                lastNode = intermediate;
                                nextRank = increase ? nextRank + 1 : nextRank - 1;
                            }

                            try
                            {
                                lastNode.Adjacents.Add(destination);
                                source.Intermediates[destId].Add(destination);
                            }
                            catch
                            {
                                System.IO.File.WriteAllText("debugX.txt", string.Format("{0}\r\n{1}\r\n", source.Rank, destination.Rank));

                                throw new Exception("wtf");
                            }
                        }
                    }
                }

                Graphs.Add(new Graph() { Ranks = ranks, Weight = graphWeight });

            } while (PositionMap.Values.Any(n => n.Rank == null));
        }
Beispiel #18
0
        public void NavigateTo(NodeModel node)
        {
            SelectedNode = node;

            Reload();
        }
 private float GetDistanceY(NodeModel other_node, NodeModel node)
 {
     return Math.Abs(other_node.ScaledLocation.Y - node.ScaledLocation.Y);
 }
Beispiel #20
0
        public void DrawNodeOutline(Color color, int lineWidth, RectangleF area, bool outside, NodeModel node, int depth)
        {
            if (!ClientRect.IntersectsWith(area))
                return;

            float x = area.X, y = area.Y, width = area.Width, height = area.Height;

            var vbo = GetLineVbo(Outlines, lineWidth);

            if (outside)
            {
                var v1 = new Vector3(area.X, area.Y + area.Height, 0);
                var v2 = new Vector3(area.X + area.Width / 2f, area.Y, 0);
                var v3 = new Vector3(area.X + area.Width, area.Y + area.Height, 0);

                vbo.AddVerticies(color, Normal, v1, v2, v2, v3, v3, v1);
            }
            else
            {
                var v1 = new Vector3(x, y, 0);
                var v2 = new Vector3(x + width, y, 0);
                var v3 = new Vector3(x + width, y + height, 0);
                var v4 = new Vector3(x, y + height, 0);

                vbo.AddVerticies(color, Normal, v1, v2, v2, v3, v3, v4, v4, v1);
            }
        }
        /*
        flow through entire list of children first
            keep track of node parents
                if any unranked parents at end of child run
                    look at all of parents children, give rank of 1 - lowest ranked child
                        re-run alg on that parent

            this way we start with first (entry) node, run through linearly from that, and tack on alternate parents later
                works great for application call graph, and for general graphs as well
         */
        private void LayoutGraph(Dictionary<int, NodeModel> graph, NodeModel node, int minRank, List<int> parents)
        {
            //debugLog.Add(string.Format("Entered Node ID {0} rank {1}", ID, Rank));

            // node already ranked correctly, no need to re-rank subordinates
            if (node.Rank != null && node.Rank.Value >= minRank)
                return;

            int? prevRank = node.Rank;

            // only increase rank
            Debug.Assert(node.Rank == null || minRank > node.Rank.Value);
            node.Rank = minRank;

            //debugLog.Add(string.Format("Node ID {0} rank set from {1} to {2}", ID, prevRank, Rank));

            parents.Add(node.ID);
            graph[node.ID] = node;

            if (node.EdgesOut != null)
                foreach (var destId in node.EdgesOut)
                {
                    if (parents.Contains(destId))
                    {
                        // destination rank should be less than source
                        //Debug.Assert(edge.Destination.Rank < edge.Source.Rank);

                        //debugLog.Add(string.Format("Switching edge {0} -> {1}, rank {2} -> {3}", ID, edge.Destination.ID, Rank, edge.Destination.Rank));

                        //edge.Source = edge.Destination;
                        //edge.Destination = this;
                        //edge.Reversed = !edge.Reversed;

                        continue;
                    }

                    // pass copy of parents list so that sub can add elemenets without affecting next iteration
                    //debugLog.Add(string.Format("Traversing to child {0} -> {1}, rank {2} -> {3}", ID, edge.Destination.ID, Rank, edge.Destination.Rank));

                    if (PositionMap.ContainsKey(destId))
                    {
                        var target = PositionMap[destId];

                        LayoutGraph(graph, target, node.Rank.Value + 1, parents.ToList());//, debugLog);
                    }
                    //debugLog.Add(string.Format("Return to node {0} rank {1}", ID, Rank));
                }

            // record so later group can be traversed for null ranked members (parents) so layout can be run on them
            if (node.EdgesIn != null)
                foreach (var source in node.EdgesIn)
                    if (PositionMap.ContainsKey(source))
                        graph[source] = PositionMap[source];

            // check if same edges down go back up and create intermediates in that case?

            //debugLog.Add(string.Format("Exited Node ID {0} rank {1}", ID, Rank));
        }
Beispiel #22
0
        public void DrawNode(Color color, RectangleF area, bool outside, NodeModel node, int depth)
        {
            if (!ClientRect.IntersectsWith(area))
                return;

            var verticies = outside ? GetTriangleVerticies(area) : GetRectVerticies(area);

            Nodes.AddVerticies(color, Normal, verticies);
        }
        public void DrawCallLine(Color color, int lineWidth, PointF start, PointF end, bool live, NodeModel source, NodeModel destination)
        {
            float height = live ? LiveCallHeight : CallHeight;

            var a = new Vector3(start.X, height, start.Y);
            var b = new Vector3(end.X, height, end.Y);

            var vbo = GetLineVbo(live ? DashedCallLines : CallLines, lineWidth * 2);

            var normal = new Vector3();

            vbo.AddVerticies(color, normal, a, b);
        }
        private long GetValueForLayout(NodeModel root, SizeLayouts layout)
        {
            long value = 0;

            switch (layout)
            {
                case SizeLayouts.Constant:
                    value = 1;
                    break;
                case SizeLayouts.MethodSize:
                    value = root.XNode.Lines;
                    break;
                case SizeLayouts.TimeInMethod:
                    // why is this negetive?? HAVENT RETURNED YET, property should return 0 i think if  neg, or detect still inside and return that
                    if (root.XNode.CalledIn != null)
                        foreach (FunctionCall call in root.XNode.CalledIn)
                            value += call.TotalTimeInsideDest;
                    break;
                case SizeLayouts.Hits:
                    if (root.XNode.CalledIn != null)
                        foreach (FunctionCall call in root.XNode.CalledIn)
                            value += call.TotalHits;
                    break;
                case SizeLayouts.TimePerHit:
                    if (root.XNode.CalledIn != null)
                    {
                        int count = 0;

                        foreach (FunctionCall call in root.XNode.CalledIn)
                            if (call.TotalHits > 0)
                            {
                                count++;
                                value += call.TotalTimeInsideDest / call.TotalHits;
                            }

                        if (count > 0)
                            value /= count;
                    }

                    break;
            }

            return value;
        }
        public void DrawNode(Color color, RectangleF area, bool outside, NodeModel node, int depth)
        {
            float x = area.X + 0.1f;
            float y = area.Y + 0.1f;
            float width = area.Width - 0.2f;
            float length = area.Height - 0.2f;
            float bottom = depth * LevelSize + 0.1f;
            float height = GetNodeHeight(node) - 0.2f;

            if (SelectionMode != SelectionModes.None)
            {
                SelectionMap[node.ID] = node;
                color = Color.FromArgb((255 << 24) | node.ID);
            }

            if (outside)
                DrawPyramid(color, x, y, width, length, bottom, height);
            else
                GLUtils.DrawCube(Nodes, color, x, y, width, length, bottom, height);
        }
        public void SetRoot(NodeModel node, bool logHistory = true)
        {
            if (node == null)
                return;

            // setting internal root will auto show properly sized external root area if showing it is enabled
            ResetZoom();
            CurrentRoot = (node == TopRoot) ? InternalRoot : node;

            if (logHistory)
            {
                // re-write forward log with new node
                while (CurrentHistory != HistoryList.Last)
                    HistoryList.RemoveLast();

                // dont set node if last node is already this
                var last = HistoryList.LastOrDefault();
                if (CurrentRoot != last)
                {
                    HistoryList.AddLast(CurrentRoot);
                    CurrentHistory = HistoryList.Last;
                }
            }

            MainUI.UpdateBreadCrumbs();

            DoRevalue = true;
            Renderer.ViewInvalidate();
        }
        public void DrawNodeLabel(string text, Font font, Color color, RectangleF rect, NodeModel node, int depth)
        {
            QFont qfont = GetQFont(font);

            float height = LabelHeight;
            if(Model.ViewLayout == LayoutType.TreeMap)
                height = depth * LevelSize + GetNodeHeight(node); // put over call lines

            if (SelectionMode != SelectionModes.None)
            {
                SelectionMap[node.ID] = node;
                color = Color.FromArgb((255 << 24) | node.ID);

                var textArea = qfont.Measure(text, rect.Size, QFontAlignment.Left);

                var normal = new Vector3(0, 1, 0);
                var v1 = new Vector3(rect.X, height, rect.Y);
                var v2 = new Vector3(rect.X, height, rect.Y + textArea.Height);
                var v3 = new Vector3(rect.X + textArea.Width, height, rect.Y + textArea.Height);
                var v4 = new Vector3(rect.X + textArea.Width, height, rect.Y);

                Nodes.AddVerticies(color, normal, v1, v2, v3, v1, v3, v4);
            }
            else
                qfont.PrintToVBO(text, QFontAlignment.Left, new Vector3(rect.X, rect.Y, -height), color, rect.Size);
        }
        private void AddNodeToHovered(NodeModel node)
        {
            GuiHovered.Add(node);
            var parent = node.Parent;

            while (parent != null)
            {
                GuiHovered.Add(parent);
                parent = parent.Parent;
            }

            GuiHovered.Reverse();
        }
        public void DrawNodeOutline(Color color, int lineWidth, RectangleF area, bool outside, NodeModel node, int depth)
        {
            float x = area.X, z = area.Y, width = area.Width, length = area.Height;

            float floor = depth * LevelSize;
            float height = GetNodeHeight(node);

            if(outside)
                DrawPyramidOutline(color, lineWidth, x, z, width, length, floor, height);
            else
                DrawBoxOutline(color, lineWidth, x, z, width, length, floor, height);
        }
        void ToggleNode(HashSet<int> map, NodeModel node)
        {
            // make sure a node cant be selected and ignored simultaneously
            if (map != IgnoredNodes && IgnoredNodes.Contains(node.ID))
                IgnoredNodes.Remove(node.ID);

            if (map != FilteredNodes && FilteredNodes.Contains(node.ID))
                FilteredNodes.Remove(node.ID);

            // toggle the setting of the node in the map
            if (map.Contains(node.ID))
                map.Remove(node.ID);
            else
                map.Add(node.ID);

            DoRedraw = true;
            Renderer.ViewInvalidate();
        }
 float GetNodeHeight(NodeModel node)
 {
     if (node.ObjType == XObjType.Method)
         return Math.Max(100f * (float)node.SecondaryValue / (float)Model.MaxSecondaryValue, LevelSize);
     else
         return LevelSize;
 }
        private void SizeNode(IRenderer Renderer, NodeModel root, NodeModel exclude, bool center)
        {
            if (!root.Show)
                return;

            RectangleF insideArea = root.AreaF;

            if (ShowLabels)
            {
                // check if enough room in root box for label
                var labelSpace = root.AreaF;
                labelSpace.Width -= LabelPadding * 2.0f;
                labelSpace.Height -= LabelPadding * 2.0f;

                var labelSize = new RectangleF(root.AreaF.Location, Renderer.MeasureString(root.Name, TextFont));
                float minHeight = (root.Nodes.Count > 0) ? labelSize.Height * 2.0f : labelSize.Height;

                if (minHeight < labelSpace.Height && labelSize.Width / 3f < labelSpace.Width)
                {
                    labelSize.X += LabelPadding;
                    labelSize.Y += LabelPadding;

                    if (labelSpace.Width < labelSize.Width)
                    {
                        root.LabelClipped = true;
                        labelSize.Width = labelSpace.Width;
                    }

                    insideArea.Y += labelSize.Height;
                    insideArea.Height -= labelSize.Height;

                    root.RoomForLabel = true;
                    root.LabelRect = labelSize;
                }
            }

            List<Sector> sectors = new TreeMap(root, exclude, insideArea.Size).Results;

            foreach (Sector sector in sectors)
            {
                var node = sector.OriginalValue;

                sector.Rect = RectangleExtensions.Contract(sector.Rect, NodeBorderWidth);

                if (sector.Rect.X < NodeBorderWidth) sector.Rect.X = NodeBorderWidth;
                if (sector.Rect.Y < NodeBorderWidth) sector.Rect.Y = NodeBorderWidth;
                if (sector.Rect.X > insideArea.Width - NodeBorderWidth) sector.Rect.X = insideArea.Width - NodeBorderWidth;
                if (sector.Rect.Y > insideArea.Height - NodeBorderWidth) sector.Rect.Y = insideArea.Height - NodeBorderWidth;

                sector.Rect.X += insideArea.X;
                sector.Rect.Y += insideArea.Y;

                node.SetArea(sector.Rect);
                PositionMap[node.ID] = node;

                node.RoomForLabel = false; // cant do above without graphic artifacts
                node.LabelClipped = false;

                if (center)
                    CenterMap.Add(node.ID);

                if (sector.Rect.Width > 1.0f && sector.Rect.Height > 1.0f)
                    SizeNode(Renderer, node, exclude, center);
            }
        }
        public void DrawNodeLabel(string text, Font font, Color color, RectangleF rect, NodeModel node, int depth)
        {
            QFont qfont = GetQFont(font);

            float height = LabelHeight;

            if (Model.ViewLayout == LayoutType.TreeMap)
            {
                height = depth * LevelSize + GetNodeHeight(node); // put over call lines
            }
            if (SelectionMode != SelectionModes.None)
            {
                SelectionMap[node.ID] = node;
                color = Color.FromArgb((255 << 24) | node.ID);

                var textArea = qfont.Measure(text, rect.Size, QFontAlignment.Left);

                var normal = new Vector3(0, 1, 0);
                var v1     = new Vector3(rect.X, height, rect.Y);
                var v2     = new Vector3(rect.X, height, rect.Y + textArea.Height);
                var v3     = new Vector3(rect.X + textArea.Width, height, rect.Y + textArea.Height);
                var v4     = new Vector3(rect.X + textArea.Width, height, rect.Y);

                Nodes.AddVerticies(color, normal, v1, v2, v3, v1, v3, v4);
            }
            else
            {
                qfont.PrintToVBO(text, QFontAlignment.Left, new Vector3(rect.X, rect.Y, -height), color, rect.Size);
            }
        }