moel@345: using System; moel@345: using System.Drawing; moel@345: using System.Diagnostics; moel@345: using System.Drawing.Drawing2D; moel@345: using System.Windows.Forms; moel@345: using Aga.Controls.Tree.NodeControls; moel@345: moel@345: namespace Aga.Controls.Tree moel@345: { moel@345: public partial class TreeViewAdv moel@345: { moel@345: public void AutoSizeColumn(TreeColumn column) moel@345: { moel@345: if (!Columns.Contains(column)) moel@345: throw new ArgumentException("column"); moel@345: moel@345: DrawContext context = new DrawContext(); moel@345: context.Graphics = Graphics.FromImage(new Bitmap(1, 1)); moel@345: context.Font = this.Font; moel@345: int res = 0; moel@345: for (int row = 0; row < RowCount; row++) moel@345: { moel@345: if (row < RowMap.Count) moel@345: { moel@345: int w = 0; moel@345: TreeNodeAdv node = RowMap[row]; moel@345: foreach (NodeControl nc in NodeControls) moel@345: { moel@345: if (nc.ParentColumn == column) moel@345: w += nc.GetActualSize(node, _measureContext).Width; moel@345: } moel@345: res = Math.Max(res, w); moel@345: } moel@345: } moel@345: moel@345: if (res > 0) moel@345: column.Width = res; moel@345: } moel@345: moel@345: private void CreatePens() moel@345: { moel@345: CreateLinePen(); moel@345: CreateMarkPen(); moel@345: } moel@345: moel@345: private void CreateMarkPen() moel@345: { moel@345: GraphicsPath path = new GraphicsPath(); moel@345: path.AddLines(new Point[] { new Point(0, 0), new Point(1, 1), new Point(-1, 1), new Point(0, 0) }); moel@345: CustomLineCap cap = new CustomLineCap(null, path); moel@345: cap.WidthScale = 1.0f; moel@345: moel@345: _markPen = new Pen(_dragDropMarkColor, _dragDropMarkWidth); moel@345: _markPen.CustomStartCap = cap; moel@345: _markPen.CustomEndCap = cap; moel@345: } moel@345: moel@345: private void CreateLinePen() moel@345: { moel@345: _linePen = new Pen(_lineColor); moel@345: _linePen.DashStyle = DashStyle.Dot; moel@345: } moel@345: moel@345: protected override void OnPaint(PaintEventArgs e) moel@345: { moel@345: BeginPerformanceCount(); moel@345: PerformanceAnalyzer.Start("OnPaint"); moel@345: moel@345: DrawContext context = new DrawContext(); moel@345: context.Graphics = e.Graphics; moel@345: context.Font = this.Font; moel@345: context.Enabled = Enabled; moel@345: moel@345: int y = 0; moel@345: int gridHeight = 0; moel@345: moel@345: if (UseColumns) moel@345: { moel@345: DrawColumnHeaders(e.Graphics); moel@345: y += ColumnHeaderHeight; moel@345: if (Columns.Count == 0 || e.ClipRectangle.Height <= y) moel@345: return; moel@345: } moel@345: moel@345: int firstRowY = _rowLayout.GetRowBounds(FirstVisibleRow).Y; moel@345: y -= firstRowY; moel@345: moel@345: e.Graphics.ResetTransform(); moel@345: e.Graphics.TranslateTransform(-OffsetX, y); moel@345: Rectangle displayRect = DisplayRectangle; moel@345: for (int row = FirstVisibleRow; row < RowCount; row++) moel@345: { moel@345: Rectangle rowRect = _rowLayout.GetRowBounds(row); moel@345: gridHeight += rowRect.Height; moel@345: if (rowRect.Y + y > displayRect.Bottom) moel@345: break; moel@345: else moel@345: DrawRow(e, ref context, row, rowRect); moel@345: } moel@345: moel@345: if ((GridLineStyle & GridLineStyle.Vertical) == GridLineStyle.Vertical && UseColumns) moel@345: DrawVerticalGridLines(e.Graphics, firstRowY); moel@345: moel@345: if (_dropPosition.Node != null && DragMode && HighlightDropPosition) moel@345: DrawDropMark(e.Graphics); moel@345: moel@345: e.Graphics.ResetTransform(); moel@345: DrawScrollBarsBox(e.Graphics); moel@345: moel@345: if (DragMode && _dragBitmap != null) moel@345: e.Graphics.DrawImage(_dragBitmap, PointToClient(MousePosition)); moel@345: moel@345: PerformanceAnalyzer.Finish("OnPaint"); moel@345: EndPerformanceCount(e); moel@345: } moel@345: moel@345: private void DrawRow(PaintEventArgs e, ref DrawContext context, int row, Rectangle rowRect) moel@345: { moel@345: TreeNodeAdv node = RowMap[row]; moel@345: context.DrawSelection = DrawSelectionMode.None; moel@345: context.CurrentEditorOwner = CurrentEditorOwner; moel@345: if (DragMode) moel@345: { moel@345: if ((_dropPosition.Node == node) && _dropPosition.Position == NodePosition.Inside && HighlightDropPosition) moel@345: context.DrawSelection = DrawSelectionMode.Active; moel@345: } moel@345: else moel@345: { moel@345: if (node.IsSelected && Focused) moel@345: context.DrawSelection = DrawSelectionMode.Active; moel@345: else if (node.IsSelected && !Focused && !HideSelection) moel@345: context.DrawSelection = DrawSelectionMode.Inactive; moel@345: } moel@345: context.DrawFocus = Focused && CurrentNode == node; moel@345: moel@345: OnRowDraw(e, node, context, row, rowRect); moel@345: moel@346: if ((GridLineStyle & GridLineStyle.Horizontal) == GridLineStyle.Horizontal) { moel@346: e.Graphics.DrawLine(LightGrayPen, 0, rowRect.Bottom, e.Graphics.ClipBounds.Right, rowRect.Bottom); moel@346: } moel@346: moel@345: if (FullRowSelect) moel@345: { moel@345: context.DrawFocus = false; moel@345: if (context.DrawSelection == DrawSelectionMode.Active || context.DrawSelection == DrawSelectionMode.Inactive) moel@345: { moel@345: Rectangle focusRect = new Rectangle(OffsetX, rowRect.Y, ClientRectangle.Width, rowRect.Height); moel@345: if (context.DrawSelection == DrawSelectionMode.Active) moel@345: { moel@346: e.Graphics.FillRectangle(GrayBrush, focusRect); moel@345: context.DrawSelection = DrawSelectionMode.FullRowSelect; moel@345: } moel@345: else moel@345: { moel@346: e.Graphics.FillRectangle(GrayBrush, focusRect); moel@345: context.DrawSelection = DrawSelectionMode.None; moel@345: } moel@345: } moel@345: } moel@345: moel@345: if (ShowLines) moel@345: DrawLines(e.Graphics, node, rowRect); moel@345: moel@345: DrawNode(node, context); moel@345: } moel@345: moel@346: private Brush GrayBrush = new SolidBrush(Color.FromArgb(240, 240, 240)); moel@346: private Pen LightGrayPen = new Pen(Color.FromArgb(247, 247, 247)); moel@346: moel@345: private void DrawVerticalGridLines(Graphics gr, int y) moel@345: { moel@345: int x = 0; moel@345: foreach (TreeColumn c in Columns) moel@345: { moel@345: if (c.IsVisible) moel@345: { moel@345: x += c.Width; moel@345: gr.DrawLine(SystemPens.InactiveBorder, x - 1, y, x - 1, gr.ClipBounds.Bottom); moel@345: } moel@345: } moel@345: } moel@345: moel@345: private void DrawColumnHeaders(Graphics gr) moel@345: { moel@345: PerformanceAnalyzer.Start("DrawColumnHeaders"); moel@345: ReorderColumnState reorder = Input as ReorderColumnState; moel@345: int x = 0; moel@345: TreeColumn.DrawBackground(gr, new Rectangle(0, 0, ClientRectangle.Width + 2, ColumnHeaderHeight - 1), false, false); moel@345: gr.TranslateTransform(-OffsetX, 0); moel@345: foreach (TreeColumn c in Columns) moel@345: { moel@345: if (c.IsVisible) moel@345: { moel@345: if (x >= OffsetX && x - OffsetX < this.Bounds.Width)// skip invisible columns moel@345: { moel@345: Rectangle rect = new Rectangle(x, 0, c.Width, ColumnHeaderHeight - 1); moel@345: gr.SetClip(rect); moel@345: bool pressed = ((Input is ClickColumnState || reorder != null) && ((Input as ColumnState).Column == c)); moel@345: c.Draw(gr, rect, Font, pressed, _hotColumn == c); moel@345: gr.ResetClip(); moel@345: moel@345: if (reorder != null && reorder.DropColumn == c) moel@345: TreeColumn.DrawDropMark(gr, rect); moel@345: } moel@345: x += c.Width; moel@345: } moel@345: } moel@345: moel@345: if (reorder != null) moel@345: { moel@345: if (reorder.DropColumn == null) moel@345: TreeColumn.DrawDropMark(gr, new Rectangle(x, 0, 0, ColumnHeaderHeight)); moel@345: gr.DrawImage(reorder.GhostImage, new Point(reorder.Location.X + + reorder.DragOffset, reorder.Location.Y)); moel@345: } moel@345: PerformanceAnalyzer.Finish("DrawColumnHeaders"); moel@345: } moel@345: moel@345: public void DrawNode(TreeNodeAdv node, DrawContext context) moel@345: { moel@345: foreach (NodeControlInfo item in GetNodeControls(node)) moel@345: { moel@345: if (item.Bounds.Right >= OffsetX && item.Bounds.X - OffsetX < this.Bounds.Width)// skip invisible nodes moel@345: { moel@345: context.Bounds = item.Bounds; moel@345: context.Graphics.SetClip(context.Bounds); moel@345: item.Control.Draw(node, context); moel@345: context.Graphics.ResetClip(); moel@345: } moel@345: } moel@345: } moel@345: moel@345: private void DrawScrollBarsBox(Graphics gr) moel@345: { moel@345: Rectangle r1 = DisplayRectangle; moel@345: Rectangle r2 = ClientRectangle; moel@345: gr.FillRectangle(SystemBrushes.Control, moel@345: new Rectangle(r1.Right, r1.Bottom, r2.Width - r1.Width, r2.Height - r1.Height)); moel@345: } moel@345: moel@345: private void DrawDropMark(Graphics gr) moel@345: { moel@345: if (_dropPosition.Position == NodePosition.Inside) moel@345: return; moel@345: moel@345: Rectangle rect = GetNodeBounds(_dropPosition.Node); moel@345: int right = DisplayRectangle.Right - LeftMargin + OffsetX; moel@345: int y = rect.Y; moel@345: if (_dropPosition.Position == NodePosition.After) moel@345: y = rect.Bottom; moel@345: gr.DrawLine(_markPen, rect.X, y, right, y); moel@345: } moel@345: moel@345: private void DrawLines(Graphics gr, TreeNodeAdv node, Rectangle rowRect) moel@345: { moel@345: if (UseColumns && Columns.Count > 0) moel@345: gr.SetClip(new Rectangle(0, rowRect.Y, Columns[0].Width, rowRect.Bottom)); moel@345: moel@345: TreeNodeAdv curNode = node; moel@345: while (curNode != _root && curNode != null) moel@345: { moel@345: int level = curNode.Level; moel@345: int x = (level - 1) * _indent + NodePlusMinus.ImageSize / 2 + LeftMargin; moel@345: int width = NodePlusMinus.Width - NodePlusMinus.ImageSize / 2; moel@345: int y = rowRect.Y; moel@345: int y2 = y + rowRect.Height; moel@345: moel@345: if (curNode == node) moel@345: { moel@345: int midy = y + rowRect.Height / 2; moel@345: gr.DrawLine(_linePen, x, midy, x + width, midy); moel@345: if (curNode.NextNode == null) moel@345: y2 = y + rowRect.Height / 2; moel@345: } moel@345: moel@345: if (node.Row == 0) moel@345: y = rowRect.Height / 2; moel@345: if (curNode.NextNode != null || curNode == node) moel@345: gr.DrawLine(_linePen, x, y, x, y2); moel@345: moel@345: curNode = curNode.Parent; moel@345: } moel@345: moel@345: gr.ResetClip(); moel@345: } moel@345: moel@345: #region Performance moel@345: moel@345: private double _totalTime; moel@345: private int _paintCount; moel@345: moel@345: [Conditional("PERF_TEST")] moel@345: private void BeginPerformanceCount() moel@345: { moel@345: _paintCount++; moel@345: TimeCounter.Start(); moel@345: } moel@345: moel@345: [Conditional("PERF_TEST")] moel@345: private void EndPerformanceCount(PaintEventArgs e) moel@345: { moel@345: double time = TimeCounter.Finish(); moel@345: _totalTime += time; moel@345: string debugText = string.Format("FPS {0:0.0}; Avg. FPS {1:0.0}", moel@345: 1 / time, 1 / (_totalTime / _paintCount)); moel@345: e.Graphics.FillRectangle(Brushes.White, new Rectangle(DisplayRectangle.Width - 150, DisplayRectangle.Height - 20, 150, 20)); moel@345: e.Graphics.DrawString(debugText, Control.DefaultFont, Brushes.Gray, moel@345: new PointF(DisplayRectangle.Width - 150, DisplayRectangle.Height - 20)); moel@345: } moel@345: #endregion moel@345: moel@345: } moel@345: }