DotNet 4.8.1 build of DotNetBar

This commit is contained in:
2025-02-07 10:35:23 -05:00
parent 33439b63a0
commit 6b0a5d60f4
2609 changed files with 989814 additions and 7 deletions

View File

@@ -0,0 +1,76 @@
using System;
using System.Drawing;
namespace DevComponents.Tree.Layout
{
/// <summary>
/// Class that is used to layout column header.
/// </summary>
internal class ColumnHeaderLayout
{
public ColumnHeaderLayout()
{
}
// Assumes that layoutInfo is up-to-date and that Node that is connected with
// columns is already processed and it's size and location calculated.
// layoutInfo.Top member reflects the next position below the node
// layoutInfo.LevelOffset should reflect the X offset for the child nodes.
public static int LayoutColumnHeader(NodeLayoutContextInfo layoutInfo,int x, int y, int clientWidth, int cellHorizontalSpacing)
{
Node node=layoutInfo.ContextNode;
int height=0;
foreach(ColumnHeader col in node.NodesColumns)
{
if(!col.Visible)
continue;
if(col.SizeChanged)
{
// Column for child nodes is always placed below the current node and
// is not included in the node's rectangle
Rectangle bounds=Rectangle.Empty;
bounds.X=x;
bounds.Y=y;
if(col.Width.Relative>0)
bounds.Width=(clientWidth*col.Width.Relative)/100-1;
else
bounds.Width=col.Width.Absolute;
if(col.StyleNormal=="" && col.StyleMouseDown=="" && col.StyleMouseOver=="")
{
bounds.Height=layoutInfo.DefaultHeaderSize.Height;
}
else
{
Size sz=Size.Empty;
if(col.StyleNormal!="")
{
ElementStyleLayout.CalculateStyleSize(layoutInfo.Styles[col.StyleNormal],layoutInfo.DefaultFont);
sz=layoutInfo.Styles[col.StyleNormal].Size;
}
if(sz.Height==0)
bounds.Height=layoutInfo.DefaultHeaderSize.Height;
else
bounds.Height=sz.Height;
}
col.SetBounds(bounds);
col.SizeChanged=false;
x+=(bounds.Width+cellHorizontalSpacing);
if(bounds.Height>height)
height=bounds.Height;
}
else if(col.Bounds.Height>height)
height=col.Bounds.Height;
}
return height;
}
}
}

View File

@@ -0,0 +1,608 @@
using System;
using System.Drawing;
namespace DevComponents.Tree
{
namespace Layout
{
/// <summary>
/// Represents class for Node's cell layout.
/// </summary>
internal class CellLayout
{
public CellLayout()
{
}
/// <summary>
/// Offset cell bounds, check box bounds, image bounds and text bounds by specified offset.
/// </summary>
/// <param name="cell">Cell to offset.</param>
/// <param name="x">Horizontal offset in pixels.</param>
/// <param name="y">Vertical offset in pixels.</param>
public void Offset(Cell cell, int x, int y)
{
cell.SetBounds(new Rectangle(cell.BoundsRelative.X+x,cell.BoundsRelative.Y+y,cell.BoundsRelative.Width,cell.BoundsRelative.Height));
if(!cell.CheckBoxBoundsRelative.IsEmpty)
cell.SetCheckBoxBounds(new Rectangle(cell.CheckBoxBoundsRelative.X+x,cell.CheckBoxBoundsRelative.Y+y,cell.CheckBoxBoundsRelative.Width,cell.CheckBoxBoundsRelative.Height));
if(!cell.ImageBoundsRelative.IsEmpty)
cell.SetImageBounds(new Rectangle(cell.ImageBoundsRelative.X+x,cell.ImageBoundsRelative.Y+y,cell.ImageBoundsRelative.Width,cell.ImageBoundsRelative.Height));
if(!cell.TextContentBounds.IsEmpty)
cell.TextContentBounds=new Rectangle(cell.TextContentBounds.X+x,cell.TextContentBounds.Y+y,cell.TextContentBounds.Width,cell.TextContentBounds.Height);
}
public void LayoutSingleCell(LayoutCellInfo info)
{
Size textSize=Size.Empty;
Font font=info.Font;
int height=0;
if(info.LayoutStyle.Font!=null)
font=info.LayoutStyle.Font;
info.ContextCell.OnLayoutCell();
Size largestImageSize = Dpi.Size(info.ContextCell.Images.LargestImageSize);
if(info.ContextCell.HostedControl!=null)
{
Size controlSize=info.ContextCell.HostedControl.Size;
if(!info.ContextCell.HostedControlSize.IsEmpty)
controlSize = info.ContextCell.HostedControlSize;
if(info.CellWidth==0)
textSize=new Size(controlSize.Width,controlSize.Height);
else
{
int availTextWidth=info.CellWidth-
ElementStyleLayout.HorizontalStyleWhiteSpace(info.LayoutStyle);
textSize=new Size(availTextWidth,controlSize.Height);
}
}
else
{
// Calculate Text Width and Height
if(info.CellWidth==0)
{
if (info.ContextCell.TextMarkupBody == null)
{
string text=info.ContextCell.Text;
if(text!="")
{
if(info.LayoutStyle.WordWrap && info.LayoutStyle.MaximumWidth>0)
textSize=TextDrawing.MeasureString(info.Graphics, text, font, info.LayoutStyle.MaximumWidth);
else if(info.ContextCell.Parent!=null && info.ContextCell.Parent.Style!=null && info.ContextCell.Parent.Style.WordWrap && info.ContextCell.Parent.Style.MaximumWidth>0)
textSize=TextDrawing.MeasureString(info.Graphics, text, font, info.ContextCell.Parent.Style.MaximumWidth);
else
textSize=TextDrawing.MeasureString(info.Graphics, text, font);
}
}
else
{
Size availSize = new Size(1600, 1);
if(info.LayoutStyle.WordWrap && info.LayoutStyle.MaximumWidth>0)
availSize.Width = info.LayoutStyle.MaximumWidth;
else if(info.ContextCell.Parent!=null && info.ContextCell.Parent.Style!=null && info.ContextCell.Parent.Style.WordWrap && info.ContextCell.Parent.Style.MaximumWidth>0)
availSize.Width = info.ContextCell.Parent.Style.MaximumWidth;
TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(info.Graphics, font, Color.Empty, false);
info.ContextCell.TextMarkupBody.Measure(availSize, d);
availSize = info.ContextCell.TextMarkupBody.Bounds.Size;
d.RightToLeft = !info.LeftToRight;
info.ContextCell.TextMarkupBody.Arrange(new Rectangle(0, 0, availSize.Width, availSize.Height), d);
textSize = info.ContextCell.TextMarkupBody.Bounds.Size;
}
}
else
{
int availTextWidth=info.CellWidth-
ElementStyleLayout.HorizontalStyleWhiteSpace(info.LayoutStyle);
availTextWidth-=largestImageSize.Width;
if(info.ContextCell.CheckBoxVisible)
availTextWidth-=CheckBoxSize.Width;
int cellHeight=font.Height;
if(info.LayoutStyle.WordWrap)
{
cellHeight=info.LayoutStyle.MaximumHeight-info.LayoutStyle.MarginTop-
info.LayoutStyle.MarginBottom-info.LayoutStyle.PaddingTop-info.LayoutStyle.PaddingBottom;
if (info.ContextCell.TextMarkupBody == null)
{
if(availTextWidth>0)
{
if(cellHeight>0)
textSize=TextDrawing.MeasureString(info.Graphics, info.ContextCell.Text,font,new Size(availTextWidth,cellHeight),info.LayoutStyle.TextFormat);
else
textSize=TextDrawing.MeasureString(info.Graphics, info.ContextCell.Text, font, availTextWidth, info.LayoutStyle.TextFormat);
}
}
else
{
Size availSize = new Size(availTextWidth, 1);
TextMarkup.MarkupDrawContext d = new TextMarkup.MarkupDrawContext(info.Graphics, font, Color.Empty, false);
info.ContextCell.TextMarkupBody.Measure(availSize, d);
availSize = info.ContextCell.TextMarkupBody.Bounds.Size;
availSize.Width = availTextWidth;
d.RightToLeft = !info.LeftToRight;
info.ContextCell.TextMarkupBody.Arrange(new Rectangle(0, 0, availSize.Width, availSize.Height), d);
textSize = info.ContextCell.TextMarkupBody.Bounds.Size;
}
}
else
textSize=new Size(availTextWidth,cellHeight);
}
}
if(info.LayoutStyle.WordWrap)
info.ContextCell.WordWrap=true;
else
info.ContextCell.WordWrap=false;
height=(int)Math.Ceiling((double)textSize.Height);
if(info.VerticalPartAlignment)
{
if(largestImageSize.Height>0)
height+=largestImageSize.Height;
if(info.ContextCell.CheckBoxVisible)
height+=CheckBoxSize.Height;
}
else
{
if(largestImageSize.Height>height)
height=largestImageSize.Height;
if(info.ContextCell.CheckBoxVisible && CheckBoxSize.Height>height)
height=CheckBoxSize.Height;
}
Rectangle r=new Rectangle(info.Left+ElementStyleLayout.LeftWhiteSpace(info.LayoutStyle),
info.Top+ElementStyleLayout.TopWhiteSpace(info.LayoutStyle)
,info.CellWidth,height);
if(r.Width==0)
{
if(info.VerticalPartAlignment)
{
r.Width=(int)Math.Ceiling((double)textSize.Width);
if(largestImageSize.Width>r.Width)
r.Width=(largestImageSize.Width+this.ImageTextSpacing);
if(info.ContextCell.CheckBoxVisible && CheckBoxSize.Width>r.Width)
r.Width+=(CheckBoxSize.Width+this.ImageTextSpacing);
}
else
{
r.Width=(int)Math.Ceiling((double)textSize.Width);
if(largestImageSize.Width>0)
r.Width+=(largestImageSize.Width+this.ImageTextSpacing);
if(info.ContextCell.CheckBoxVisible)
r.Width+=(CheckBoxSize.Width+this.ImageTextSpacing);
}
}
// Now that we have cell bounds store them
Rectangle rCellBounds=new Rectangle(info.Left,info.Top,info.CellWidth,r.Height+info.LayoutStyle.MarginTop+info.LayoutStyle.MarginBottom+info.LayoutStyle.PaddingTop+info.LayoutStyle.PaddingBottom);
if(rCellBounds.Width==0)
rCellBounds.Width=r.Width+ElementStyleLayout.HorizontalStyleWhiteSpace(info.LayoutStyle);
info.ContextCell.SetBounds(rCellBounds);
// Set Position of the image
if(!largestImageSize.IsEmpty)
{
eVerticalAlign va=GetVerticalAlign(info.ContextCell.ImageAlignment);
eHorizontalAlign ha=GetHorizontalAlign(info.ContextCell.ImageAlignment,info.LeftToRight);
if(info.VerticalPartAlignment)
info.ContextCell.SetImageBounds(AlignContentVertical(largestImageSize, ref r, ha, va, this.ImageTextSpacing));
else
info.ContextCell.SetImageBounds(AlignContent(largestImageSize, ref r, ha, va, this.ImageTextSpacing));
}
else
info.ContextCell.SetImageBounds(Rectangle.Empty);
// Set position of the check box
if(info.ContextCell.CheckBoxVisible)
{
eVerticalAlign va=GetVerticalAlign(info.ContextCell.CheckBoxAlignment);
eHorizontalAlign ha=GetHorizontalAlign(info.ContextCell.CheckBoxAlignment,info.LeftToRight);
if(info.VerticalPartAlignment)
info.ContextCell.SetCheckBoxBounds(AlignContentVertical(this.CheckBoxSize, ref r, ha, va, this.ImageTextSpacing));
else
info.ContextCell.SetCheckBoxBounds(AlignContent(this.CheckBoxSize, ref r, ha, va, this.ImageTextSpacing));
}
else
info.ContextCell.SetCheckBoxBounds(Rectangle.Empty);
// Set position of the text
//info.ContextCell.SetTextBounds(Rectangle.Empty);
if(!textSize.IsEmpty)
info.ContextCell.TextContentBounds=r;
else
info.ContextCell.TextContentBounds=Rectangle.Empty;
}
private Rectangle AlignContent(System.Drawing.Size contentSize, ref Rectangle boundingRectangle, eHorizontalAlign horizAlign, eVerticalAlign vertAlign, int contentSpacing)
{
Rectangle contentRect=new Rectangle(Point.Empty,contentSize);
switch(horizAlign)
{
case eHorizontalAlign.Right:
{
contentRect.X=boundingRectangle.Right-contentRect.Width;
boundingRectangle.Width-=(contentRect.Width+contentSpacing);
break;
}
//case eHorizontalAlign.Left:
default:
{
contentRect.X=boundingRectangle.X;
boundingRectangle.X=contentRect.Right+contentSpacing;
boundingRectangle.Width-=(contentRect.Width+contentSpacing);
break;
}
// case eHorizontalAlign.Center:
// {
// contentRect.X=boundingRectangle.X+(boundingRectangle.Width-contentRect.Width)/2;
// break;
// }
}
switch(vertAlign)
{
case eVerticalAlign.Top:
{
contentRect.Y=boundingRectangle.Y;
break;
}
case eVerticalAlign.Middle:
{
contentRect.Y=boundingRectangle.Y+(boundingRectangle.Height-contentRect.Height)/2;
break;
}
case eVerticalAlign.Bottom:
{
contentRect.Y=boundingRectangle.Bottom-contentRect.Height;
break;
}
}
return contentRect;
}
private Rectangle AlignContentVertical(System.Drawing.Size contentSize, ref Rectangle boundingRectangle, eHorizontalAlign horizAlign, eVerticalAlign vertAlign, int contentSpacing)
{
Rectangle contentRect=new Rectangle(Point.Empty,contentSize);
switch(horizAlign)
{
case eHorizontalAlign.Left:
{
contentRect.X=boundingRectangle.X;
break;
}
case eHorizontalAlign.Right:
{
contentRect.X=boundingRectangle.Right-contentRect.Width;
break;
}
case eHorizontalAlign.Center:
{
contentRect.X=boundingRectangle.X+(boundingRectangle.Width-contentRect.Width)/2;
break;
}
}
switch(vertAlign)
{
case eVerticalAlign.Bottom:
{
contentRect.Y=boundingRectangle.Bottom-contentRect.Height;
boundingRectangle.Height-=(contentRect.Height+contentSpacing);
break;
}
//case eVerticalAlign.Top:
default:
{
contentRect.Y=boundingRectangle.Y;
boundingRectangle.Y=contentRect.Bottom+contentSpacing;
boundingRectangle.Height-=(contentRect.Height+contentSpacing);
break;
}
// case eVerticalAlign.Middle:
// {
// contentRect.Y=boundingRectangle.Y+(boundingRectangle.Height-contentRect.Height)/2;
// break;
// }
}
return contentRect;
}
private eHorizontalAlign GetHorizontalAlign(eCellPartAlignment align, bool leftToRight)
{
if(((align==eCellPartAlignment.NearBottom || align==eCellPartAlignment.NearCenter ||
align==eCellPartAlignment.NearTop) && leftToRight) ||
((align==eCellPartAlignment.FarBottom || align==eCellPartAlignment.FarCenter ||
align==eCellPartAlignment.FarTop) && !leftToRight))
return eHorizontalAlign.Left;
else if(align==eCellPartAlignment.CenterBottom || align==eCellPartAlignment.CenterTop)
return eHorizontalAlign.Center;
return eHorizontalAlign.Right;
}
private eVerticalAlign GetVerticalAlign(eCellPartAlignment align)
{
eVerticalAlign va=eVerticalAlign.Middle;
switch(align)
{
case eCellPartAlignment.FarBottom:
case eCellPartAlignment.NearBottom:
case eCellPartAlignment.CenterBottom:
va=eVerticalAlign.Bottom;
break;
case eCellPartAlignment.FarTop:
case eCellPartAlignment.NearTop:
case eCellPartAlignment.CenterTop:
va=eVerticalAlign.Top;
break;
}
return va;
}
private System.Drawing.Size CheckBoxSize
{
get
{
return new Size(Dpi.Width12,Dpi.Height12);
}
}
/// <summary>
/// Returns spacing between check box and image if both are displayed
/// </summary>
private int ImageCheckBoxSpacing
{
get {return Dpi.Width1;}
}
/// <summary>
/// Returns spacing between image or checkbox and text
/// </summary>
private int ImageTextSpacing
{
get {return Dpi.Width1;}
}
/// <summary>
/// Returns horizontal spacing between cells in a node
/// </summary>
public int CellHorizontalSpacing
{
get {return Dpi.Width1;}
}
/// <summary>
/// Returns vertical spacing between cells in a node
/// </summary>
public int CellVerticalSpacing
{
get { return Dpi.Height1; }
}
/// <summary>
/// Spacing between different parts of the cell, like image, option button, text and expand button area
/// </summary>
public int CellPartSpacing
{
get { return Dpi.Width1; }
}
public Size LayoutCells(NodeLayoutContextInfo layoutInfo, int x, int y)
{
eCellLayout layout=layoutInfo.CellLayout;
if(layoutInfo.ContextNode.CellLayout!=layoutInfo.CellLayout && layoutInfo.ContextNode.CellLayout!=eCellLayout.Default)
layout=layoutInfo.ContextNode.CellLayout;
if(layout==eCellLayout.Horizontal || layout==eCellLayout.Default)
return this.LayoutCellsHorizontal(layoutInfo,x,y);
else
return this.LayoutCellsVertical(layoutInfo,x,y);
}
private Size LayoutCellsHorizontal(NodeLayoutContextInfo layoutInfo, int x, int y)
{
Node node=layoutInfo.ContextNode;
int height=0, width=0;
for(int i=0;i<node.Cells.Count;i++)
{
Cell cell=node.Cells[i];
bool bCellVisible=true;
// Setup cell layout helper class
LayoutCellInfo cellLayout=this.GetLayoutCellInfo();
cellLayout.Top=y;
cellLayout.Left=x;
cellLayout.CellWidth=0;
cellLayout.ContextCell=cell;
cellLayout.Graphics=layoutInfo.Graphics;
cellLayout.LeftToRight=layoutInfo.LeftToRight;
cellLayout.Font=layoutInfo.DefaultFont;
if(cell.Layout!=eCellPartLayout.Default)
cellLayout.VerticalPartAlignment=(cell.Layout==eCellPartLayout.Vertical);
else if(layoutInfo.CellPartLayout!=eCellPartLayout.Default)
cellLayout.VerticalPartAlignment=(layoutInfo.CellPartLayout==eCellPartLayout.Vertical);
if(layoutInfo.DefaultColumns.Count>0 || layoutInfo.ChildColumns!=null && layoutInfo.ChildColumns.Count>0)
{
ColumnInfo ci=null;
if(layoutInfo.ChildColumns!=null && layoutInfo.ChildColumns.Count>0)
ci=layoutInfo.ChildColumns[i] as ColumnInfo;
else
ci=layoutInfo.DefaultColumns[i] as ColumnInfo;
bCellVisible=ci.Visible;
cellLayout.CellWidth=ci.Width;
}
// Prepare union style
if(cell.StyleNormal!=null)
cellLayout.LayoutStyle=cell.StyleNormal;
else
{
if(layoutInfo.ContextNode.Style!=null)
{
ElementStyle styleCopy = layoutInfo.DefaultCellStyle.Copy();
styleCopy.ApplyStyle(layoutInfo.ContextNode.Style);
cellLayout.LayoutStyle = styleCopy;
}
else
cellLayout.LayoutStyle=layoutInfo.DefaultCellStyle;
}
this.LayoutSingleCell(cellLayout);
if(bCellVisible)
{
x+=cell.BoundsRelative.Width;
width+=cell.BoundsRelative.Width;
if(cell.BoundsRelative.Width>0)
{
x+=this.CellHorizontalSpacing;
width+=this.CellHorizontalSpacing;
}
if(cell.BoundsRelative.Height>height)
height=cell.BoundsRelative.Height;
}
}
// Take last added spacing off
x-=this.CellHorizontalSpacing;
width-=this.CellHorizontalSpacing;
return new Size(width,height);
}
private Size LayoutCellsVertical(NodeLayoutContextInfo layoutInfo, int x, int y)
{
Node node=layoutInfo.ContextNode;
int height=0, width=0;
eHorizontalAlign align=eHorizontalAlign.Center;
int iVisibleCells=0;
for(int i=0;i<node.Cells.Count;i++)
{
Cell cell=node.Cells[i];
bool bCellVisible=true;
// Setup cell layout helper class
LayoutCellInfo cellLayout=this.GetLayoutCellInfo();
cellLayout.Top=y;
cellLayout.Left=x;
cellLayout.CellWidth=0;
cellLayout.ContextCell=cell;
cellLayout.Graphics=layoutInfo.Graphics;
cellLayout.LeftToRight=layoutInfo.LeftToRight;
cellLayout.Font=layoutInfo.DefaultFont;
if(cell.Layout!=eCellPartLayout.Default)
cellLayout.VerticalPartAlignment=(cell.Layout==eCellPartLayout.Vertical);
else if(layoutInfo.CellPartLayout!=eCellPartLayout.Default)
cellLayout.VerticalPartAlignment=(layoutInfo.CellPartLayout==eCellPartLayout.Vertical);
if(layoutInfo.DefaultColumns.Count>0 || layoutInfo.ChildColumns!=null && layoutInfo.ChildColumns.Count>0)
{
ColumnInfo ci=null;
if(layoutInfo.ChildColumns!=null && layoutInfo.ChildColumns.Count>0)
ci=layoutInfo.ChildColumns[i] as ColumnInfo;
else
ci=layoutInfo.DefaultColumns[i] as ColumnInfo;
bCellVisible=ci.Visible;
cellLayout.CellWidth=ci.Width;
}
// Prepare union style
if(cell.StyleNormal!=null)
cellLayout.LayoutStyle=cell.StyleNormal;
else
cellLayout.LayoutStyle=layoutInfo.DefaultCellStyle;
this.LayoutSingleCell(cellLayout);
cell.SetVisible(bCellVisible);
if(bCellVisible)
{
iVisibleCells++;
y+=cell.BoundsRelative.Height;
height+=cell.BoundsRelative.Height;
if(cell.BoundsRelative.Height>0)
{
y+=this.CellVerticalSpacing;
height+=this.CellVerticalSpacing;
}
if(cell.BoundsRelative.Width>width)
width=cell.BoundsRelative.Width;
}
}
// Take last added spacing off
y-=this.CellVerticalSpacing;
height-=this.CellVerticalSpacing;
// Additional pass needed if horizontal alignment is other than left and there is more than one cell visible
if(align!=eHorizontalAlign.Left && iVisibleCells>1)
{
foreach(Cell cell in node.Cells)
{
if(!cell.IsVisible)
continue;
if(align==eHorizontalAlign.Center)
this.Offset(cell,(width-cell.BoundsRelative.Width)/2,0);
else // Right aligned cells
this.Offset(cell,width-cell.BoundsRelative.Width,0);
}
}
return new Size(width,height);
}
private LayoutCellInfo m_LayoutCellInfo=null;
private LayoutCellInfo GetLayoutCellInfo()
{
if(m_LayoutCellInfo==null)
m_LayoutCellInfo=new LayoutCellInfo();
return m_LayoutCellInfo;
}
}
}
internal class LayoutCellInfo
{
public Cell ContextCell=null;
public int CellWidth=0;
public System.Drawing.Graphics Graphics=null;
public System.Drawing.Font Font=null;
public int Left=0;
public int Top=0;
public ElementStyle LayoutStyle=null;
public bool LeftToRight=true;
public bool VerticalPartAlignment=false;
public LayoutCellInfo()
{
}
}
internal class ColumnInfo
{
public bool Visible;
public int Width;
public ColumnInfo(int width, bool visible)
{
this.Width=width;
this.Visible=visible;
}
}
}

View File

@@ -0,0 +1,335 @@
using System;
using System.Collections;
using System.Drawing;
namespace DevComponents.Tree.Layout
{
/// <summary>
/// Represents the class that performs node diagram layout.
/// </summary>
internal class NodeDiagramLayout:NodeLayout
{
private eDiagramFlow m_DiagramFlow=eDiagramFlow.LeftToRight;
public NodeDiagramLayout(TreeGX treeControl, Rectangle clientArea):base(treeControl,clientArea)
{
}
public override void PerformLayout()
{
this.PrepareStyles();
// Get default Columns
ArrayList defaultColInfoList=this.GetDefaultColumnInfo();
if(m_Tree.Nodes.Count==0)
return;
System.Drawing.Graphics graphics=this.GetGraphics();
try
{
// Loop through each top-level node
Node[] topLevelNodes=this.GetTopLevelNodes();
NodeLayoutContextInfo layoutInfo=this.GetDefaultNodeLayoutContextInfo(graphics);
foreach(Node childNode in topLevelNodes)
{
if(!childNode.Visible)
continue;
layoutInfo.ContextNode=childNode;
ProcessRootNode(layoutInfo);
break;
}
EmptyBoundsUnusedNodes(topLevelNodes);
}
finally
{
if(this.DisposeGraphics)
graphics.Dispose();
}
}
private void ProcessRootNode(NodeLayoutContextInfo layoutInfo)
{
if(m_DiagramFlow==eDiagramFlow.RightToLeft || m_DiagramFlow==eDiagramFlow.BottomToTop)
layoutInfo.MapPositionNear=true;
ProcessSubNode(layoutInfo);
PositionRootNode(layoutInfo);
}
private void PositionRootNode(NodeLayoutContextInfo layoutInfo)
{
Point location=Point.Empty;
Node root=layoutInfo.ContextNode;
switch(m_DiagramFlow)
{
case eDiagramFlow.LeftToRight:
{
location.Y=(root.ChildNodesBounds.Height-root.BoundsRelative.Height)/2;
break;
}
case eDiagramFlow.RightToLeft:
{
location.X=root.ChildNodesBounds.Width+this.NodeHorizontalSpacing;
location.Y=(root.ChildNodesBounds.Height-root.BoundsRelative.Height)/2;
break;
}
case eDiagramFlow.TopToBottom:
{
location.X=0; //(root.ChildNodesBounds.Width-root.Bounds.Width)/2;
break;
}
case eDiagramFlow.BottomToTop:
{
location.X=root.ChildNodesBounds.Width; //-root.Bounds.Width; //-root.Bounds.Width)/2;
location.Y=root.ChildNodesBounds.Height+this.NodeVerticalSpacing; //-root.Bounds.Height; //+this.NodeVerticalSpacing;
break;
}
}
OffsetNodeLocation(root,location.X,location.Y);
Rectangle area=Rectangle.Empty;
area=Rectangle.Union(area,root.BoundsRelative);
PositionSubNodes(root);
area=Rectangle.Union(area,root.ChildNodesBounds);
root.ChildNodesBounds=area;
m_Width=area.Width;
m_Height=area.Height;
}
// private int GetMaxChildNodeWidth(Node parent)
// {
// int width=0;
// foreach(Node node in parent.Nodes)
// {
// if(node.Bounds.Width>width)
// width=node.Bounds.Width;
// }
// return width;
// }
private void PositionSubNodes(Node parentNode)
{
if(parentNode.Nodes.Count==0)
return;
Rectangle rChildBounds=Rectangle.Empty;
bool bFirst=true;
bool rootNode=IsRootNode(parentNode);
if(m_DiagramFlow==eDiagramFlow.LeftToRight || !rootNode && m_DiagramFlow==eDiagramFlow.TopToBottom)
{
int y=parentNode.BoundsRelative.Y-(parentNode.ChildNodesBounds.Height-parentNode.BoundsRelative.Height)/2;
int x=0;
// if(parentNode.Parent!=null)
// x=parentNode.Bounds.X+GetMaxChildNodeWidth(parentNode.Parent)+this.NodeHorizontalSpacing;
// else
x=parentNode.BoundsRelative.Right+this.NodeHorizontalSpacing;
foreach(Node node in parentNode.Nodes)
{
if(!node.Visible)
continue;
int top=y;
bool anyVisibleNodes=node.AnyVisibleNodes;
if(node.ChildNodesBounds.Height>node.BoundsRelative.Height && node.Expanded && anyVisibleNodes)
top+=(node.ChildNodesBounds.Height-node.BoundsRelative.Height)/2;
OffsetNodeLocation(node,x,top);
if(node.Expanded && anyVisibleNodes)
{
PositionSubNodes(node);
y+=(Math.Max(node.BoundsRelative.Height,node.ChildNodesBounds.Height)+this.NodeVerticalSpacing);
}
else y+=(node.BoundsRelative.Height+this.NodeVerticalSpacing);
if(bFirst)
{
rChildBounds=node.BoundsRelative;
bFirst=false;
}
else
rChildBounds=Rectangle.Union(rChildBounds,node.BoundsRelative);
if(!node.ChildNodesBounds.IsEmpty)
rChildBounds=Rectangle.Union(rChildBounds,node.ChildNodesBounds);
}
}
else if(m_DiagramFlow==eDiagramFlow.RightToLeft || !rootNode && m_DiagramFlow==eDiagramFlow.BottomToTop)
{
int y=parentNode.BoundsRelative.Y-(parentNode.ChildNodesBounds.Height-parentNode.BoundsRelative.Height)/2;
int x=parentNode.BoundsRelative.X-this.NodeHorizontalSpacing;
foreach(Node node in parentNode.Nodes)
{
if(!node.Visible)
continue;
int left=x-node.BoundsRelative.Width;
int top=y;
bool anyVisibleNodes=node.AnyVisibleNodes;
if(node.ChildNodesBounds.Height>node.BoundsRelative.Height && node.Expanded && anyVisibleNodes)
top+=(node.ChildNodesBounds.Height-node.BoundsRelative.Height)/2;
OffsetNodeLocation(node,left,top);
if(node.Expanded && anyVisibleNodes)
{
PositionSubNodes(node);
y+=(Math.Max(node.BoundsRelative.Height,node.ChildNodesBounds.Height)+this.NodeVerticalSpacing);
}
else y+=(node.BoundsRelative.Height+this.NodeVerticalSpacing);
if(bFirst)
{
rChildBounds=node.BoundsRelative;
bFirst=false;
}
else
rChildBounds=Rectangle.Union(rChildBounds,node.BoundsRelative);
if(!node.ChildNodesBounds.IsEmpty)
rChildBounds=Rectangle.Union(rChildBounds,node.ChildNodesBounds);
}
}
else if(m_DiagramFlow==eDiagramFlow.TopToBottom)
{
int y=parentNode.BoundsRelative.Bottom+this.NodeVerticalSpacing;
foreach(Node node in parentNode.Nodes)
{
if(!node.Visible)
continue;
int left=parentNode.BoundsRelative.Right+this.NodeHorizontalSpacing;
int top=y;
bool anyVisibleNodes=node.AnyVisibleNodes;
if(node.ChildNodesBounds.Height>node.BoundsRelative.Height && node.Expanded && anyVisibleNodes)
top+=(node.ChildNodesBounds.Height-node.BoundsRelative.Height)/2;
OffsetNodeLocation(node,left,top);
if(node.Expanded && anyVisibleNodes)
{
PositionSubNodes(node);
y+=(Math.Max(node.BoundsRelative.Height,node.ChildNodesBounds.Height)+this.NodeVerticalSpacing);
}
else y+=(node.BoundsRelative.Height+this.NodeVerticalSpacing);
if(bFirst)
{
rChildBounds=node.BoundsRelative;
bFirst=false;
}
else
rChildBounds=Rectangle.Union(rChildBounds,node.BoundsRelative);
if(!node.ChildNodesBounds.IsEmpty)
rChildBounds=Rectangle.Union(rChildBounds,node.ChildNodesBounds);
}
}
else if(m_DiagramFlow==eDiagramFlow.BottomToTop)
{
int y=parentNode.BoundsRelative.Top-this.NodeVerticalSpacing;
foreach(Node node in parentNode.Nodes)
{
if(!node.Visible)
continue;
int left=parentNode.BoundsRelative.Left-this.NodeHorizontalSpacing-node.BoundsRelative.Width;
int top=y-node.BoundsRelative.Height;
bool anyVisibleNodes=node.AnyVisibleNodes;
if(node.ChildNodesBounds.Height>node.BoundsRelative.Height && node.Expanded && anyVisibleNodes)
top-=(node.ChildNodesBounds.Height-node.BoundsRelative.Height)/2;
OffsetNodeLocation(node,left,top);
if(node.Expanded && anyVisibleNodes)
{
PositionSubNodes(node);
y-=(Math.Max(node.BoundsRelative.Height,node.ChildNodesBounds.Height)+this.NodeVerticalSpacing);
}
else y-=(node.BoundsRelative.Height+this.NodeVerticalSpacing);
if(bFirst)
{
rChildBounds=node.BoundsRelative;
bFirst=false;
}
else
rChildBounds=Rectangle.Union(rChildBounds,node.BoundsRelative);
if(!node.ChildNodesBounds.IsEmpty)
rChildBounds=Rectangle.Union(rChildBounds,node.ChildNodesBounds);
}
}
parentNode.ChildNodesBounds=rChildBounds;
}
private void ProcessSubNode(NodeLayoutContextInfo layoutInfo)
{
Node node=layoutInfo.ContextNode;
bool bHorizontalFlow=true;//(m_DiagramFlow==eDiagramFlow.LeftToRight || m_DiagramFlow==eDiagramFlow.RightToLeft);
if(node.SizeChanged)
{
// Calculate size of the node itself...
LayoutNode(layoutInfo);
}
else
node.SetBounds(new Rectangle(Point.Empty,node.BoundsRelative.Size));
if(node.Expanded)
{
ArrayList parentColumns=layoutInfo.ChildColumns;
ArrayList childColumns=GetNodeColumnInfo(node);
Rectangle childNodesBounds=Rectangle.Empty;
foreach(Node childNode in node.Nodes)
{
if(!childNode.Visible)
continue;
layoutInfo.ContextNode=childNode;
layoutInfo.ChildColumns=childColumns;
ProcessSubNode(layoutInfo);
if(bHorizontalFlow)
{
childNodesBounds.Height+=(Math.Max(childNode.BoundsRelative.Height,childNode.ChildNodesBounds.Height)+this.NodeVerticalSpacing);
childNodesBounds.Width=Math.Max(childNodesBounds.Width,childNode.BoundsRelative.Width+(childNode.ChildNodesBounds.Width>0?this.NodeHorizontalSpacing+childNode.ChildNodesBounds.Width:0));
}
else
{
childNodesBounds.Width+=(Math.Max(childNode.BoundsRelative.Width,childNode.ChildNodesBounds.Width)+this.NodeHorizontalSpacing);
childNodesBounds.Height=Math.Max(childNodesBounds.Height,childNode.BoundsRelative.Height+(childNode.ChildNodesBounds.Height>0?this.NodeVerticalSpacing+childNode.ChildNodesBounds.Height:0));
}
}
layoutInfo.ChildColumns=parentColumns;
if(bHorizontalFlow)
{
if(childNodesBounds.Height>0)
childNodesBounds.Height-=this.NodeVerticalSpacing;
}
else
{
if(childNodesBounds.Width>0)
childNodesBounds.Width-=this.NodeHorizontalSpacing;
}
node.ChildNodesBounds=childNodesBounds;
layoutInfo.ChildColumns=null;
layoutInfo.ContextNode=node;
}
else node.ChildNodesBounds=Rectangle.Empty;
}
/// <summary>
/// Returns true if root node should have expanded part
/// </summary>
protected override bool RootHasExpandedPart
{
get {return false;}
}
/// <summary>
/// Indicates the layout flow for the nodes.
/// </summary>
public eDiagramFlow DiagramFlow
{
get {return m_DiagramFlow;}
set
{
m_DiagramFlow=value;
}
}
}
}

View File

@@ -0,0 +1,591 @@
using System;
using System.Drawing;
using System.Collections;
namespace DevComponents.Tree.Layout
{
/// <summary>
/// Summary description for NodeLayout.
/// </summary>
internal abstract class NodeLayout
{
#region Private Variables
protected int m_Height=0;
protected int m_Width=0;
protected TreeGX m_Tree=null;
protected Rectangle m_ClientArea;
//protected int m_ExpandAreaWidth=8;
private Size m_ExpandPartSize = new Size(9, 9);
private int m_CommandAreaWidth=10;
private int m_TreeLayoutChildNodeIndent = 16;
private System.Windows.Forms.LeftRightAlignment m_LeftRight=System.Windows.Forms.LeftRightAlignment.Left;
private int m_NodeVerticalSpacing=0;
private int m_NodeHorizontalSpacing=0;
private CellLayout m_CellLayout=null;
private Graphics m_Graphics=null;
#endregion
public NodeLayout(TreeGX treeControl, Rectangle clientArea)
{
m_Tree=treeControl;
m_ClientArea=clientArea;
}
/// <summary>
/// Performs layout of the nodes inside of the tree control.
/// </summary>
public virtual void PerformLayout()
{
}
/// <summary>
/// Performs layout for single unassigned node. Node does not have to be part of the tree control.
/// </summary>
/// <param name="node">Node to perform layout on.</param>
public virtual void PerformSingleNodeLayout(Node node)
{
if(node==null)
return;
this.PrepareStyles();
// Get default Columns
System.Drawing.Graphics graphics=this.GetGraphics();
try
{
NodeLayoutContextInfo layoutInfo=this.GetDefaultNodeLayoutContextInfo(graphics);
layoutInfo.ContextNode=node;
LayoutNode(layoutInfo);
}
finally
{
graphics.Dispose();
}
}
public int Width
{
get {return m_Width;}
}
public int Height
{
get {return m_Height;}
}
public Rectangle ClientArea
{
get {return m_ClientArea;}
set {m_ClientArea=value;}
}
public Graphics Graphics
{
get { return m_Graphics;}
set { m_Graphics = value;}
}
internal bool DisposeGraphics
{
get
{
return (m_Graphics == null);
}
}
protected virtual System.Drawing.Graphics GetGraphics()
{
if(m_Graphics!=null)
return m_Graphics;
Graphics g=m_Tree.CreateGraphics();
if(m_Tree.AntiAlias)
{
g.SmoothingMode=System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
}
return g;
}
/// <summary>
/// Resizes all styles and prepares them for layout.
/// </summary>
protected virtual void PrepareStyles()
{
// Resize styles if needed
foreach(ElementStyle es in m_Tree.Styles)
{
if(es.SizeChanged)
ElementStyleLayout.CalculateStyleSize(es,m_Tree.Font);
}
}
/// <summary>
/// Returns default top-level columns for tree control.
/// </summary>
/// <returns>Returns array list of ColumnInfo objects.</returns>
protected virtual ArrayList GetDefaultColumnInfo()
{
ArrayList ci=new ArrayList();
ColumnHeaderCollection columns=m_Tree.Columns;
if(columns!=null)
{
foreach(ColumnHeader h in columns)
{
ci.Add(new ColumnInfo(h.Bounds.Width, h.Visible));
}
}
return ci;
}
/// <summary>
/// Returns column information for a given node.
/// </summary>
/// <param name="node">Node to return column information for</param>
/// <returns>Returns array list of ColumnInfo objects or null if there are no columns defined.</returns>
protected virtual ArrayList GetNodeColumnInfo(Node node)
{
if(node.NodesColumns.Count==0)
return null;
ArrayList ci=new ArrayList();
foreach(ColumnHeader h in node.NodesColumns)
{
ci.Add(new ColumnInfo(h.Width.Absolute, h.Visible));
}
return ci;
}
/// <summary>
/// Gets or sets the vertical spacing between nodes in pixels.
/// </summary>
public virtual int NodeVerticalSpacing
{
get {return m_NodeVerticalSpacing;}
set {m_NodeVerticalSpacing=value;}
}
/// <summary>
/// Gets or sets the horizontal spacing between nodes in pixels.
/// </summary>
public virtual int NodeHorizontalSpacing
{
get {return m_NodeHorizontalSpacing;}
set {m_NodeHorizontalSpacing=value;}
}
/// <summary>
/// Gets or sets the child node indent in pixels.
/// </summary>
public virtual int TreeLayoutChildNodeIndent
{
get {return m_TreeLayoutChildNodeIndent; }
set { m_TreeLayoutChildNodeIndent = value; }
}
/// <summary>
/// Returns column header collection for the given column template name.
/// </summary>
/// <param name="name">Name of the column template.</param>
/// <returns>Column header collection or null if template name cannot be found.</returns>
public virtual ColumnHeaderCollection GetColumnHeader(string name)
{
if(name=="" || name==null)
return null;
return m_Tree.Headers.GetByName(name).Columns;
}
/// <summary>
/// Returns width of the expand button area. Default is 8 pixels.
/// </summary>
protected virtual int ExpandAreaWidth
{
get {return Dpi.Width(m_ExpandPartSize.Width);}
}
/// <summary>
/// Gets or sets width of command button area. Default is 8 pixels.
/// </summary>
public virtual int CommandAreaWidth
{
get {return m_CommandAreaWidth;}
set {m_CommandAreaWidth=value;}
}
/// <summary>
/// Sets the position and size of the node command button.
/// </summary>
/// <param name="layoutInfo">Node layout context information</param>
protected virtual void LayoutCommandPart(NodeLayoutContextInfo layoutInfo, ElementStyle nodeStyle)
{
// Command part is right-aligned just before the node border
Rectangle bounds=new Rectangle(layoutInfo.ContextNode.ContentBounds.Right-this.CommandAreaWidth-
ElementStyleLayout.StyleSpacing(nodeStyle,eSpacePart.Border,eStyleSide.Right),layoutInfo.ContextNode.ContentBounds.Y+
ElementStyleLayout.StyleSpacing(nodeStyle,eSpacePart.Border,eStyleSide.Top),
this.CommandAreaWidth, layoutInfo.ContextNode.ContentBounds.Height-
ElementStyleLayout.StyleSpacing(nodeStyle,eSpacePart.Border,eStyleSide.Top)-
ElementStyleLayout.StyleSpacing(nodeStyle,eSpacePart.Border,eStyleSide.Bottom));
// Rectangle bounds=new Rectangle(layoutInfo.ContextNode.ContentBounds.Right-this.CommandAreaWidth-
// ElementStyleLayout.StyleSpacing(nodeStyle,eSpacePart.Border,eStyleSide.Right),layoutInfo.ContextNode.ContentBounds.Y,
// this.CommandAreaWidth, layoutInfo.ContextNode.ContentBounds.Height);
layoutInfo.ContextNode.CommandBoundsRelative=bounds;
}
/// <summary>
/// Determines the rectangle of the +/- part of the tree node that is used to expand node.
/// </summary>
/// <param name="layoutInfo">Node layout context information</param>
protected virtual void LayoutExpandPart(NodeLayoutContextInfo layoutInfo, bool bLeftNode)
{
Node node=layoutInfo.ContextNode;
Size partSize=Dpi.Size(GetExpandPartSize());
Rectangle bounds=new Rectangle(0,0,partSize.Width,partSize.Height);
bounds.Y=(node.BoundsRelative.Height-bounds.Height)/2;
if(bLeftNode)
bounds.X=(this.ExpandAreaWidth-bounds.Width)/2;
else
bounds.X=node.BoundsRelative.Right-this.ExpandAreaWidth+(this.ExpandAreaWidth-partSize.Width)/2;
node.SetExpandPartRectangle(bounds);
}
/// <summary>
/// Returns the size of the node expand part.
/// </summary>
/// <returns>Size of the expand part, default 8,8.</returns>
protected virtual Size GetExpandPartSize()
{
return m_ExpandPartSize;
}
/// <summary>
/// Gets or sets the size of the expand part that is expanding/collapsing the node. Default value is 8,8.
/// </summary>
public System.Drawing.Size ExpandPartSize
{
get {return m_ExpandPartSize;}
set
{
m_ExpandPartSize=value;
}
}
/// <summary>
/// Provides the layout for single node.
/// </summary>
/// <param name="layoutInfo">Layout information.</param>
protected virtual void LayoutNode(NodeLayoutContextInfo layoutInfo)
{
// if(!layoutInfo.ContextNode.SizeChanged)
// return;
bool bHasExpandPart=this.HasExpandPart(layoutInfo);
bool bHasCommandPart=this.HasCommandPart(layoutInfo);
Node node=layoutInfo.ContextNode;
Rectangle nodeRect=Rectangle.Empty;
Rectangle nodeContentRect=Rectangle.Empty; // Node content rect excludes expand rect
int height=0, width=0;
// Left node relative to the main root node...
bool bLeftNode=(layoutInfo.MapPositionNear && layoutInfo.LeftToRight);
if(bLeftNode && bHasExpandPart || this.ReserveExpandPartSpace)
{
width+=(this.ExpandAreaWidth+this.GetCellLayout().CellPartSpacing);
}
int x=width; // relative to 0,0 of the node
int y=0; // Relative to 0,0 of the node
// Apply node style
ElementStyle nodeStyle=null;
if(node.Expanded && node.StyleExpanded!=null)
nodeStyle=node.StyleExpanded;
else if(node.Style!=null)
nodeStyle=node.Style;
else
nodeStyle=layoutInfo.DefaultNodeStyle;
nodeContentRect.X=x;
if(nodeStyle!=null)
{
x+=ElementStyleLayout.LeftWhiteSpace(nodeStyle); // nodeStyle.MarginLeft+nodeStyle.PaddingLeft;
y+=ElementStyleLayout.TopWhiteSpace(nodeStyle); //nodeStyle.MarginTop+nodeStyle.PaddingTop;
nodeContentRect.X+=nodeStyle.MarginLeft;
nodeContentRect.Y+=nodeStyle.MarginTop;
}
Size size=this.GetCellLayout().LayoutCells(layoutInfo,x,y);
node.SetCellsBounds(new Rectangle(x,y,size.Width,size.Height));
height=size.Height;
width+=size.Width;
nodeContentRect.Width=size.Width;
nodeContentRect.Height=size.Height;
if(nodeStyle!=null)
{
nodeContentRect.Width+=(ElementStyleLayout.StyleSpacing(nodeStyle,eSpacePart.Padding | eSpacePart.Border,eStyleSide.Left)+
ElementStyleLayout.StyleSpacing(nodeStyle,eSpacePart.Padding | eSpacePart.Border,eStyleSide.Right));
nodeContentRect.Height+=(ElementStyleLayout.StyleSpacing(nodeStyle,eSpacePart.Padding | eSpacePart.Border,eStyleSide.Top)+
ElementStyleLayout.StyleSpacing(nodeStyle,eSpacePart.Padding | eSpacePart.Border,eStyleSide.Bottom));
width+=(ElementStyleLayout.HorizontalStyleWhiteSpace(nodeStyle));
height+=(ElementStyleLayout.VerticalStyleWhiteSpace(nodeStyle));
}
if(!bLeftNode && bHasExpandPart)
width+=this.ExpandAreaWidth;
if(bHasCommandPart)
{
width+=this.CommandAreaWidth;
nodeContentRect.Width+=this.CommandAreaWidth;
}
nodeRect.Height=height;
nodeRect.Width=width;
node.SetBounds(nodeRect);
node.SetContentBounds(nodeContentRect);
if(bHasCommandPart)
LayoutCommandPart(layoutInfo, nodeStyle);
else
node.CommandBoundsRelative=Rectangle.Empty;
if(bHasExpandPart)
LayoutExpandPart(layoutInfo,bLeftNode);
else
node.SetExpandPartRectangle(Rectangle.Empty);
node.SizeChanged=false;
// Calculate size and location of node column header if any
//if(node.NodesColumnHeaderVisible)
{
//layoutInfo.Left+=this.NodeLevelOffset;
LayoutColumnHeader(layoutInfo);
//layoutInfo.Left-=this.NodeLevelOffset;
}
}
/// <summary>
/// Returns true if given node has expand part.
/// </summary>
/// <param name="layoutInfo">Layout context information.</param>
/// <returns></returns>
protected virtual bool HasExpandPart(NodeLayoutContextInfo layoutInfo)
{
Node node=layoutInfo.ContextNode;
if(node.ExpandVisibility==eNodeExpandVisibility.Auto)
{
if(IsRootNode(node) && !RootHasExpandedPart || !NodeOperations.GetAnyVisibleNodes(node))
return false;
return true;
}
else
return (node.ExpandVisibility==eNodeExpandVisibility.Visible);
}
/// <summary>
/// Returns whether given node has command part.
/// </summary>
/// <param name="layoutInfo">Layout context information.</param>
/// <returns>True if command part should be drawn otherwise false.</returns>
protected virtual bool HasCommandPart(NodeLayoutContextInfo layoutInfo)
{
return layoutInfo.ContextNode.CommandButton;
}
/// <summary>
/// Returns true if root node should have expanded part
/// </summary>
protected virtual bool RootHasExpandedPart
{
get {return true;}
}
/// <summary>
/// Returns true if expand part space should be accounted for even if they expand part is not visible or need to be displayed. Default value is false.
/// </summary>
protected virtual bool ReserveExpandPartSpace
{
get
{
return false;
}
}
/// <summary>
/// Returns class responsible for cell layout.
/// </summary>
/// <returns>Cell layout class.</returns>
protected virtual CellLayout GetCellLayout()
{
if(m_CellLayout==null)
m_CellLayout=new CellLayout();
return m_CellLayout;
}
/// <summary>
/// Offsets node location and location of it's child nodes bounds.
/// </summary>
/// <param name="node">Node to offset.</param>
/// <param name="x">Horizontal offset.</param>
/// <param name="y">Vertical offset.</param>
protected virtual void OffsetNodeLocation(Node node, int x, int y)
{
node.SetBounds(new Rectangle(node.BoundsRelative.X+x,node.BoundsRelative.Y+y,node.BoundsRelative.Width,node.BoundsRelative.Height));
if(node.Expanded)
node.ChildNodesBounds=new Rectangle(node.ChildNodesBounds.X+x,node.ChildNodesBounds.Y+y,node.ChildNodesBounds.Width,node.ChildNodesBounds.Height);
}
protected virtual NodeLayoutContextInfo GetDefaultNodeLayoutContextInfo(System.Drawing.Graphics graphics)
{
NodeLayoutContextInfo layoutInfo=new NodeLayoutContextInfo();
layoutInfo.ClientRectangle=m_ClientArea;
layoutInfo.DefaultColumns=this.GetDefaultColumnInfo();
layoutInfo.ChildColumns=null;
layoutInfo.Left=0;
layoutInfo.Top=0; // TODO: Include Columns if visible into this...
layoutInfo.DefaultFont=m_Tree.Font;
layoutInfo.LeftToRight=(this.LeftRight==System.Windows.Forms.LeftRightAlignment.Left);
layoutInfo.Graphics=graphics;
layoutInfo.Styles=m_Tree.Styles;
if(m_Tree.CellLayout!=eCellLayout.Default)
layoutInfo.CellLayout=m_Tree.CellLayout;
if(m_Tree.CellPartLayout!=eCellPartLayout.Default)
layoutInfo.CellPartLayout=m_Tree.CellPartLayout;
if(m_Tree.NodeStyle!=null)
layoutInfo.DefaultNodeStyle=m_Tree.NodeStyle;
if(m_Tree.CellStyleDefault!=null)
layoutInfo.DefaultCellStyle=m_Tree.CellStyleDefault;
else
layoutInfo.DefaultCellStyle=ElementStyle.GetDefaultCellStyle(layoutInfo.DefaultNodeStyle);
// Determine size of the default Column Header
if(m_Tree.ColumnStyleNormal!=null)
{
ElementStyleLayout.CalculateStyleSize(m_Tree.ColumnStyleNormal,layoutInfo.DefaultFont);
layoutInfo.DefaultHeaderSize=m_Tree.ColumnStyleNormal.Size;
}
if(layoutInfo.DefaultHeaderSize.IsEmpty)
layoutInfo.DefaultHeaderSize.Height=layoutInfo.DefaultFont.Height+4;
return layoutInfo;
}
protected Node[] GetTopLevelNodes()
{
if(m_Tree.DisplayRootNode!=null)
return new Node[] {m_Tree.DisplayRootNode};
else
{
Node[] nodes=new Node[m_Tree.Nodes.Count];
m_Tree.Nodes.CopyTo(nodes);
return nodes;
}
}
protected bool IsRootNode(Node node)
{
return NodeOperations.IsRootNode(m_Tree,node);
}
protected virtual void EmptyBoundsUnusedNodes(Node[] topLevelNodes)
{
if(m_Tree.DisplayRootNode!=null)
{
Node node=m_Tree.DisplayRootNode.PrevVisibleNode;
while(node!=null)
{
node.SetBounds(Rectangle.Empty);
node=node.PrevVisibleNode;
}
node=m_Tree.DisplayRootNode.NextNode;
if(node==null)
{
node=m_Tree.DisplayRootNode.Parent;
while(node!=null)
{
if(node.NextNode!=null)
{
node=node.NextNode;
break;
}
else
node=node.Parent;
}
}
while(node!=null)
{
node.SetBounds(Rectangle.Empty);
node=node.NextVisibleNode;
}
}
else
{
for(int i=1;i<topLevelNodes.Length;i++)
{
topLevelNodes[i].SetBounds(Rectangle.Empty);
}
}
}
#region Column Support
// Assumes that layoutInfo is up-to-date and that Node that is connected with
// columns is already processed and it's size and location calculated.
// layoutInfo.Top member reflects the next position below the node
// layoutInfo.LevelOffset should reflect the X offset for the child nodes.
public void LayoutColumnHeader(NodeLayoutContextInfo layoutInfo)
{
Node node=layoutInfo.ContextNode;
if(node.NodesColumns.Count==0)
{
node.ColumnHeaderHeight=0;
return;
}
int x=layoutInfo.Left;
int y=layoutInfo.ContextNode.BoundsRelative.Bottom;
bool bLeftNode=(layoutInfo.MapPositionNear && layoutInfo.LeftToRight);
int expandPartWidth=this.ExpandAreaWidth;
int cellPartSpacing=GetCellLayout().CellPartSpacing;
if(!bLeftNode)
x+=(expandPartWidth+cellPartSpacing);
int clientWidth=layoutInfo.ClientRectangle.Width-(layoutInfo.Left+expandPartWidth);
if(clientWidth<=0)
clientWidth=layoutInfo.ClientRectangle.Width;
node.ColumnHeaderHeight=Layout.ColumnHeaderLayout.LayoutColumnHeader(layoutInfo,x,y,clientWidth,this.GetCellLayout().CellHorizontalSpacing);
}
#endregion
#region RTL Support
public virtual System.Windows.Forms.LeftRightAlignment LeftRight
{
get {return m_LeftRight;}
set {m_LeftRight=value;}
}
#endregion
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Drawing;
using System.Collections;
namespace DevComponents.Tree.Layout
{
/// <summary>
/// Used to pass node contextual information used for layout of the node.
/// </summary>
internal class NodeLayoutContextInfo
{
public Node ContextNode=null;
public Rectangle ClientRectangle=Rectangle.Empty;
public int Left;
public int Top;
public ArrayList DefaultColumns=null;
public ArrayList ChildColumns=null;
public Font DefaultFont=null;
public ElementStyle DefaultCellStyle=null;
public ElementStyle DefaultNodeStyle=null;
public Size DefaultHeaderSize=Size.Empty;
public bool LeftToRight=true;
public bool HasExpandPart=true;
public System.Drawing.Graphics Graphics=null;
public ElementStyleCollection Styles=null;
public eCellLayout CellLayout=eCellLayout.Horizontal;
public eCellPartLayout CellPartLayout=eCellPartLayout.Horizontal;
public bool MapPositionNear=false;
}
}

View File

@@ -0,0 +1,61 @@
using System;
using System.Drawing;
using System.Collections;
namespace DevComponents.Tree.Layout
{
/// <summary>
/// Internal class that orders one level of the nodes in list like layout. Nodes are ordered from top to bottom.
/// </summary>
internal class NodeListLayout:Layout.NodeLayout
{
public NodeListLayout(TreeGX treeControl, Rectangle clientArea):base(treeControl,clientArea)
{
}
public override void PerformLayout()
{
if(m_Tree.Nodes.Count==0)
return;
this.PrepareStyles();
System.Drawing.Graphics graphics=this.GetGraphics();
m_Width=0;
m_Height=0;
try
{
NodeCollection nodes=this.GetLayoutNodes();
NodeLayoutContextInfo layoutInfo=this.GetDefaultNodeLayoutContextInfo(graphics);
foreach(Node childNode in nodes)
{
if(!childNode.Visible)
continue;
layoutInfo.ContextNode=childNode;
ProcessNode(layoutInfo);
if(childNode.BoundsRelative.Width>this.Width)
m_Width=childNode.BoundsRelative.Width;
}
m_Height=layoutInfo.Top-this.NodeVerticalSpacing;
}
finally
{
if(this.DisposeGraphics)
graphics.Dispose();
}
}
private void ProcessNode(NodeLayoutContextInfo layoutInfo)
{
LayoutNode(layoutInfo);
layoutInfo.ContextNode.SetBounds(new Rectangle(layoutInfo.Left,layoutInfo.Top,layoutInfo.ContextNode.BoundsRelative.Width,layoutInfo.ContextNode.BoundsRelative.Height));
//OffsetNodeLocation(layoutInfo.ContextNode,layoutInfo.Left,layoutInfo.Top);
layoutInfo.Top+=(layoutInfo.ContextNode.BoundsRelative.Height+this.NodeVerticalSpacing);
}
private NodeCollection GetLayoutNodes()
{
return m_Tree.Nodes;
}
}
}

View File

@@ -0,0 +1,525 @@
using System;
using System.Drawing;
using System.Collections;
namespace DevComponents.Tree.Layout
{
/// <summary>
/// Represents the class that performs node map layout.
/// </summary>
internal class NodeMapLayout:NodeLayout
{
#region Private Variables
private eMapFlow m_MapFlow=eMapFlow.Spread;
#endregion
public NodeMapLayout(TreeGX treeControl, Rectangle clientArea):base(treeControl,clientArea)
{
}
public override void PerformLayout()
{
this.PrepareStyles();
// Get default Columns
//ArrayList defaultColInfoList=this.GetDefaultColumnInfo();
if(m_Tree.Nodes.Count==0)
return;
Graphics graphics=this.GetGraphics();
try
{
// Loop through each top-level node
Node[] topLevelNodes=this.GetTopLevelNodes();
NodeLayoutContextInfo layoutInfo=this.GetDefaultNodeLayoutContextInfo(graphics);
foreach(Node childNode in topLevelNodes)
{
if(!childNode.Visible)
continue;
layoutInfo.ContextNode=childNode;
ProcessRootNode(layoutInfo);
break;
}
EmptyBoundsUnusedNodes(topLevelNodes);
}
finally
{
if(this.DisposeGraphics)
graphics.Dispose();
}
}
private void ProcessRootNode(NodeLayoutContextInfo layoutInfo)
{
Node node=layoutInfo.ContextNode;
// Center root node on the screen
//if(node.SizeChanged)
//{
// Calculate size of the node itself...
LayoutNode(layoutInfo);
// Calculate size and location of node column header if any
// if(node.NodesColumnHeaderVisible)
// {
// LayoutColumnHeader(layoutInfo);
// }
//}
// if(node.Expanded && node.NodesColumnHeaderVisible && node.NodesColumns.Count>0)
// layoutInfo.Top+=node.ColumnHeaderHeight;
NodesMapPosition positions=NodesMapPosition.Empty;
bool bNear=false;
if(node.Expanded)
{
if(node.NodesColumns.Count>0)
layoutInfo.ChildColumns=GetNodeColumnInfo(node);
foreach(Node childNode in node.Nodes)
{
if(!childNode.Visible)
continue;
layoutInfo.ContextNode=childNode;
if(bNear || childNode.MapSubRootPosition==eMapPosition.Near)
{
layoutInfo.MapPositionNear=true;
ProcessSubNode(layoutInfo);
positions.Near.Add(childNode);
positions.NearHeight+=GetTotalChildNodeHeight(childNode);
bNear=true;
}
else if(childNode.MapSubRootPosition==eMapPosition.Far)
{
layoutInfo.MapPositionNear=false;
ProcessSubNode(layoutInfo);
positions.Far.Add(childNode);
positions.FarHeight+=GetTotalChildNodeHeight(childNode);
}
else
positions.Default.Add(childNode);
}
// Assign nodes to appropriate sides....
if(positions.Default.Count>0)
{
int toFar=0;
if(positions.Near.Count==0 && positions.Far.Count==0 && positions.Default.Count<=4)
toFar=2;
else
toFar=(int)Math.Ceiling((double)((positions.Near.Count-positions.Far.Count+positions.Default.Count))/2);
for(int i=0;i<toFar;i++)
{
layoutInfo.ContextNode=positions.Default[0] as Node;
if(m_MapFlow==eMapFlow.RightToLeft)
layoutInfo.MapPositionNear=true;
else
layoutInfo.MapPositionNear=false;
ProcessSubNode(layoutInfo);
positions.Far.Add(positions.Default[0]);
positions.FarHeight+=GetTotalChildNodeHeight(positions.Default[0] as Node);
positions.Default.RemoveAt(0);
if(positions.Default.Count==0)
break;
}
for(int i=0;i<positions.Default.Count;i++)
{
layoutInfo.ContextNode=positions.Default[i] as Node;
if(m_MapFlow==eMapFlow.LeftToRight)
layoutInfo.MapPositionNear=false;
else
layoutInfo.MapPositionNear=true;
ProcessSubNode(layoutInfo);
positions.Near.Add(positions.Default[i]);
positions.NearHeight+=GetTotalChildNodeHeight(positions.Default[i] as Node); //+this.NodeVerticalSpacing;
}
positions.Default.Clear();
}
layoutInfo.ChildColumns=null;
layoutInfo.ContextNode=node;
}
// Set the position of the root node
Point pRoot = new Point(0, 0);
pRoot.Offset(node.Offset,0);
// Adjust top position
node.SetBounds(new Rectangle(pRoot,node.BoundsRelative.Size));
node.ExpandPartRectangleRelative.Offset(pRoot);
foreach(Cell c in node.Cells)
c.BoundsRelative.Offset(pRoot);
// Set the position of the child nodes
if(node.Expanded)
{
PositionCenterRootSubNodes(node, positions);
}
else
{
node.ChildNodesBounds = Rectangle.Empty;
m_Width = node.Bounds.Width;
m_Height = node.Bounds.Height;
}
}
private int GetTotalChildNodeHeight(Node childNode)
{
if(childNode.Expanded)
return Math.Max(childNode.BoundsRelative.Height,childNode.ChildNodesBounds.Height);
return childNode.BoundsRelative.Height;
}
private void ProcessSubNode(NodeLayoutContextInfo layoutInfo)
{
Node node=layoutInfo.ContextNode;
//if(node.SizeChanged)
//{
// Calculate size of the node itself...
LayoutNode(layoutInfo);
//}
//else
// node.SetBounds(new Rectangle(Point.Empty,node.Bounds.Size));
if(node.Expanded && node.AnyVisibleNodes)
{
ArrayList parentColumns=layoutInfo.ChildColumns;
ArrayList childColumns=GetNodeColumnInfo(node);
if(node.NodesColumns.Count>0)
layoutInfo.ChildColumns=GetNodeColumnInfo(node);
Rectangle childNodesBounds=Rectangle.Empty;
foreach(Node childNode in node.Nodes)
{
if(!childNode.Visible)
continue;
layoutInfo.ContextNode=childNode;
layoutInfo.ChildColumns=childColumns;
ProcessSubNode(layoutInfo);
childNodesBounds.Height+=(Math.Max(childNode.BoundsRelative.Height,childNode.ChildNodesBounds.Height)+this.NodeVerticalSpacing);
childNodesBounds.Width=Math.Max(childNodesBounds.Width,childNode.BoundsRelative.Width+(childNode.ChildNodesBounds.Width>0?this.NodeHorizontalSpacing+childNode.ChildNodesBounds.Width:0));
}
layoutInfo.ChildColumns=parentColumns;
if(childNodesBounds.Height>0)
childNodesBounds.Height-=this.NodeVerticalSpacing;
node.ChildNodesBounds=childNodesBounds;
layoutInfo.ChildColumns=null;
layoutInfo.ContextNode=node;
}
else node.ChildNodesBounds=Rectangle.Empty;
}
private void PositionCenterRootSubNodes(Node root, NodesMapPosition positions)
{
Rectangle area=Rectangle.Empty;
area=Rectangle.Union(area,root.BoundsRelative);
// Far Nodes Layout
//int y=0, x=0;
int areaHeight=positions.FarHeight;
int minAreaHeight=this.GetMinimumAreaHeight(positions.Far,root.BoundsRelative.Height);
if(areaHeight<minAreaHeight)
areaHeight=minAreaHeight;
int areaLeft=root.BoundsRelative.Right-root.BoundsRelative.Width/3;
int areaTop=0;
if(m_MapFlow==eMapFlow.TopToBottom)
areaTop=root.BoundsRelative.Bottom+this.NodeVerticalSpacing; // Top Bottom Orientation
else if(m_MapFlow==eMapFlow.BottomToTop)
areaTop=root.BoundsRelative.Y-(areaHeight+this.NodeVerticalSpacing*((positions.Far.Count==1?1:positions.Far.Count-1))); //Bottom Top Orientation
else if(m_MapFlow==eMapFlow.LeftToRight || m_MapFlow==eMapFlow.RightToLeft)
areaTop=root.BoundsRelative.Y-(areaHeight+this.NodeVerticalSpacing*((positions.Far.Count==1?1:positions.Far.Count-1)));
else // Spread
areaTop=root.BoundsRelative.Y+root.BoundsRelative.Height/2-(areaHeight+this.NodeVerticalSpacing*((positions.Far.Count==1?1:positions.Far.Count-1)))/2; // Around spread orientation
if(m_MapFlow==eMapFlow.RightToLeft)
{
int areaRightMost=root.BoundsRelative.X+root.BoundsRelative.Width/3;
PositionNearSubRootNodes(root,positions.Far,areaRightMost,areaTop,areaHeight,ref area);
}
else
{
PositionFarSubRootNodes(root,positions.Far,areaLeft,areaTop,ref area);
}
if(m_MapFlow==eMapFlow.LeftToRight)
{
areaTop=root.BoundsRelative.Bottom+this.NodeVerticalSpacing;
PositionFarSubRootNodes(root,positions.Near,areaLeft,areaTop,ref area);
}
else
{
// Near nodes layout
areaHeight=positions.NearHeight;
minAreaHeight=this.GetMinimumAreaHeight(positions.Near,root.BoundsRelative.Height);
if(areaHeight<minAreaHeight)
areaHeight=minAreaHeight;
int areaRightMost=root.BoundsRelative.X+root.BoundsRelative.Width/3;
if(m_MapFlow==eMapFlow.TopToBottom)
areaTop=root.BoundsRelative.Bottom+this.NodeVerticalSpacing; // Top Bottom Orientation
else if(m_MapFlow==eMapFlow.BottomToTop)
areaTop=root.BoundsRelative.Y-(areaHeight+this.NodeVerticalSpacing*((positions.Near.Count==1?1:positions.Near.Count-1))); //Bottom Top Orientation
else if(m_MapFlow==eMapFlow.LeftToRight || m_MapFlow==eMapFlow.RightToLeft)
areaTop=root.BoundsRelative.Bottom+this.NodeVerticalSpacing; // Top Bottom Orientation
else // Spread
areaTop=root.BoundsRelative.Y+root.BoundsRelative.Height/2-(areaHeight+this.NodeVerticalSpacing*((positions.Near.Count==1?1:positions.Near.Count-1)))/2; // Around spread orientation
PositionNearSubRootNodes(root,positions.Near,areaRightMost,areaTop,areaHeight,ref area);
}
m_Width=area.Width;
m_Height=area.Height;
root.ChildNodesBounds=area;
}
private void PositionFarSubRootNodes(Node root, ArrayList farNodes, int areaLeft, int areaTop, ref Rectangle usedArea)
{
int top=areaTop;
bool twoNodesLayout = (farNodes.Count == 2);
for(int index=0;index<farNodes.Count;index++)
{
Node node=farNodes[index] as Node;
int x=areaLeft+this.NodeHorizontalSpacing;
int y=top;
if(node.ChildNodesBounds.Height>node.BoundsRelative.Height && node.Expanded && node.AnyVisibleNodes)
y+=(node.ChildNodesBounds.Height-node.BoundsRelative.Height)/2;
if(root.BoundsRelative.IntersectsWith(new Rectangle(root.BoundsRelative.X,y,node.BoundsRelative.Width,node.BoundsRelative.Height)))
{
if(twoNodesLayout && index==1)
{
y = root.BoundsRelative.Bottom + this.NodeVerticalSpacing/2;
if(node.ChildNodesBounds.Height>node.BoundsRelative.Height && node.Expanded && node.AnyVisibleNodes)
y+=(node.ChildNodesBounds.Height-node.BoundsRelative.Height)/2;
}
else
{
// Change X position since Y is already accounted for...
x+=(root.BoundsRelative.Right-x+this.NodeHorizontalSpacing);
}
}
x+=node.Offset;
OffsetNodeLocation(node,x,y);
if(node.Expanded && node.AnyVisibleNodes)
{
PositionSubNodes(node,true);
usedArea=Rectangle.Union(usedArea,node.ChildNodesBounds);
}
else
usedArea=Rectangle.Union(usedArea,node.BoundsRelative);
if(node.Expanded && node.AnyVisibleNodes)
{
top+=(Math.Max(node.ChildNodesBounds.Height,node.BoundsRelative.Height)+this.NodeVerticalSpacing);
}
else
{
top+=(node.BoundsRelative.Height+this.NodeVerticalSpacing);
}
}
}
private void PositionNearSubRootNodes(Node root, ArrayList nearNodes, int areaRightMost, int areaTop, int areaHeight, ref Rectangle usedArea)
{
int bottom=areaTop+(areaHeight+this.NodeVerticalSpacing*(nearNodes.Count-1));
bool twoNodesLayout = (nearNodes.Count == 2);
for(int index=0;index<nearNodes.Count;index++)
{
Node node=nearNodes[index] as Node;
int x=areaRightMost-node.BoundsRelative.Width-this.NodeHorizontalSpacing;
int y=0;
if(node.ChildNodesBounds.Height>node.BoundsRelative.Height && node.Expanded && node.AnyVisibleNodes)
y=bottom-((node.ChildNodesBounds.Height-node.BoundsRelative.Height)/2+node.BoundsRelative.Height);
else
y=bottom-node.BoundsRelative.Height;
// Rectangle rNodeArea=new Rectangle(x,y,node.Bounds.Width,node.Bounds.Height);
// rNodeArea.Inflate(this.NodeHorizontalSpacing,this.NodeVerticalSpacing);
//if(root.Bounds.IntersectsWith(rNodeArea))
if(root.BoundsRelative.IntersectsWith(new Rectangle(root.BoundsRelative.X,y,node.BoundsRelative.Width,node.BoundsRelative.Height)))
{
if(twoNodesLayout && index==1)
{
y = root.BoundsRelative.Top - this.NodeVerticalSpacing/2;
if(node.ChildNodesBounds.Height>node.BoundsRelative.Height && node.Expanded && node.AnyVisibleNodes)
y-=((node.ChildNodesBounds.Height-node.BoundsRelative.Height)/2+node.BoundsRelative.Height);
else
y-=node.BoundsRelative.Height;
}
else
{
// Change X position since Y is already accounted for...
x-=(x+node.BoundsRelative.Width-root.BoundsRelative.X+this.NodeHorizontalSpacing);
}
}
x-=node.Offset;
OffsetNodeLocation(node,x,y);
if(node.Expanded && node.AnyVisibleNodes)
{
PositionSubNodes(node,false);
usedArea = Rectangle.Union(usedArea, node.BoundsRelative);
usedArea=Rectangle.Union(usedArea,node.ChildNodesBounds);
}
else
usedArea=Rectangle.Union(usedArea,node.BoundsRelative);
if(node.Expanded && node.AnyVisibleNodes)
{
bottom-=(Math.Max(node.ChildNodesBounds.Height,node.BoundsRelative.Height)+this.NodeVerticalSpacing);
}
else
{
bottom-=(node.BoundsRelative.Height+this.NodeVerticalSpacing);
}
}
}
private void PositionSubNodes(Node parentNode,bool bFar)
{
if(parentNode.Nodes.Count==0)
return;
int y=parentNode.BoundsRelative.Y-(parentNode.ChildNodesBounds.Height-parentNode.BoundsRelative.Height)/2;
int x=parentNode.BoundsRelative.Right+this.SubNodeHorizontalSpacing;
if(!bFar)
{
x=parentNode.BoundsRelative.X-this.SubNodeHorizontalSpacing;
}
Rectangle rChildBounds=Rectangle.Empty;
bool bFirst=true;
if(bFar)
{
foreach(Node node in parentNode.Nodes)
{
if(!node.Visible)
continue;
int top=y;
bool anyVisibleNodes=node.AnyVisibleNodes;
if(node.ChildNodesBounds.Height>node.BoundsRelative.Height && node.Expanded && anyVisibleNodes)
top+=(node.ChildNodesBounds.Height-node.BoundsRelative.Height)/2;
OffsetNodeLocation(node,x,top);
if(node.Expanded && anyVisibleNodes)
{
PositionSubNodes(node,bFar);
y+=(Math.Max(node.BoundsRelative.Height,node.ChildNodesBounds.Height)+this.NodeVerticalSpacing);
}
else y+=(node.BoundsRelative.Height+this.NodeVerticalSpacing);
if(bFirst)
{
rChildBounds=node.BoundsRelative;
bFirst=false;
}
else
rChildBounds=Rectangle.Union(rChildBounds,node.BoundsRelative);
if(!node.ChildNodesBounds.IsEmpty)
rChildBounds=Rectangle.Union(rChildBounds,node.ChildNodesBounds);
}
}
else
{
foreach(Node node in parentNode.Nodes)
{
if(!node.Visible)
continue;
int left=x-node.BoundsRelative.Width;
int top=y;
bool anyVisibleNodes=node.AnyVisibleNodes;
if(node.ChildNodesBounds.Height>node.BoundsRelative.Height && node.Expanded && anyVisibleNodes)
top+=(node.ChildNodesBounds.Height-node.BoundsRelative.Height)/2;
OffsetNodeLocation(node,left,top);
if(node.Expanded && anyVisibleNodes)
{
PositionSubNodes(node,bFar);
y+=(Math.Max(node.BoundsRelative.Height,node.ChildNodesBounds.Height)+this.NodeVerticalSpacing);
}
else y+=(node.BoundsRelative.Height+this.NodeVerticalSpacing);
if(bFirst)
{
rChildBounds=node.BoundsRelative;
bFirst=false;
}
else
rChildBounds=Rectangle.Union(rChildBounds,node.BoundsRelative);
if(!node.ChildNodesBounds.IsEmpty)
rChildBounds=Rectangle.Union(rChildBounds,node.ChildNodesBounds);
}
}
parentNode.ChildNodesBounds=rChildBounds;
}
private int GetMinimumAreaHeight(ArrayList nodes, int rootHeight)
{
int height=rootHeight;
if(nodes.Count==1)
height+=(((Node)nodes[0]).BoundsRelative.Height*2);
else if(nodes.Count>=2)
height+=(((Node)nodes[0]).BoundsRelative.Height+((Node)nodes[1]).BoundsRelative.Height);
return height;
}
private int SubNodeHorizontalSpacing
{
get {return 24;}
}
/// <summary>
/// Returns true if root node should have expanded part
/// </summary>
protected override bool RootHasExpandedPart
{
get {return false;}
}
private struct NodesMapPosition
{
public ArrayList Near;
public ArrayList Far;
public ArrayList Default;
public int NearHeight;
public int FarHeight;
public static NodesMapPosition Empty
{
get
{
NodesMapPosition m;
m.Default=new ArrayList();
m.Near=new ArrayList();
m.Far=new ArrayList();
m.NearHeight=0;
m.FarHeight=0;
return m;
}
}
}
/// <summary>
/// Gets or sets the flow of the sub-root nodes for Map layout.
/// </summary>
public eMapFlow MapFlow
{
get{return m_MapFlow;}
set{m_MapFlow=value;}
}
}
}

View File

@@ -0,0 +1,132 @@
using System.Collections;
using System.Drawing;
using System.Windows.Forms;
namespace DevComponents.Tree.Layout
{
/// <summary>
/// Summary description for NodeTreeLayout.
/// </summary>
internal class NodeTreeLayout:NodeLayout
{
//private bool m_LayoutPerformed=false;
public NodeTreeLayout(TreeGX treeControl, Rectangle clientArea):base(treeControl,clientArea)
{
ExpandPartSize=new Size(9,9);
}
public override void PerformLayout()
{
this.PrepareStyles();
// Get default Columns
ArrayList defaultColInfoList=this.GetDefaultColumnInfo();
Graphics graphics=this.GetGraphics();
try
{
// Loop through each top-level node
Node[] topLevelNodes=this.GetTopLevelNodes();
NodeLayoutContextInfo layoutInfo=GetDefaultNodeLayoutContextInfo(graphics);
foreach(Node childNode in topLevelNodes)
{
layoutInfo.ContextNode=childNode;
ProcessNode(layoutInfo);
}
}
finally
{
if(this.DisposeGraphics)
graphics.Dispose();
}
}
#region Node routines
private void ProcessNode(NodeLayoutContextInfo layoutInfo)
{
Node node=layoutInfo.ContextNode;
if(node.SizeChanged)
{
// Calculate size of the node itself...
LayoutNode(layoutInfo);
// Calculate size and location of node column header if any
// if(node.NodesColumnHeaderVisible)
// {
// layoutInfo.Left+=this.NodeLevelOffset;
// LayoutColumnHeader(layoutInfo);
// layoutInfo.Left-=this.NodeLevelOffset;
// }
}
else if(node.BoundsRelative.Top!=layoutInfo.Top)
{
// Adjust top position
node.SetBounds(new Rectangle(node.BoundsRelative.X,layoutInfo.Top,node.BoundsRelative.Width,node.BoundsRelative.Height));
foreach(Cell c in node.Cells)
c.SetBounds(new Rectangle(c.BoundsRelative.X,layoutInfo.Top,c.BoundsRelative.Width,c.BoundsRelative.Height));
}
// Need to set the Top position properly
layoutInfo.Top+=(node.BoundsRelative.Height+this.NodeVerticalSpacing);
// if(node.Expanded && node.NodesColumnHeaderVisible && node.NodesColumns.Count>0)
// layoutInfo.Top+=node.ColumnHeaderHeight;
if(node.Expanded)
{
int originalLevelOffset=layoutInfo.Left;
layoutInfo.Left+=this.NodeLevelOffset;
ArrayList parentColumns=layoutInfo.ChildColumns;
ArrayList childColumns=GetNodeColumnInfo(node);
foreach(Node childNode in node.Nodes)
{
layoutInfo.ContextNode=childNode;
layoutInfo.ChildColumns=childColumns;
ProcessNode(layoutInfo);
}
layoutInfo.ChildColumns=parentColumns;
layoutInfo.ContextNode=node;
layoutInfo.Left=originalLevelOffset;
}
}
/// <summary>
/// Returns true if expand part space should be accounted for even if they expand part is not visible or need to be displayed. Default value is false.
/// </summary>
protected override bool ReserveExpandPartSpace
{
get
{
return true;
}
}
/// <summary>
/// Gets whether the expand part of the node +/- is aligned to the left of the node in left-to-right layout.
/// </summary>
/// <param name="node">Node to get expand part alignment for</param>
/// <returns>true if node expand part is aligned to the left in left-to-right layout.</returns>
private bool ExpandPartAlignedNear(Node node)
{
return true; // If changed LayoutExpandPart needs to be updated as well
}
// private NodeCollection GetTopLevelNodes()
// {
// return m_Tree.Nodes;
// }
private int NodeLevelOffset
{
get {return 10;}
}
#endregion
}
}