moel@345
|
1 |
using System;
|
moel@345
|
2 |
using System.Collections.Generic;
|
moel@345
|
3 |
using System.Text;
|
moel@345
|
4 |
using System.ComponentModel;
|
moel@345
|
5 |
using System.Windows.Forms;
|
moel@345
|
6 |
using System.Drawing;
|
moel@345
|
7 |
using System.Windows.Forms.VisualStyles;
|
moel@345
|
8 |
using System.Drawing.Imaging;
|
moel@345
|
9 |
|
moel@345
|
10 |
namespace Aga.Controls.Tree
|
moel@345
|
11 |
{
|
moel@345
|
12 |
[TypeConverter(typeof(TreeColumn.TreeColumnConverter)), DesignTimeVisible(false), ToolboxItem(false)]
|
moel@345
|
13 |
public class TreeColumn : Component
|
moel@345
|
14 |
{
|
moel@345
|
15 |
private class TreeColumnConverter : ComponentConverter
|
moel@345
|
16 |
{
|
moel@345
|
17 |
public TreeColumnConverter()
|
moel@345
|
18 |
: base(typeof(TreeColumn))
|
moel@345
|
19 |
{
|
moel@345
|
20 |
}
|
moel@345
|
21 |
|
moel@345
|
22 |
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
|
moel@345
|
23 |
{
|
moel@345
|
24 |
return false;
|
moel@345
|
25 |
}
|
moel@345
|
26 |
}
|
moel@345
|
27 |
|
moel@345
|
28 |
private const int HeaderLeftMargin = 5;
|
moel@345
|
29 |
private const int HeaderRightMargin = 5;
|
moel@345
|
30 |
private const int SortOrderMarkMargin = 8;
|
moel@345
|
31 |
|
moel@345
|
32 |
private TextFormatFlags _headerFlags;
|
moel@345
|
33 |
private TextFormatFlags _baseHeaderFlags = TextFormatFlags.NoPadding |
|
moel@345
|
34 |
TextFormatFlags.EndEllipsis |
|
moel@345
|
35 |
TextFormatFlags.VerticalCenter |
|
moel@345
|
36 |
TextFormatFlags.PreserveGraphicsTranslateTransform;
|
moel@345
|
37 |
|
moel@345
|
38 |
#region Properties
|
moel@345
|
39 |
|
moel@345
|
40 |
private TreeColumnCollection _owner;
|
moel@345
|
41 |
internal TreeColumnCollection Owner
|
moel@345
|
42 |
{
|
moel@345
|
43 |
get { return _owner; }
|
moel@345
|
44 |
set { _owner = value; }
|
moel@345
|
45 |
}
|
moel@345
|
46 |
|
moel@345
|
47 |
[Browsable(false)]
|
moel@345
|
48 |
public int Index
|
moel@345
|
49 |
{
|
moel@345
|
50 |
get
|
moel@345
|
51 |
{
|
moel@345
|
52 |
if (Owner != null)
|
moel@345
|
53 |
return Owner.IndexOf(this);
|
moel@345
|
54 |
else
|
moel@345
|
55 |
return -1;
|
moel@345
|
56 |
}
|
moel@345
|
57 |
}
|
moel@345
|
58 |
|
moel@345
|
59 |
private string _header;
|
moel@345
|
60 |
[Localizable(true)]
|
moel@345
|
61 |
public string Header
|
moel@345
|
62 |
{
|
moel@345
|
63 |
get { return _header; }
|
moel@345
|
64 |
set
|
moel@345
|
65 |
{
|
moel@345
|
66 |
_header = value;
|
moel@345
|
67 |
OnHeaderChanged();
|
moel@345
|
68 |
}
|
moel@345
|
69 |
}
|
moel@345
|
70 |
|
moel@345
|
71 |
private string _tooltipText;
|
moel@345
|
72 |
[Localizable(true)]
|
moel@345
|
73 |
public string TooltipText
|
moel@345
|
74 |
{
|
moel@345
|
75 |
get { return _tooltipText; }
|
moel@345
|
76 |
set { _tooltipText = value; }
|
moel@345
|
77 |
}
|
moel@345
|
78 |
|
moel@345
|
79 |
private int _width;
|
moel@345
|
80 |
[DefaultValue(50), Localizable(true)]
|
moel@345
|
81 |
public int Width
|
moel@345
|
82 |
{
|
moel@345
|
83 |
get
|
moel@345
|
84 |
{
|
moel@345
|
85 |
return _width;
|
moel@345
|
86 |
}
|
moel@345
|
87 |
set
|
moel@345
|
88 |
{
|
moel@345
|
89 |
if (_width != value)
|
moel@345
|
90 |
{
|
moel@345
|
91 |
_width = Math.Max(MinColumnWidth, value);
|
moel@345
|
92 |
if (_maxColumnWidth > 0)
|
moel@345
|
93 |
{
|
moel@345
|
94 |
_width = Math.Min(_width, MaxColumnWidth);
|
moel@345
|
95 |
}
|
moel@345
|
96 |
OnWidthChanged();
|
moel@345
|
97 |
}
|
moel@345
|
98 |
}
|
moel@345
|
99 |
}
|
moel@345
|
100 |
|
moel@345
|
101 |
private int _minColumnWidth;
|
moel@345
|
102 |
[DefaultValue(0)]
|
moel@345
|
103 |
public int MinColumnWidth
|
moel@345
|
104 |
{
|
moel@345
|
105 |
get { return _minColumnWidth; }
|
moel@345
|
106 |
set
|
moel@345
|
107 |
{
|
moel@345
|
108 |
if (value < 0)
|
moel@345
|
109 |
throw new ArgumentOutOfRangeException("value");
|
moel@345
|
110 |
|
moel@345
|
111 |
_minColumnWidth = value;
|
moel@345
|
112 |
Width = Math.Max(value, Width);
|
moel@345
|
113 |
}
|
moel@345
|
114 |
}
|
moel@345
|
115 |
|
moel@345
|
116 |
private int _maxColumnWidth;
|
moel@345
|
117 |
[DefaultValue(0)]
|
moel@345
|
118 |
public int MaxColumnWidth
|
moel@345
|
119 |
{
|
moel@345
|
120 |
get { return _maxColumnWidth; }
|
moel@345
|
121 |
set
|
moel@345
|
122 |
{
|
moel@345
|
123 |
if (value < 0)
|
moel@345
|
124 |
throw new ArgumentOutOfRangeException("value");
|
moel@345
|
125 |
|
moel@345
|
126 |
_maxColumnWidth = value;
|
moel@345
|
127 |
if (value > 0)
|
moel@345
|
128 |
Width = Math.Min(value, _width);
|
moel@345
|
129 |
}
|
moel@345
|
130 |
}
|
moel@345
|
131 |
|
moel@345
|
132 |
private bool _visible = true;
|
moel@345
|
133 |
[DefaultValue(true)]
|
moel@345
|
134 |
public bool IsVisible
|
moel@345
|
135 |
{
|
moel@345
|
136 |
get { return _visible; }
|
moel@345
|
137 |
set
|
moel@345
|
138 |
{
|
moel@345
|
139 |
_visible = value;
|
moel@345
|
140 |
OnIsVisibleChanged();
|
moel@345
|
141 |
}
|
moel@345
|
142 |
}
|
moel@345
|
143 |
|
moel@345
|
144 |
private HorizontalAlignment _textAlign = HorizontalAlignment.Left;
|
moel@345
|
145 |
[DefaultValue(HorizontalAlignment.Left)]
|
moel@345
|
146 |
public HorizontalAlignment TextAlign
|
moel@345
|
147 |
{
|
moel@345
|
148 |
get { return _textAlign; }
|
moel@345
|
149 |
set
|
moel@345
|
150 |
{
|
moel@345
|
151 |
if (value != _textAlign)
|
moel@345
|
152 |
{
|
moel@345
|
153 |
_textAlign = value;
|
moel@345
|
154 |
_headerFlags = _baseHeaderFlags | TextHelper.TranslateAligmentToFlag(value);
|
moel@345
|
155 |
OnHeaderChanged();
|
moel@345
|
156 |
}
|
moel@345
|
157 |
}
|
moel@345
|
158 |
}
|
moel@345
|
159 |
|
moel@345
|
160 |
private bool _sortable = false;
|
moel@345
|
161 |
[DefaultValue(false)]
|
moel@345
|
162 |
public bool Sortable
|
moel@345
|
163 |
{
|
moel@345
|
164 |
get { return _sortable; }
|
moel@345
|
165 |
set { _sortable = value; }
|
moel@345
|
166 |
}
|
moel@345
|
167 |
|
moel@345
|
168 |
private SortOrder _sort_order = SortOrder.None;
|
moel@345
|
169 |
public SortOrder SortOrder
|
moel@345
|
170 |
{
|
moel@345
|
171 |
get { return _sort_order; }
|
moel@345
|
172 |
set
|
moel@345
|
173 |
{
|
moel@345
|
174 |
if (value == _sort_order)
|
moel@345
|
175 |
return;
|
moel@345
|
176 |
_sort_order = value;
|
moel@345
|
177 |
OnSortOrderChanged();
|
moel@345
|
178 |
}
|
moel@345
|
179 |
}
|
moel@345
|
180 |
|
moel@345
|
181 |
public Size SortMarkSize
|
moel@345
|
182 |
{
|
moel@345
|
183 |
get
|
moel@345
|
184 |
{
|
moel@345
|
185 |
if (Application.RenderWithVisualStyles)
|
moel@345
|
186 |
return new Size(9, 5);
|
moel@345
|
187 |
else
|
moel@345
|
188 |
return new Size(7, 4);
|
moel@345
|
189 |
}
|
moel@345
|
190 |
}
|
moel@345
|
191 |
#endregion
|
moel@345
|
192 |
|
moel@345
|
193 |
public TreeColumn():
|
moel@345
|
194 |
this(string.Empty, 50)
|
moel@345
|
195 |
{
|
moel@345
|
196 |
}
|
moel@345
|
197 |
|
moel@345
|
198 |
public TreeColumn(string header, int width)
|
moel@345
|
199 |
{
|
moel@345
|
200 |
_header = header;
|
moel@345
|
201 |
_width = width;
|
moel@345
|
202 |
_headerFlags = _baseHeaderFlags | TextFormatFlags.Left;
|
moel@345
|
203 |
}
|
moel@345
|
204 |
|
moel@345
|
205 |
public override string ToString()
|
moel@345
|
206 |
{
|
moel@345
|
207 |
if (string.IsNullOrEmpty(Header))
|
moel@345
|
208 |
return GetType().Name;
|
moel@345
|
209 |
else
|
moel@345
|
210 |
return Header;
|
moel@345
|
211 |
}
|
moel@345
|
212 |
|
moel@345
|
213 |
protected override void Dispose(bool disposing)
|
moel@345
|
214 |
{
|
moel@345
|
215 |
base.Dispose(disposing);
|
moel@345
|
216 |
}
|
moel@345
|
217 |
|
moel@345
|
218 |
#region Draw
|
moel@345
|
219 |
|
moel@345
|
220 |
private static VisualStyleRenderer _normalRenderer;
|
moel@345
|
221 |
private static VisualStyleRenderer _pressedRenderer;
|
moel@345
|
222 |
private static VisualStyleRenderer _hotRenderer;
|
moel@345
|
223 |
|
moel@345
|
224 |
private static void CreateRenderers()
|
moel@345
|
225 |
{
|
moel@345
|
226 |
if (Application.RenderWithVisualStyles && _normalRenderer == null)
|
moel@345
|
227 |
{
|
moel@345
|
228 |
_normalRenderer = new VisualStyleRenderer(VisualStyleElement.Header.Item.Normal);
|
moel@345
|
229 |
_pressedRenderer = new VisualStyleRenderer(VisualStyleElement.Header.Item.Pressed);
|
moel@345
|
230 |
_hotRenderer = new VisualStyleRenderer(VisualStyleElement.Header.Item.Hot);
|
moel@345
|
231 |
}
|
moel@345
|
232 |
}
|
moel@345
|
233 |
|
moel@345
|
234 |
internal Bitmap CreateGhostImage(Rectangle bounds, Font font)
|
moel@345
|
235 |
{
|
moel@345
|
236 |
Bitmap b = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb);
|
moel@345
|
237 |
Graphics gr = Graphics.FromImage(b);
|
moel@345
|
238 |
gr.FillRectangle(SystemBrushes.ControlDark, bounds);
|
moel@345
|
239 |
DrawContent(gr, bounds, font);
|
moel@345
|
240 |
BitmapHelper.SetAlphaChanelValue(b, 150);
|
moel@345
|
241 |
return b;
|
moel@345
|
242 |
}
|
moel@345
|
243 |
|
moel@345
|
244 |
internal void Draw(Graphics gr, Rectangle bounds, Font font, bool pressed, bool hot)
|
moel@345
|
245 |
{
|
moel@345
|
246 |
DrawBackground(gr, bounds, pressed, hot);
|
moel@345
|
247 |
DrawContent(gr, bounds, font);
|
moel@345
|
248 |
}
|
moel@345
|
249 |
|
moel@345
|
250 |
private void DrawContent(Graphics gr, Rectangle bounds, Font font)
|
moel@345
|
251 |
{
|
moel@345
|
252 |
Rectangle innerBounds = new Rectangle(bounds.X + HeaderLeftMargin, bounds.Y,
|
moel@345
|
253 |
bounds.Width - HeaderLeftMargin - HeaderRightMargin,
|
moel@345
|
254 |
bounds.Height);
|
moel@345
|
255 |
|
moel@345
|
256 |
if (SortOrder != SortOrder.None)
|
moel@345
|
257 |
innerBounds.Width -= (SortMarkSize.Width + SortOrderMarkMargin);
|
moel@345
|
258 |
|
moel@345
|
259 |
Size maxTextSize = TextRenderer.MeasureText(gr, Header, font, innerBounds.Size, TextFormatFlags.NoPadding);
|
moel@345
|
260 |
Size textSize = TextRenderer.MeasureText(gr, Header, font, innerBounds.Size, _baseHeaderFlags);
|
moel@345
|
261 |
|
moel@345
|
262 |
if (SortOrder != SortOrder.None)
|
moel@345
|
263 |
{
|
moel@345
|
264 |
int tw = Math.Min(textSize.Width, innerBounds.Size.Width);
|
moel@345
|
265 |
|
moel@345
|
266 |
int x = 0;
|
moel@345
|
267 |
if (TextAlign == HorizontalAlignment.Left)
|
moel@345
|
268 |
x = innerBounds.X + tw + SortOrderMarkMargin;
|
moel@345
|
269 |
else if (TextAlign == HorizontalAlignment.Right)
|
moel@345
|
270 |
x = innerBounds.Right + SortOrderMarkMargin;
|
moel@345
|
271 |
else
|
moel@345
|
272 |
x = innerBounds.X + tw + (innerBounds.Width - tw) / 2 + SortOrderMarkMargin;
|
moel@345
|
273 |
DrawSortMark(gr, bounds, x);
|
moel@345
|
274 |
}
|
moel@345
|
275 |
|
moel@345
|
276 |
if (textSize.Width < maxTextSize.Width)
|
moel@345
|
277 |
TextRenderer.DrawText(gr, Header, font, innerBounds, SystemColors.ControlText, _baseHeaderFlags | TextFormatFlags.Left);
|
moel@345
|
278 |
else
|
moel@345
|
279 |
TextRenderer.DrawText(gr, Header, font, innerBounds, SystemColors.ControlText, _headerFlags);
|
moel@345
|
280 |
}
|
moel@345
|
281 |
|
moel@345
|
282 |
private void DrawSortMark(Graphics gr, Rectangle bounds, int x)
|
moel@345
|
283 |
{
|
moel@345
|
284 |
int y = bounds.Y + bounds.Height / 2 - 2;
|
moel@345
|
285 |
x = Math.Max(x, bounds.X + SortOrderMarkMargin);
|
moel@345
|
286 |
|
moel@345
|
287 |
int w2 = SortMarkSize.Width / 2;
|
moel@345
|
288 |
if (SortOrder == SortOrder.Ascending)
|
moel@345
|
289 |
{
|
moel@345
|
290 |
Point[] points = new Point[] { new Point(x, y), new Point(x + SortMarkSize.Width, y), new Point(x + w2, y + SortMarkSize.Height) };
|
moel@345
|
291 |
gr.FillPolygon(SystemBrushes.ControlDark, points);
|
moel@345
|
292 |
}
|
moel@345
|
293 |
else if (SortOrder == SortOrder.Descending)
|
moel@345
|
294 |
{
|
moel@345
|
295 |
Point[] points = new Point[] { new Point(x - 1, y + SortMarkSize.Height), new Point(x + SortMarkSize.Width, y + SortMarkSize.Height), new Point(x + w2, y - 1) };
|
moel@345
|
296 |
gr.FillPolygon(SystemBrushes.ControlDark, points);
|
moel@345
|
297 |
}
|
moel@345
|
298 |
}
|
moel@345
|
299 |
|
moel@345
|
300 |
internal static void DrawDropMark(Graphics gr, Rectangle rect)
|
moel@345
|
301 |
{
|
moel@345
|
302 |
gr.FillRectangle(SystemBrushes.HotTrack, rect.X-1, rect.Y, 2, rect.Height);
|
moel@345
|
303 |
}
|
moel@345
|
304 |
|
moel@345
|
305 |
internal static void DrawBackground(Graphics gr, Rectangle bounds, bool pressed, bool hot)
|
moel@345
|
306 |
{
|
moel@345
|
307 |
if (Application.RenderWithVisualStyles)
|
moel@345
|
308 |
{
|
moel@345
|
309 |
CreateRenderers();
|
moel@345
|
310 |
if (pressed)
|
moel@345
|
311 |
_pressedRenderer.DrawBackground(gr, bounds);
|
moel@345
|
312 |
else if (hot)
|
moel@345
|
313 |
_hotRenderer.DrawBackground(gr, bounds);
|
moel@345
|
314 |
else
|
moel@345
|
315 |
_normalRenderer.DrawBackground(gr, bounds);
|
moel@345
|
316 |
}
|
moel@345
|
317 |
else
|
moel@345
|
318 |
{
|
moel@345
|
319 |
gr.FillRectangle(SystemBrushes.Control, bounds);
|
moel@345
|
320 |
Pen p1 = SystemPens.ControlLightLight;
|
moel@345
|
321 |
Pen p2 = SystemPens.ControlDark;
|
moel@345
|
322 |
Pen p3 = SystemPens.ControlDarkDark;
|
moel@345
|
323 |
if (pressed)
|
moel@345
|
324 |
gr.DrawRectangle(p2, bounds.X, bounds.Y, bounds.Width, bounds.Height);
|
moel@345
|
325 |
else
|
moel@345
|
326 |
{
|
moel@345
|
327 |
gr.DrawLine(p1, bounds.X, bounds.Y, bounds.Right, bounds.Y);
|
moel@345
|
328 |
gr.DrawLine(p3, bounds.X, bounds.Bottom, bounds.Right, bounds.Bottom);
|
moel@345
|
329 |
gr.DrawLine(p3, bounds.Right - 1, bounds.Y, bounds.Right - 1, bounds.Bottom - 1);
|
moel@345
|
330 |
gr.DrawLine(p1, bounds.Left, bounds.Y + 1, bounds.Left, bounds.Bottom - 2);
|
moel@345
|
331 |
gr.DrawLine(p2, bounds.Right - 2, bounds.Y + 1, bounds.Right - 2, bounds.Bottom - 2);
|
moel@345
|
332 |
gr.DrawLine(p2, bounds.X, bounds.Bottom - 1, bounds.Right - 2, bounds.Bottom - 1);
|
moel@345
|
333 |
}
|
moel@345
|
334 |
}
|
moel@345
|
335 |
}
|
moel@345
|
336 |
|
moel@345
|
337 |
#endregion
|
moel@345
|
338 |
|
moel@345
|
339 |
#region Events
|
moel@345
|
340 |
|
moel@345
|
341 |
public event EventHandler HeaderChanged;
|
moel@345
|
342 |
private void OnHeaderChanged()
|
moel@345
|
343 |
{
|
moel@345
|
344 |
if (HeaderChanged != null)
|
moel@345
|
345 |
HeaderChanged(this, EventArgs.Empty);
|
moel@345
|
346 |
}
|
moel@345
|
347 |
|
moel@345
|
348 |
public event EventHandler SortOrderChanged;
|
moel@345
|
349 |
private void OnSortOrderChanged()
|
moel@345
|
350 |
{
|
moel@345
|
351 |
if (SortOrderChanged != null)
|
moel@345
|
352 |
SortOrderChanged(this, EventArgs.Empty);
|
moel@345
|
353 |
}
|
moel@345
|
354 |
|
moel@345
|
355 |
public event EventHandler IsVisibleChanged;
|
moel@345
|
356 |
private void OnIsVisibleChanged()
|
moel@345
|
357 |
{
|
moel@345
|
358 |
if (IsVisibleChanged != null)
|
moel@345
|
359 |
IsVisibleChanged(this, EventArgs.Empty);
|
moel@345
|
360 |
}
|
moel@345
|
361 |
|
moel@345
|
362 |
public event EventHandler WidthChanged;
|
moel@345
|
363 |
private void OnWidthChanged()
|
moel@345
|
364 |
{
|
moel@345
|
365 |
if (WidthChanged != null)
|
moel@345
|
366 |
WidthChanged(this, EventArgs.Empty);
|
moel@345
|
367 |
}
|
moel@345
|
368 |
|
moel@345
|
369 |
#endregion
|
moel@345
|
370 |
}
|
moel@345
|
371 |
}
|