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: }