* X11Keyboard.cs: Detect and use the num lock mask.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TreeView.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004 Novell, Inc.
21 //
22 // Authors:
23 //      Jackson Harper (jackson@ximian.com)
24
25
26 using System;
27 using System.Drawing;
28 using System.Drawing.Drawing2D;
29 using System.Collections;
30
31 namespace System.Windows.Forms {
32
33         public class TreeView : Control {
34
35                 private string path_separator = "\\";
36                 private int item_height = -1;
37                 private bool sorted;
38                 private TreeNode top_node;
39                 internal TreeNode root_node;
40                 private TreeNodeCollection nodes;
41                 private int total_node_count;
42
43                 private ImageList image_list;
44                 private int image_index = -1;
45                 private int selected_image_index = -1;
46
47                 private bool full_row_select;
48                 private bool hot_tracking;
49                 private int indent = 19;
50
51                 private bool checkboxes;
52                 private bool label_edit;
53                 private bool scrollable;
54                 private bool show_lines = true;
55                 private bool show_root_lines = true;
56                 private bool show_plus_minus = true;
57
58                 private int update_stack;
59
60                 private TreeViewEventHandler on_after_check;
61                 private TreeViewEventHandler on_after_collapse;
62                 private TreeViewEventHandler on_after_expand;
63                 private NodeLabelEditEventHandler on_after_label_edit;
64                 private TreeViewEventHandler on_after_select;
65                 private TreeViewCancelEventHandler on_before_check;
66                 private TreeViewCancelEventHandler on_before_collapse;
67                 private TreeViewCancelEventHandler on_before_expand;
68                 private NodeLabelEditEventHandler on_before_label_edit;
69                 private TreeViewCancelEventHandler on_before_select;
70
71                 private Pen dash;
72
73                 public TreeView ()
74                 {
75                         root_node = new TreeNode (this);
76                         root_node.Text = "ROOT NODE";
77                         nodes = new TreeNodeCollection (root_node);
78                         root_node.SetNodes (nodes);
79
80                         MouseDown += new MouseEventHandler (MouseDownHandler);
81                         SizeChanged += new EventHandler (SizeChangedHandler);
82
83                         SetStyle (ControlStyles.AllPaintingInWmPaint, true);
84                         SetStyle (ControlStyles.UserPaint, true);
85
86                         dash = new Pen (SystemColors.ControlLight, 1);
87                 }
88
89                 public string PathSeparator {
90                         get { return path_separator; }
91                         set { path_separator = value; }
92                 }
93
94                 public bool Sorted {
95                         get { return sorted; }
96                         set {
97                                 if (sorted != value)
98                                         sorted = value;
99                                 if (sorted)
100                                         Nodes.Sort ();
101                         }
102                 }
103
104                 public TreeNode TopNode {
105                         get { return top_node; }
106                 }
107
108                 public TreeNodeCollection Nodes {
109                         get { return nodes; }
110                 }
111
112                 public int ItemHeight {
113                         get {
114                                 if (item_height == -1)
115                                         return FontHeight + 3;
116                                 return item_height;
117                         }
118                         set {
119                                 if (value == item_height)
120                                         return;
121                                 item_height = value;
122                                 Refresh ();
123                         }
124                 }
125
126                 public int VisibleCount {
127                         get {
128                                 return ClientRectangle.Height / ItemHeight;
129                         }
130                 }
131
132                 [MonoTODO ("Anything special need to be done here?")]
133                 public ImageList ImageList {
134                         get { return image_list; }
135                         set { image_list = value; }
136                 }
137
138                 public int ImageIndex {
139                         get { return image_index; }
140                         set {
141                                 if (value < 0) {
142                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
143                                                 "'value' must be greater than or equal to 0.");
144                                 }
145                                 image_index = value;
146                         }
147                 }
148
149                 public int SelectedImageIndex {
150                         get { return selected_image_index; }
151                         set {
152                                 if (value < 0) {
153                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
154                                                 "'value' must be greater than or equal to 0.");
155                                 }
156                         }
157                 }
158
159                 public override Color BackColor {
160                         get { return base.BackColor;}
161                         set { base.BackColor = value; }
162                 }
163
164                 public override Image BackgroundImage {
165                         get { return base.BackgroundImage; }
166                         set { base.BackgroundImage = value; }
167                 }
168
169                 /*
170                    Commented out until this is implemented in Control
171                 public override BorderStyle BorderStyle {
172                         get { return base.BorderStyle; }
173                         set { base.BorderStyle = value; }
174                 }
175                 */
176
177                 public override Color ForeColor {
178                         get { return base.ForeColor; }
179                         set { base.ForeColor = value; }
180                 }
181
182                 public override string Text {
183                         get { return base.Text; }
184                         set { base.Text = value; }
185                 }
186
187                 public bool FullRowSelect {
188                         get { return full_row_select; }
189                         set {
190                                 if (value == full_row_select)
191                                         return;
192                                 full_row_select = value;
193                                 Refresh ();
194                         }
195                 }
196
197                 public bool HotTracking {
198                         get { return hot_tracking; }
199                         set { hot_tracking = value; }
200                 }
201
202                 public int Indent {
203                         get { return indent; }
204                         set {
205                                 if (indent == value)
206                                         return;
207                                 if (value > 32000) {
208                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'Indent'. " +
209                                                         "'Indent' must be less than or equal to 32000");
210                                 }       
211                                 if (value < 0) {
212                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'Indent'. " +
213                                                         "'Indent' must be greater than or equal to 0.");
214                                 }
215                                 indent = value;
216                                 Refresh ();
217                         }
218                 }
219
220                 public bool LabelEdit {
221                         get { return label_edit; }
222                         set { label_edit = value; }
223                 }
224
225                 public bool Scrollable {
226                         get { return scrollable; }
227                         set {
228                                 if (scrollable == value)
229                                         return;
230                                 scrollable = value;
231                         }
232                 }
233
234                 public bool ShowLines {
235                         get { return show_lines; }
236                         set {
237                                 if (show_lines == value)
238                                         return;
239                                 show_lines = value;
240                                 Refresh ();
241                         }
242                 }
243
244                 public bool ShowRootLines {
245                         get { return show_root_lines; }
246                         set {
247                                 if (show_root_lines == value)
248                                         return;
249                                 show_root_lines = value;
250                                 Refresh ();
251                         }
252                 }
253
254                 public bool CheckBoxes {
255                         get { return checkboxes; }
256                         set {
257                                 if (value == checkboxes)
258                                         return;
259                                 checkboxes = value;
260                                 Refresh ();
261                         }
262                 }
263
264                 public bool ShowPlusMinus {
265                         get { return show_plus_minus; }
266                         set {
267                                 if (show_plus_minus == value)
268                                         return;
269                                 show_plus_minus = value;
270                                 Refresh ();
271                         }
272                 }
273
274                 [MonoTODO ("Anything extra needed here")]
275                 protected override CreateParams CreateParams {
276                         get {
277                                 CreateParams cp = base.CreateParams;
278                                 return cp;
279                         }
280                 }
281
282                 
283                 protected override Size DefaultSize {
284                         get { return new Size (121, 97); }
285                 }
286
287                 internal int TotalNodeCount {
288                         get { return total_node_count; }
289                         set { total_node_count = value; }
290                 }
291
292                 protected override void CreateHandle ()
293                 {
294                         base.CreateHandle ();
295                 }
296
297                 protected override void Dispose (bool disposing)
298                 {
299                         if (disposing) {
300                                 if (image_list != null)
301                                         image_list.Dispose ();
302                         }
303                         base.Dispose (disposing);
304                 }
305
306                 [MonoTODO ("What does the state effect?")]
307                 protected OwnerDrawPropertyBag GetItemRenderStyles (TreeNode node, int state)
308                 {
309                         return node.prop_bag;
310                 }
311
312                 [MonoTODO ("Need to know if we are editing, not if editing is enabled")]
313                 protected override bool IsInputKey (Keys key_data)
314                 {
315                         if (label_edit && (key_data & Keys.Alt) == 0)
316                         {
317                                 switch (key_data & Keys.KeyCode) {
318                                 case Keys.Enter:
319                                 case Keys.Escape:
320                                 case Keys.Prior:
321                                 case Keys.Next:
322                                 case Keys.End:
323                                 case Keys.Home:
324                                 case Keys.Left:
325                                 case Keys.Up:
326                                 case Keys.Right:
327                                 case Keys.Down:
328                                         return true;
329                                 }
330                         }
331                         return base.IsInputKey (key_data);
332                 }
333
334                 protected virtual void OnAfterCheck (TreeViewEventArgs e)
335                 {
336                         if (on_after_check != null)
337                                 on_after_check (this, e);
338                 }
339
340                 protected internal virtual void OnAfterCollapse (TreeViewEventArgs e)
341                 {
342                         if (on_after_collapse != null)
343                                 on_after_collapse (this, e);
344                 }
345
346                 protected internal virtual void OnAfterExpand (TreeViewEventArgs e)
347                 {
348                         if (on_after_expand != null)
349                                 on_after_expand (this, e);
350                 }
351
352                 protected virtual void OnAfterLabelEdit (NodeLabelEditEventArgs e)
353                 {
354                         if (on_after_label_edit != null)
355                                 on_after_label_edit (this, e);
356                 }
357
358                 protected virtual void OnAfterSelect (TreeViewEventArgs e)
359                 {
360                         if (on_after_select != null)
361                                 on_after_select (this, e);
362                 }
363
364                 protected virtual void OnBeforeCheck (TreeViewCancelEventArgs e)
365                 {
366                         if (on_before_check != null)
367                                 on_before_check (this, e);
368                 }
369
370                 protected internal virtual void OnBeforeCollapse (TreeViewCancelEventArgs e)
371                 {
372                         if (on_before_collapse != null)
373                                 on_before_collapse (this, e);
374                 }
375
376                 protected internal virtual void OnBeforeExpand (TreeViewCancelEventArgs e)
377                 {
378                         if (on_before_expand != null)
379                                 on_before_expand (this, e);
380                 }
381
382                 protected virtual void OnBeforeLabelEdit (NodeLabelEditEventArgs e)
383                 {
384                         if (on_before_label_edit != null)
385                                 on_before_label_edit (this, e);
386                 }
387
388                 protected virtual void OnBeforeSelect (TreeViewCancelEventArgs e)
389                 {
390                         if (on_before_select != null)
391                                 on_before_select (this, e);
392                 }
393
394                 protected override void OnHandleCreated (EventArgs e)
395                 {
396                         base.OnHandleCreated (e);
397                 }
398
399                 protected override void OnHandleDestroyed (EventArgs e)
400                 {
401                         base.OnHandleDestroyed (e);
402                 }
403
404                 public void BeginUpdate ()
405                 {
406                         if (!IsHandleCreated)
407                                 return;
408                         update_stack++;
409                 }
410
411                 public void EndUpdate ()
412                 {
413                         if (!IsHandleCreated)
414                                 return;
415
416                         if (update_stack > 1) {
417                                 update_stack--;
418                         } else {
419                                 update_stack = 0;
420                                 Refresh ();
421                         }
422                 }
423
424                 public void ExpandAll ()
425                 {
426                         root_node.ExpandAll ();
427                 }
428
429                 public void CollapseAll ()
430                 {
431                         root_node.CollapseAll ();
432                 }
433
434                 public TreeNode GetNodeAt (Point pt)
435                 {
436                         return GetNodeAt (pt.X, pt.Y);
437                 }
438
439                 public TreeNode GetNodeAt (int x, int y)
440                 {
441                         if (top_node == null)
442                                 top_node = nodes [0];
443
444                         OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (TopNode);
445                         int move = y / ItemHeight;
446
447                         for (int i = 0; i < move; i++) {
448                                 if (!o.MoveNext ())
449                                         return null;
450                         }
451
452                         // Make sure it is in the horizontal bounding box
453                         if (o.CurrentNode.Bounds.Left > x && o.CurrentNode.Bounds.Right < x)
454                                 return o.CurrentNode;
455
456                         return null;
457                 }
458
459                 public int GetNodeCount (bool include_subtrees)
460                 {
461                         return root_node.GetNodeCount (include_subtrees);
462                 }
463
464                 public override string ToString ()
465                 {
466                         int count = Nodes.Count;
467                         if (count < 0)
468                                 return String.Concat (base.ToString (), "Node Count: 0");
469                         return String.Concat (base.ToString (), "Node Count: ", count, " Nodes[0]: ", Nodes [0]);
470                                                 
471                 }
472
473                 protected override void WndProc(ref Message m)
474                 {
475                         switch ((Msg) m.Msg) {
476                         case Msg.WM_PAINT: {                            
477                                 PaintEventArgs  paint_event;
478
479                                 paint_event = XplatUI.PaintEventStart (Handle);
480                                 DoPaint (paint_event);
481                                 XplatUI.PaintEventEnd (Handle);
482                                 return;
483                         }
484                         case Msg.WM_LBUTTONDBLCLK:
485                                 Console.WriteLine ("double click");
486                                 break;
487                         }
488                         base.WndProc (ref m);
489                 }
490
491                 internal void UpdateBelow (TreeNode node)
492                 {
493                         // Invalidate all these nodes and the nodes below it
494                 }
495
496                 private void DoPaint (PaintEventArgs pe)
497                 {
498                         if (Width <= 0 || Height <=  0 || Visible == false)
499                                 return;
500
501                         Draw();
502                         pe.Graphics.DrawImage (ImageBuffer, 0, 0);
503                 }
504
505                 private bool add_hscroll;
506                 private bool add_vscroll;
507                 private int max_node_width;
508                 
509                 private void Draw ()
510                 {
511                         DateTime start = DateTime.Now;
512                         if (top_node == null && Nodes.Count > 0)
513                                 top_node = nodes [0];
514                         // Decide if we need a scrollbar
515                         int visible_node_count = GetVisibleNodeCount ();
516                         Console.WriteLine ("time to get visible node count:  " + (DateTime.Now - start));
517                         int node_count = 0;
518
519                         Rectangle fill = ClientRectangle;
520                         Rectangle vclip = Rectangle.Empty;
521
522                         add_vscroll = false;
523                         add_hscroll = false;
524
525                         if ((visible_node_count * ItemHeight) > ClientRectangle.Height) {
526                                 add_vscroll = true;
527                                 if (vbar == null)
528                                         vbar = new VScrollBar ();
529                                 vclip = new Rectangle (ClientRectangle.Width - vbar.Width, 0, vbar.Width, Height);
530                                 fill.Width -= vbar.Width;
531                                 DeviceContext.ExcludeClip (vclip);
532                         }
533
534                         DeviceContext.FillRectangle (new SolidBrush (Color.White), fill);
535                         
536                         int depth = 0;
537                         int item_height = ItemHeight;
538                         Font font = Font;
539                         int height = ClientRectangle.Height;
540
541                         foreach (TreeNode node in nodes) {
542                                 DrawNode (node, ref depth, ref node_count, item_height,
543                                                 font, ref visible_node_count, height);
544                                 depth = 0;
545                         }
546
547                         if (max_node_width > ClientRectangle.Width) {
548                                 add_hscroll = true;
549                                 AddHorizontalScrollBar ();
550                         }
551
552                         if (add_vscroll)
553                                 AddVerticalScrollBar (node_count, vclip);
554
555                         if (add_hscroll && add_vscroll) {
556                                 Rectangle grip = new Rectangle (hbar.Right, vbar.Bottom, vbar.Width, hbar.Height);
557                                 DeviceContext.FillRectangle (new SolidBrush (BackColor), grip);
558                                 ControlPaint.DrawSizeGrip (DeviceContext, BackColor, grip);
559                         }
560                         
561                         /*
562                         ControlPaint.DrawBorder3D (DeviceContext, ClientRectangle, Border3DStyle.Sunken,
563                                 Border3DSide.Left | Border3DSide.Right | Border3DSide.Top | Border3DSide.Bottom);
564                         */
565
566                         /*
567                         int depth = 0;
568                         foreach (TreeNode node in nodes) {
569                                 DumpNode (node, ref depth);
570                                 depth = 0;
571                         }
572
573                         */
574                         Console.WriteLine ("treeview drawing time:  " + (DateTime.Now - start));
575                         Console.WriteLine ("node count:             " + node_count);
576                         Console.WriteLine ("total node count:       " + total_node_count);
577                 }
578
579                 private void DumpNode (TreeNode node, ref int depth)
580                 {
581                         for (int i = 0; i < depth; i++)
582                                 Console.Write ("****");
583                         Console.WriteLine (node.Text);
584
585                         if (node.PrevNode != null)
586                                 Console.WriteLine (" -- " + node.PrevNode.Text);
587                         depth++;
588                         foreach (TreeNode child in node.Nodes) {
589                                 DumpNode (child, ref depth);
590                         }
591                         depth--;
592                         
593                 }
594
595                 private void DrawNodePlusMinus (TreeNode node, int x, int y, int middle)
596                 {
597                         node.UpdatePlusMinusBounds (x, middle - 4, 8, 8);
598
599                         DeviceContext.DrawRectangle (SystemPens.ControlDark, node.plus_minus_bounds);
600
601                         if (node.IsExpanded) {
602                                 DeviceContext.DrawLine (SystemPens.ControlDarkDark, x + 2, middle, x + 6, middle); 
603                         } else {
604                                 DeviceContext.DrawLine (SystemPens.ControlDarkDark, x + 2, middle, x + 6, middle);
605                                 DeviceContext.DrawLine (SystemPens.ControlDarkDark, x + 4, y + 6, x + 4, y + 10);
606                         }
607                 }
608
609                 private void DrawNodeLines (TreeNode node, Pen dash, int x, int y, int middle, int item_height, int node_count)
610                 {
611                         int xadjust = 9;
612                         if (node_count > 0 && show_plus_minus)
613                                 xadjust = 13;
614                         DeviceContext.DrawLine (dash, x - indent + xadjust, middle, x, middle);
615
616                         int ly = 0;
617                         if (node.PrevNode != null) {
618                                 int prevadjust = (node.Nodes.Count > 0 && show_plus_minus ? 4 : 0);
619                                 int myadjust = (node.Nodes.Count > 0 && show_plus_minus ? 4 : 0);
620                                 ly = node.PrevNode.Bounds.Bottom - (item_height / 2) + prevadjust;
621                                 DeviceContext.DrawLine (dash, x - indent + 9, middle - myadjust, x - indent + 9, ly);
622                         } else if (node.Parent != null) {
623                                 int myadjust = (node.Nodes.Count > 0 && show_plus_minus ? 4 : 0);
624                                 ly = node.Parent.Bounds.Bottom;
625                                 DeviceContext.DrawLine (dash, x - indent + 9, middle - myadjust, x - indent + 9, ly);
626                         }
627                 }
628
629                 private void DrawNodeImage (TreeNode node, int x, int y)
630                 {
631                         if (node.ImageIndex > -1 && ImageList != null && node.ImageIndex < ImageList.Images.Count) {
632                                 ImageList.Draw (DeviceContext, x, y + 2, ImageList.ImageSize.Width, 
633                                                 ImageList.ImageSize.Height, node.ImageIndex);
634                         } else if (ImageIndex > -1 && ImageList != null && ImageIndex < ImageList.Images.Count) {
635                                 ImageList.Draw (DeviceContext, x, y + 2, ImageList.ImageSize.Width, 
636                                                 ImageList.ImageSize.Height, ImageIndex);
637                         }
638                 }
639
640                 private void UpdateNodeBounds (TreeNode node, int x, int y, int item_height)
641                 {
642                         int width = (int) (node.Text.Length * Font.Size);
643                         int xoff = indent;
644
645                         if (!show_root_lines && node.Parent == null)
646                                 xoff = 0;
647
648                         if (image_list != null)
649                                 xoff += image_list.ImageSize.Width;
650                         node.UpdateBounds (x + xoff, y, width, item_height);
651                 }
652
653                 private void DrawNode (TreeNode node, ref int depth, ref int node_count, int item_height,
654                                 Font font, ref int visible_node_count, int max_height)
655                 {
656                         node_count++;
657                         int x = (!show_root_lines && node.Parent != null ? depth  - 1 : depth) * indent;
658                         int y = (item_height + 1) * (node_count - skipped_nodes - 1);
659                         bool visible = (y >= 0 && y < max_height);
660
661                         if (visible)
662                                 visible_node_count++;
663
664                         int _n_count = node.nodes.Count;
665                         int middle = y + (item_height / 2);
666
667                         UpdateNodeBounds (node, x, y, item_height);
668
669                         if (show_root_lines || node.Parent != null) {
670                                 x += 5;
671                                 if (_n_count > 0) {
672                                         if (show_plus_minus && visible) {
673                                                 DrawNodePlusMinus (node, x, y, middle);
674                                         }
675                                 }
676                                 x += indent - 5; 
677                         }
678
679                         if (show_lines)
680                                 DrawNodeLines (node, dash, x, y, middle, item_height, _n_count);
681
682                         int ox = x;
683                         if (ImageList != null) {
684                                 if (visible)
685                                         DrawNodeImage (node, x, y);
686                                 // MS leaves the space for the image if the ImageList is
687                                 // non null regardless of whether or not an image is drawn
688                                 ox += ImageList.ImageSize.Width + 3; // leave a little space so the text isn't against the image
689                         }
690
691                         
692                         if (visible) {
693                                 DeviceContext.DrawString (node.Text, font, new SolidBrush (Color.Black), ox, y + 2);
694                                 y += item_height + 1;
695                         }
696
697                         if (node.Bounds.Right > max_node_width)
698                                 max_node_width = node.Bounds.Right;
699
700                         depth++;
701                         if (node.IsExpanded) {
702                                 for (int i = 0; i < _n_count; i++) {
703                                         int tdepth = depth;
704                                         DrawNode (node.nodes [i], ref tdepth, ref node_count, item_height,
705                                                         font, ref visible_node_count, max_height);
706                                 }
707                         }
708
709                 }
710
711                 VScrollBar vbar;
712                 bool vbar_added;
713                 int skipped_nodes;
714                 
715                 private void AddVerticalScrollBar (int total_nodes, Rectangle bounds)
716                 {
717                         vbar.Maximum = total_nodes;
718                         int height = ClientRectangle.Height;
719
720                         vbar.LargeChange = height / ItemHeight;
721
722                         if (add_hscroll)
723                                 bounds.Height -= hbar.Height;
724
725                         vbar.Bounds = bounds;
726
727                         if (!vbar_added) {
728                                 Controls.Add (vbar);
729                                 vbar.ValueChanged += new EventHandler (VScrollBarValueChanged);
730                                 vbar_added = true;
731                         }
732                 }
733
734                 HScrollBar hbar;
735                 bool hbar_added;
736                 int hbar_offset;
737
738                 private void AddHorizontalScrollBar ()
739                 {
740                         if (hbar == null) {
741                                 hbar = new HScrollBar ();
742                         }
743
744                         hbar.Bounds = new Rectangle (ClientRectangle.Left, ClientRectangle.Bottom - hbar.Height,
745                                         (add_vscroll ? Width - vbar.Width : Width), hbar.Height);
746
747                         if (!hbar_added) {
748                                 Controls.Add (hbar);
749                                 hbar_added = true;
750                         }
751                 }
752
753                 private void SizeChangedHandler (object sender, EventArgs e)
754                 {
755                         
756                         if (max_node_width > ClientRectangle.Width) {
757                                 add_hscroll = true;
758                                 AddHorizontalScrollBar ();
759                         }
760
761                         if (vbar != null) {
762                                 vbar.Left = Right - vbar.Width;
763                                 vbar.Height = Height;
764                         }
765
766                         if (hbar != null) {
767                                 hbar.Top = Bottom - hbar.Height;
768                                 hbar.Width = Width;
769                         }
770                 }
771
772                 private void VScrollBarValueChanged (object sender, EventArgs e)
773                 {
774                         skipped_nodes = vbar.Value;
775                         Refresh ();
776                 }
777
778                 private int GetVisibleNodeCount ()
779                 {
780
781                         if (Nodes.Count < 1)
782                                 return 0;
783
784                         OpenTreeNodeEnumerator e = new OpenTreeNodeEnumerator (root_node.Nodes [0]);
785
786                         int count = 0;
787                         while (e.MoveNext ()) {
788                                 count++;
789                         }
790
791                         return count;
792                 }
793
794                 // TODO: Handle all sorts o stuff here
795                 private void MouseDownHandler (object sender, MouseEventArgs e)
796                 {
797                         if (!show_plus_minus)
798                                 return;
799
800                         OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (root_node);
801
802                         // TODO: So much optimization potential here
803                         int half_height = ItemHeight / 2;
804                         while (walk.MoveNext ()) {
805                                 TreeNode node = (TreeNode) walk.Current;
806                                 if (node.PlusMinusBounds.Contains (e.X, e.Y)) {
807                                         node.Toggle ();
808                                         break;
809                                 }
810                         }
811                 }
812
813                 public event TreeViewEventHandler AfterCheck {
814                         add { on_after_check += value; }
815                         remove { on_after_check -= value; }
816                 }
817
818                 public event TreeViewEventHandler AfterCollapse {
819                         add { on_after_collapse += value; }
820                         remove { on_after_collapse -= value; }
821                 }
822
823                 public event TreeViewEventHandler AfterExpand {
824                         add { on_after_expand += value; }
825                         remove { on_after_expand -= value; }
826                 }
827
828                 public event NodeLabelEditEventHandler AfterLabelEdit {
829                         add { on_after_label_edit += value; }
830                         remove { on_after_label_edit -= value; }
831                 }
832
833                 public event TreeViewEventHandler AfterSelect {
834                         add { on_after_select += value; }
835                         remove { on_after_select -= value; }
836                 }
837
838                 public event TreeViewCancelEventHandler BeforeCheck {
839                         add { on_before_check += value; }
840                         remove { on_before_check -= value; }
841                 }
842
843                 public event TreeViewCancelEventHandler BeforeCollapse {
844                         add { on_before_collapse += value; }
845                         remove { on_before_collapse -= value; }
846                 }
847
848                 public event TreeViewCancelEventHandler BeforeExpand {
849                         add { on_before_expand += value; }
850                         remove { on_before_expand -= value; }
851                 }
852
853                 public event NodeLabelEditEventHandler BeforeLabelEdit {
854                         add { on_before_label_edit += value; }
855                         remove { on_before_label_edit -= value; }
856                 }
857
858                 public event TreeViewCancelEventHandler BeforeSelect {
859                         add { on_before_select += value; }
860                         remove { on_before_select -= value; }
861                 }
862
863                 public new event PaintEventHandler Paint {
864                         add { base.Paint += value; }
865                         remove { base.Paint -= value; }
866                 }
867
868                 public new event EventHandler TextChanged {
869                         add { base.TextChanged += value; }
870                         remove { base.TextChanged -= value; }
871                 }
872         }
873 }
874