moel@345
|
1 |
using System;
|
moel@345
|
2 |
using System.Drawing;
|
moel@345
|
3 |
using System.Diagnostics;
|
moel@345
|
4 |
using System.Drawing.Drawing2D;
|
moel@345
|
5 |
using System.Windows.Forms;
|
moel@345
|
6 |
using Aga.Controls.Tree.NodeControls;
|
moel@345
|
7 |
|
moel@345
|
8 |
namespace Aga.Controls.Tree
|
moel@345
|
9 |
{
|
moel@345
|
10 |
public partial class TreeViewAdv
|
moel@345
|
11 |
{
|
moel@345
|
12 |
public void AutoSizeColumn(TreeColumn column)
|
moel@345
|
13 |
{
|
moel@345
|
14 |
if (!Columns.Contains(column))
|
moel@345
|
15 |
throw new ArgumentException("column");
|
moel@345
|
16 |
|
moel@345
|
17 |
DrawContext context = new DrawContext();
|
moel@345
|
18 |
context.Graphics = Graphics.FromImage(new Bitmap(1, 1));
|
moel@345
|
19 |
context.Font = this.Font;
|
moel@345
|
20 |
int res = 0;
|
moel@345
|
21 |
for (int row = 0; row < RowCount; row++)
|
moel@345
|
22 |
{
|
moel@345
|
23 |
if (row < RowMap.Count)
|
moel@345
|
24 |
{
|
moel@345
|
25 |
int w = 0;
|
moel@345
|
26 |
TreeNodeAdv node = RowMap[row];
|
moel@345
|
27 |
foreach (NodeControl nc in NodeControls)
|
moel@345
|
28 |
{
|
moel@345
|
29 |
if (nc.ParentColumn == column)
|
moel@345
|
30 |
w += nc.GetActualSize(node, _measureContext).Width;
|
moel@345
|
31 |
}
|
moel@345
|
32 |
res = Math.Max(res, w);
|
moel@345
|
33 |
}
|
moel@345
|
34 |
}
|
moel@345
|
35 |
|
moel@345
|
36 |
if (res > 0)
|
moel@345
|
37 |
column.Width = res;
|
moel@345
|
38 |
}
|
moel@345
|
39 |
|
moel@345
|
40 |
private void CreatePens()
|
moel@345
|
41 |
{
|
moel@345
|
42 |
CreateLinePen();
|
moel@345
|
43 |
CreateMarkPen();
|
moel@345
|
44 |
}
|
moel@345
|
45 |
|
moel@345
|
46 |
private void CreateMarkPen()
|
moel@345
|
47 |
{
|
moel@345
|
48 |
GraphicsPath path = new GraphicsPath();
|
moel@345
|
49 |
path.AddLines(new Point[] { new Point(0, 0), new Point(1, 1), new Point(-1, 1), new Point(0, 0) });
|
moel@345
|
50 |
CustomLineCap cap = new CustomLineCap(null, path);
|
moel@345
|
51 |
cap.WidthScale = 1.0f;
|
moel@345
|
52 |
|
moel@345
|
53 |
_markPen = new Pen(_dragDropMarkColor, _dragDropMarkWidth);
|
moel@345
|
54 |
_markPen.CustomStartCap = cap;
|
moel@345
|
55 |
_markPen.CustomEndCap = cap;
|
moel@345
|
56 |
}
|
moel@345
|
57 |
|
moel@345
|
58 |
private void CreateLinePen()
|
moel@345
|
59 |
{
|
moel@345
|
60 |
_linePen = new Pen(_lineColor);
|
moel@345
|
61 |
_linePen.DashStyle = DashStyle.Dot;
|
moel@345
|
62 |
}
|
moel@345
|
63 |
|
moel@345
|
64 |
protected override void OnPaint(PaintEventArgs e)
|
moel@345
|
65 |
{
|
moel@345
|
66 |
BeginPerformanceCount();
|
moel@345
|
67 |
PerformanceAnalyzer.Start("OnPaint");
|
moel@345
|
68 |
|
moel@345
|
69 |
DrawContext context = new DrawContext();
|
moel@345
|
70 |
context.Graphics = e.Graphics;
|
moel@345
|
71 |
context.Font = this.Font;
|
moel@345
|
72 |
context.Enabled = Enabled;
|
moel@345
|
73 |
|
moel@345
|
74 |
int y = 0;
|
moel@345
|
75 |
int gridHeight = 0;
|
moel@345
|
76 |
|
moel@345
|
77 |
if (UseColumns)
|
moel@345
|
78 |
{
|
moel@345
|
79 |
DrawColumnHeaders(e.Graphics);
|
moel@345
|
80 |
y += ColumnHeaderHeight;
|
moel@345
|
81 |
if (Columns.Count == 0 || e.ClipRectangle.Height <= y)
|
moel@345
|
82 |
return;
|
moel@345
|
83 |
}
|
moel@345
|
84 |
|
moel@345
|
85 |
int firstRowY = _rowLayout.GetRowBounds(FirstVisibleRow).Y;
|
moel@345
|
86 |
y -= firstRowY;
|
moel@345
|
87 |
|
moel@345
|
88 |
e.Graphics.ResetTransform();
|
moel@345
|
89 |
e.Graphics.TranslateTransform(-OffsetX, y);
|
moel@345
|
90 |
Rectangle displayRect = DisplayRectangle;
|
moel@345
|
91 |
for (int row = FirstVisibleRow; row < RowCount; row++)
|
moel@345
|
92 |
{
|
moel@345
|
93 |
Rectangle rowRect = _rowLayout.GetRowBounds(row);
|
moel@345
|
94 |
gridHeight += rowRect.Height;
|
moel@345
|
95 |
if (rowRect.Y + y > displayRect.Bottom)
|
moel@345
|
96 |
break;
|
moel@345
|
97 |
else
|
moel@345
|
98 |
DrawRow(e, ref context, row, rowRect);
|
moel@345
|
99 |
}
|
moel@345
|
100 |
|
moel@345
|
101 |
if ((GridLineStyle & GridLineStyle.Vertical) == GridLineStyle.Vertical && UseColumns)
|
moel@345
|
102 |
DrawVerticalGridLines(e.Graphics, firstRowY);
|
moel@345
|
103 |
|
moel@345
|
104 |
if (_dropPosition.Node != null && DragMode && HighlightDropPosition)
|
moel@345
|
105 |
DrawDropMark(e.Graphics);
|
moel@345
|
106 |
|
moel@345
|
107 |
e.Graphics.ResetTransform();
|
moel@345
|
108 |
DrawScrollBarsBox(e.Graphics);
|
moel@345
|
109 |
|
moel@345
|
110 |
if (DragMode && _dragBitmap != null)
|
moel@345
|
111 |
e.Graphics.DrawImage(_dragBitmap, PointToClient(MousePosition));
|
moel@345
|
112 |
|
moel@345
|
113 |
PerformanceAnalyzer.Finish("OnPaint");
|
moel@345
|
114 |
EndPerformanceCount(e);
|
moel@345
|
115 |
}
|
moel@345
|
116 |
|
moel@345
|
117 |
private void DrawRow(PaintEventArgs e, ref DrawContext context, int row, Rectangle rowRect)
|
moel@345
|
118 |
{
|
moel@345
|
119 |
TreeNodeAdv node = RowMap[row];
|
moel@345
|
120 |
context.DrawSelection = DrawSelectionMode.None;
|
moel@345
|
121 |
context.CurrentEditorOwner = CurrentEditorOwner;
|
moel@345
|
122 |
if (DragMode)
|
moel@345
|
123 |
{
|
moel@345
|
124 |
if ((_dropPosition.Node == node) && _dropPosition.Position == NodePosition.Inside && HighlightDropPosition)
|
moel@345
|
125 |
context.DrawSelection = DrawSelectionMode.Active;
|
moel@345
|
126 |
}
|
moel@345
|
127 |
else
|
moel@345
|
128 |
{
|
moel@345
|
129 |
if (node.IsSelected && Focused)
|
moel@345
|
130 |
context.DrawSelection = DrawSelectionMode.Active;
|
moel@345
|
131 |
else if (node.IsSelected && !Focused && !HideSelection)
|
moel@345
|
132 |
context.DrawSelection = DrawSelectionMode.Inactive;
|
moel@345
|
133 |
}
|
moel@345
|
134 |
context.DrawFocus = Focused && CurrentNode == node;
|
moel@345
|
135 |
|
moel@345
|
136 |
OnRowDraw(e, node, context, row, rowRect);
|
moel@345
|
137 |
|
moel@346
|
138 |
if ((GridLineStyle & GridLineStyle.Horizontal) == GridLineStyle.Horizontal) {
|
moel@346
|
139 |
e.Graphics.DrawLine(LightGrayPen, 0, rowRect.Bottom, e.Graphics.ClipBounds.Right, rowRect.Bottom);
|
moel@346
|
140 |
}
|
moel@346
|
141 |
|
moel@345
|
142 |
if (FullRowSelect)
|
moel@345
|
143 |
{
|
moel@345
|
144 |
context.DrawFocus = false;
|
moel@345
|
145 |
if (context.DrawSelection == DrawSelectionMode.Active || context.DrawSelection == DrawSelectionMode.Inactive)
|
moel@345
|
146 |
{
|
moel@345
|
147 |
Rectangle focusRect = new Rectangle(OffsetX, rowRect.Y, ClientRectangle.Width, rowRect.Height);
|
moel@345
|
148 |
if (context.DrawSelection == DrawSelectionMode.Active)
|
moel@345
|
149 |
{
|
moel@346
|
150 |
e.Graphics.FillRectangle(GrayBrush, focusRect);
|
moel@345
|
151 |
context.DrawSelection = DrawSelectionMode.FullRowSelect;
|
moel@345
|
152 |
}
|
moel@345
|
153 |
else
|
moel@345
|
154 |
{
|
moel@346
|
155 |
e.Graphics.FillRectangle(GrayBrush, focusRect);
|
moel@345
|
156 |
context.DrawSelection = DrawSelectionMode.None;
|
moel@345
|
157 |
}
|
moel@345
|
158 |
}
|
moel@345
|
159 |
}
|
moel@345
|
160 |
|
moel@345
|
161 |
if (ShowLines)
|
moel@345
|
162 |
DrawLines(e.Graphics, node, rowRect);
|
moel@345
|
163 |
|
moel@345
|
164 |
DrawNode(node, context);
|
moel@345
|
165 |
}
|
moel@345
|
166 |
|
moel@346
|
167 |
private Brush GrayBrush = new SolidBrush(Color.FromArgb(240, 240, 240));
|
moel@346
|
168 |
private Pen LightGrayPen = new Pen(Color.FromArgb(247, 247, 247));
|
moel@346
|
169 |
|
moel@345
|
170 |
private void DrawVerticalGridLines(Graphics gr, int y)
|
moel@345
|
171 |
{
|
moel@345
|
172 |
int x = 0;
|
moel@345
|
173 |
foreach (TreeColumn c in Columns)
|
moel@345
|
174 |
{
|
moel@345
|
175 |
if (c.IsVisible)
|
moel@345
|
176 |
{
|
moel@345
|
177 |
x += c.Width;
|
moel@345
|
178 |
gr.DrawLine(SystemPens.InactiveBorder, x - 1, y, x - 1, gr.ClipBounds.Bottom);
|
moel@345
|
179 |
}
|
moel@345
|
180 |
}
|
moel@345
|
181 |
}
|
moel@345
|
182 |
|
moel@345
|
183 |
private void DrawColumnHeaders(Graphics gr)
|
moel@345
|
184 |
{
|
moel@345
|
185 |
PerformanceAnalyzer.Start("DrawColumnHeaders");
|
moel@345
|
186 |
ReorderColumnState reorder = Input as ReorderColumnState;
|
moel@345
|
187 |
int x = 0;
|
moel@345
|
188 |
TreeColumn.DrawBackground(gr, new Rectangle(0, 0, ClientRectangle.Width + 2, ColumnHeaderHeight - 1), false, false);
|
moel@345
|
189 |
gr.TranslateTransform(-OffsetX, 0);
|
moel@345
|
190 |
foreach (TreeColumn c in Columns)
|
moel@345
|
191 |
{
|
moel@345
|
192 |
if (c.IsVisible)
|
moel@345
|
193 |
{
|
moel@345
|
194 |
if (x >= OffsetX && x - OffsetX < this.Bounds.Width)// skip invisible columns
|
moel@345
|
195 |
{
|
moel@345
|
196 |
Rectangle rect = new Rectangle(x, 0, c.Width, ColumnHeaderHeight - 1);
|
moel@345
|
197 |
gr.SetClip(rect);
|
moel@345
|
198 |
bool pressed = ((Input is ClickColumnState || reorder != null) && ((Input as ColumnState).Column == c));
|
moel@345
|
199 |
c.Draw(gr, rect, Font, pressed, _hotColumn == c);
|
moel@345
|
200 |
gr.ResetClip();
|
moel@345
|
201 |
|
moel@345
|
202 |
if (reorder != null && reorder.DropColumn == c)
|
moel@345
|
203 |
TreeColumn.DrawDropMark(gr, rect);
|
moel@345
|
204 |
}
|
moel@345
|
205 |
x += c.Width;
|
moel@345
|
206 |
}
|
moel@345
|
207 |
}
|
moel@345
|
208 |
|
moel@345
|
209 |
if (reorder != null)
|
moel@345
|
210 |
{
|
moel@345
|
211 |
if (reorder.DropColumn == null)
|
moel@345
|
212 |
TreeColumn.DrawDropMark(gr, new Rectangle(x, 0, 0, ColumnHeaderHeight));
|
moel@345
|
213 |
gr.DrawImage(reorder.GhostImage, new Point(reorder.Location.X + + reorder.DragOffset, reorder.Location.Y));
|
moel@345
|
214 |
}
|
moel@345
|
215 |
PerformanceAnalyzer.Finish("DrawColumnHeaders");
|
moel@345
|
216 |
}
|
moel@345
|
217 |
|
moel@345
|
218 |
public void DrawNode(TreeNodeAdv node, DrawContext context)
|
moel@345
|
219 |
{
|
moel@345
|
220 |
foreach (NodeControlInfo item in GetNodeControls(node))
|
moel@345
|
221 |
{
|
moel@345
|
222 |
if (item.Bounds.Right >= OffsetX && item.Bounds.X - OffsetX < this.Bounds.Width)// skip invisible nodes
|
moel@345
|
223 |
{
|
moel@345
|
224 |
context.Bounds = item.Bounds;
|
moel@345
|
225 |
context.Graphics.SetClip(context.Bounds);
|
moel@345
|
226 |
item.Control.Draw(node, context);
|
moel@345
|
227 |
context.Graphics.ResetClip();
|
moel@345
|
228 |
}
|
moel@345
|
229 |
}
|
moel@345
|
230 |
}
|
moel@345
|
231 |
|
moel@345
|
232 |
private void DrawScrollBarsBox(Graphics gr)
|
moel@345
|
233 |
{
|
moel@345
|
234 |
Rectangle r1 = DisplayRectangle;
|
moel@345
|
235 |
Rectangle r2 = ClientRectangle;
|
moel@345
|
236 |
gr.FillRectangle(SystemBrushes.Control,
|
moel@345
|
237 |
new Rectangle(r1.Right, r1.Bottom, r2.Width - r1.Width, r2.Height - r1.Height));
|
moel@345
|
238 |
}
|
moel@345
|
239 |
|
moel@345
|
240 |
private void DrawDropMark(Graphics gr)
|
moel@345
|
241 |
{
|
moel@345
|
242 |
if (_dropPosition.Position == NodePosition.Inside)
|
moel@345
|
243 |
return;
|
moel@345
|
244 |
|
moel@345
|
245 |
Rectangle rect = GetNodeBounds(_dropPosition.Node);
|
moel@345
|
246 |
int right = DisplayRectangle.Right - LeftMargin + OffsetX;
|
moel@345
|
247 |
int y = rect.Y;
|
moel@345
|
248 |
if (_dropPosition.Position == NodePosition.After)
|
moel@345
|
249 |
y = rect.Bottom;
|
moel@345
|
250 |
gr.DrawLine(_markPen, rect.X, y, right, y);
|
moel@345
|
251 |
}
|
moel@345
|
252 |
|
moel@345
|
253 |
private void DrawLines(Graphics gr, TreeNodeAdv node, Rectangle rowRect)
|
moel@345
|
254 |
{
|
moel@345
|
255 |
if (UseColumns && Columns.Count > 0)
|
moel@345
|
256 |
gr.SetClip(new Rectangle(0, rowRect.Y, Columns[0].Width, rowRect.Bottom));
|
moel@345
|
257 |
|
moel@345
|
258 |
TreeNodeAdv curNode = node;
|
moel@345
|
259 |
while (curNode != _root && curNode != null)
|
moel@345
|
260 |
{
|
moel@345
|
261 |
int level = curNode.Level;
|
moel@345
|
262 |
int x = (level - 1) * _indent + NodePlusMinus.ImageSize / 2 + LeftMargin;
|
moel@345
|
263 |
int width = NodePlusMinus.Width - NodePlusMinus.ImageSize / 2;
|
moel@345
|
264 |
int y = rowRect.Y;
|
moel@345
|
265 |
int y2 = y + rowRect.Height;
|
moel@345
|
266 |
|
moel@345
|
267 |
if (curNode == node)
|
moel@345
|
268 |
{
|
moel@345
|
269 |
int midy = y + rowRect.Height / 2;
|
moel@345
|
270 |
gr.DrawLine(_linePen, x, midy, x + width, midy);
|
moel@345
|
271 |
if (curNode.NextNode == null)
|
moel@345
|
272 |
y2 = y + rowRect.Height / 2;
|
moel@345
|
273 |
}
|
moel@345
|
274 |
|
moel@345
|
275 |
if (node.Row == 0)
|
moel@345
|
276 |
y = rowRect.Height / 2;
|
moel@345
|
277 |
if (curNode.NextNode != null || curNode == node)
|
moel@345
|
278 |
gr.DrawLine(_linePen, x, y, x, y2);
|
moel@345
|
279 |
|
moel@345
|
280 |
curNode = curNode.Parent;
|
moel@345
|
281 |
}
|
moel@345
|
282 |
|
moel@345
|
283 |
gr.ResetClip();
|
moel@345
|
284 |
}
|
moel@345
|
285 |
|
moel@345
|
286 |
#region Performance
|
moel@345
|
287 |
|
moel@345
|
288 |
private double _totalTime;
|
moel@345
|
289 |
private int _paintCount;
|
moel@345
|
290 |
|
moel@345
|
291 |
[Conditional("PERF_TEST")]
|
moel@345
|
292 |
private void BeginPerformanceCount()
|
moel@345
|
293 |
{
|
moel@345
|
294 |
_paintCount++;
|
moel@345
|
295 |
TimeCounter.Start();
|
moel@345
|
296 |
}
|
moel@345
|
297 |
|
moel@345
|
298 |
[Conditional("PERF_TEST")]
|
moel@345
|
299 |
private void EndPerformanceCount(PaintEventArgs e)
|
moel@345
|
300 |
{
|
moel@345
|
301 |
double time = TimeCounter.Finish();
|
moel@345
|
302 |
_totalTime += time;
|
moel@345
|
303 |
string debugText = string.Format("FPS {0:0.0}; Avg. FPS {1:0.0}",
|
moel@345
|
304 |
1 / time, 1 / (_totalTime / _paintCount));
|
moel@345
|
305 |
e.Graphics.FillRectangle(Brushes.White, new Rectangle(DisplayRectangle.Width - 150, DisplayRectangle.Height - 20, 150, 20));
|
moel@345
|
306 |
e.Graphics.DrawString(debugText, Control.DefaultFont, Brushes.Gray,
|
moel@345
|
307 |
new PointF(DisplayRectangle.Width - 150, DisplayRectangle.Height - 20));
|
moel@345
|
308 |
}
|
moel@345
|
309 |
#endregion
|
moel@345
|
310 |
|
moel@345
|
311 |
}
|
moel@345
|
312 |
}
|