private void DrawNode(NodeModel node, RectangleF area, RectangleF labelArea, int depth, bool drawChildren, bool showHit)
{
if (!node.Show)
return;
var xNode = node.XNode;
// set background of node base color
Color background = XColors.EmptyColor;
// if selcted
if (node.Hovered && ViewLayout == LayoutType.TreeMap)
{
if (depth > XColors.OverColors.Length - 1)
depth = XColors.OverColors.Length - 1;
background = XColors.OverColors[depth];
}
else if (ViewLayout != LayoutType.TreeMap && !CenterMap.Contains(node.ID))
background = XColors.OutsideColor;
// if no overlay, draw the border color as the entire node cause its very small
bool noBorder = area.Width < 3.0f || area.Height < 3.0f;
if (noBorder)
background = XColors.ObjColors[(int)node.ObjType];
Color overlay = XColors.EmptyColor;
if (showHit)
{
// check if function is an entry point or holding
if (XRay.FlowTracking && xNode.StillInside > 0)
GLUtils.BlendColors((xNode.EntryPoint > 0) ? XColors.EntryColor : XColors.HoldingColor, ref overlay);
// not an else if, draw over holding or entry
if (xNode.ExceptionHit > 0)
GLUtils.BlendColors(XColors.ExceptionColors[xNode.ExceptionHit], ref overlay);
else if (xNode.FunctionHit > 0)
{
if (node.ObjType == XObjType.Field)
{
if (xNode.LastFieldOp == FieldOp.Set)
GLUtils.BlendColors(XColors.FieldSetColors[xNode.FunctionHit], ref overlay);
else
GLUtils.BlendColors(XColors.FieldGetColors[xNode.FunctionHit], ref overlay);
}
else
GLUtils.BlendColors(XColors.HitColors[xNode.FunctionHit], ref overlay);
}
else if (xNode.ConstructedHit > 0)
GLUtils.BlendColors(XColors.ConstructedColors[xNode.ConstructedHit], ref overlay);
else if (xNode.DisposeHit > 0)
GLUtils.BlendColors(XColors.DisposedColors[xNode.DisposeHit], ref overlay);
}
if (FocusedNodes.Count > 0 && node.ObjType == XObjType.Class)
{
bool dependent = DependentClasses.Contains(node.ID);
bool independent = IndependentClasses.Contains(node.ID);
if (dependent && independent)
GLUtils.BlendColors(XColors.InterdependentColor, ref overlay);
else if (dependent)
GLUtils.BlendColors(XColors.DependentColor, ref overlay);
else if (independent)
GLUtils.BlendColors(XColors.IndependentColor, ref overlay);
}
if (node.SearchMatch && !SearchStrobe)
GLUtils.BlendColors(XColors.SearchMatchColor, ref overlay);
if (FilteredNodes.Contains(node.ID))
GLUtils.BlendColors(XColors.FilteredColor, ref overlay);
else if (IgnoredNodes.Contains(node.ID))
GLUtils.BlendColors(XColors.IgnoredColor, ref overlay);
// mix background with overlay
if (overlay != XColors.EmptyColor)
GLUtils.BlendColors(overlay, ref background);
// use a circle for external/outside nodes in the call map
bool outside = (ViewLayout == LayoutType.CallGraph && node.XNode.External);
// if just a point, drawing a border messes up pixels
if (noBorder && !DrawSubpixel)
{
Renderer.DrawNode(background, area, outside, node, depth);
}
else
{
Color pen = XColors.ObjColors[(int)node.ObjType];
if (FilteredNodes.Contains(node.ID))
pen = XColors.FilteredColor;
else if (IgnoredNodes.Contains(node.ID))
pen = XColors.IgnoredColor;
int penWidth = 1;
if (FocusedNodes.Contains(node))
penWidth = 2;
Renderer.DrawNode(background, area, outside, node, depth);
Renderer.DrawNodeOutline(pen, penWidth, area, outside, node, depth);
}
// draw label
//buffer.FillRectangle(SearchMatchBrush, node.DebugRect);
if (ShowLabels && node.RoomForLabel)
{
Renderer.DrawTextBackground(XColors.LabelBgColor, labelArea.X, labelArea.Y, labelArea.Width, labelArea.Height);
Renderer.DrawNodeLabel(node.Name, TextFont, XColors.ObjColors[(int)node.ObjType], labelArea, node, depth);
// draw code inside node
if(ShowCode && node.AreaF.Width > 50 && node.AreaF.Height > 50)
if (node.ObjType == XObjType.Method)
{
string code = node.XNode.GetMethodCode();
Renderer.DrawString(code, TextFont, XColors.CodeColor, node.AreaF.X + 5, node.AreaF.Y + labelArea.Height + 5, node.AreaF.Width - 10, node.AreaF.Height - 10 - labelArea.Height);
}
// draw field values inside node
else if (node.ObjType == XObjType.Field)
{
var summary = "";
foreach (var value in node.GetFieldValues())
summary += value + "\r\n";
Renderer.DrawString(summary, TextFont, XColors.CodeColor, node.AreaF.X + 5, node.AreaF.Y + labelArea.Height + 5, node.AreaF.Width - 10, node.AreaF.Height - 10 - labelArea.Height);
}
}
if (MapMode == TreeMapMode.Dependencies && node.ObjType == XObjType.Class)
drawChildren = false;
if (drawChildren && ((area.Width > 1 && area.Height > 1) || DrawSubpixel))
foreach (var sub in node.Nodes)
DrawNode(sub, depth + 1, drawChildren);
// after drawing children, draw instance tracking on top of it all
/*if (XRay.InstanceTracking && node.ObjType == XObjType.Class)
{
if (XRay.InstanceCount[node.ID] > 0)
{
string count = XRay.InstanceCount[node.ID].ToString();
Rectangle x = new Rectangle(node.Area.Location, buffer.MeasureString(count, InstanceFont).ToSize());
if (node.Area.Contains(x))
{
buffer.FillRectangle(NothingBrush, x);
buffer.DrawString(count, InstanceFont, InstanceBrush, node.Area.Location.X + 2, node.Area.Location.Y + 2);
}
}
}*/
}