* UpDownBase.cs:
[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-2005 Novell, Inc.
21 //
22 // Authors:
23 //      Jackson Harper (jackson@ximian.com)
24 //      Kazuki Oikawa (kazuki@panicode.com)
25
26 using System;
27 using System.Collections;
28 using System.ComponentModel;
29 using System.ComponentModel.Design;
30 using System.Drawing;
31 using System.Drawing.Drawing2D;
32 using System.Runtime.InteropServices;
33
34 namespace System.Windows.Forms {
35         [DefaultProperty("Nodes")]
36         [DefaultEvent("AfterSelect")]
37         [Designer("System.Windows.Forms.Design.TreeViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
38         public class TreeView : Control {
39                 #region Fields
40                 private string path_separator = "\\";
41                 private int item_height = -1;
42                 private bool sorted;
43                 internal TreeNode root_node;
44                 internal bool nodes_added;
45                 private TreeNodeCollection nodes;
46
47                 private TreeViewAction selection_action;
48                 private TreeNode selected_node;
49                 private TreeNode pre_selected_node;
50                 private TreeNode focused_node;
51                 private TreeNode highlighted_node;
52                 private Rectangle mouse_rect;
53                 private bool select_mmove;
54
55                 private ImageList image_list;
56                 private int image_index = -1;
57                 private int selected_image_index = -1;
58
59 #if NET_2_0
60                 private string image_key;
61                 private string selected_image_key;
62 #endif
63                 private bool full_row_select;
64                 private bool hot_tracking;
65                 private int indent = 19;
66
67                 private NodeLabelEditEventArgs edit_args;
68                 private LabelEditTextBox edit_text_box;
69                 internal TreeNode edit_node;
70                 
71                 private bool checkboxes;
72                 private bool label_edit;
73                 private bool scrollable = true;
74                 private bool show_lines = true;
75                 private bool show_root_lines = true;
76                 private bool show_plus_minus = true;
77                 private bool hide_selection = true;
78
79                 private int max_visible_order = -1;
80                 private VScrollBar vbar;
81                 private HScrollBar hbar;
82                 private bool vbar_bounds_set;
83                 private bool hbar_bounds_set;
84                 internal int skipped_nodes;
85                 internal int hbar_offset;
86                 
87                 private int update_stack;
88                 private bool update_needed;
89                 
90                 private Pen dash;
91                 private Color line_color;
92                 private StringFormat string_format;
93
94                 private int drag_begin_x = 0;
95                 private int drag_begin_y = 0;
96                 private long handle_count = 1;
97
98                 private TreeViewDrawMode draw_mode;
99
100 #if NET_2_0
101                 IComparer tree_view_node_sorter;
102 #endif
103                 #endregion      // Fields
104
105                 #region Public Constructors     
106                 public TreeView ()
107                 {
108                         InternalBorderStyle = BorderStyle.Fixed3D;
109                         base.background_color = ThemeEngine.Current.ColorWindow;
110                         base.foreground_color = ThemeEngine.Current.ColorWindowText;
111
112                         root_node = new TreeNode (this);
113                         root_node.Text = "ROOT NODE";
114                         nodes = new TreeNodeCollection (root_node);
115                         root_node.SetNodes (nodes);
116
117                         MouseDown += new MouseEventHandler (MouseDownHandler);
118                         MouseUp += new MouseEventHandler(MouseUpHandler);
119                         MouseMove += new MouseEventHandler(MouseMoveHandler);
120                         SizeChanged += new EventHandler (SizeChangedHandler);
121                         FontChanged += new EventHandler (FontChangedHandler);
122                         LostFocus += new EventHandler (LostFocusHandler);
123                         GotFocus += new EventHandler (GotFocusHandler);
124                         MouseWheel += new MouseEventHandler(MouseWheelHandler);
125                         VisibleChanged += new EventHandler (VisibleChangedHandler);
126
127                         SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick
128 #if NET_2_0
129                                 | ControlStyles.UseTextForAccessibility
130 #endif
131                                 , false);
132
133                         string_format = new StringFormat ();
134                         string_format.LineAlignment = StringAlignment.Center;
135                         string_format.Alignment = StringAlignment.Center;
136
137                         vbar = new ImplicitVScrollBar ();
138                         hbar = new ImplicitHScrollBar ();
139
140                         vbar.Visible = false;
141                         hbar.Visible = false;
142                         vbar.ValueChanged += new EventHandler (VScrollBarValueChanged);
143                         hbar.ValueChanged += new EventHandler (HScrollBarValueChanged);
144
145                         SuspendLayout ();
146                         Controls.AddImplicit (vbar);
147                         Controls.AddImplicit (hbar);
148                         ResumeLayout ();
149                 }
150
151                 #endregion      // Public Constructors
152
153                 #region Public Instance Properties
154                 public override Color BackColor {
155                         get { return base.BackColor;}
156                         set {
157                                 base.BackColor = value;
158
159                                 CreateDashPen ();
160                                 Invalidate ();
161                         }
162                 }
163
164
165                 [Browsable(false)]
166                 [EditorBrowsable(EditorBrowsableState.Never)]
167                 public override Image BackgroundImage {
168                         get { return base.BackgroundImage; }
169                         set { base.BackgroundImage = value; }
170                 }
171
172                 [DefaultValue(BorderStyle.Fixed3D)]
173                 [DispId(-504)]
174                 public BorderStyle BorderStyle {
175                         get { return InternalBorderStyle; }
176                         set { InternalBorderStyle  = value; }
177                 }
178
179                 [DefaultValue(false)]
180                 public bool CheckBoxes {
181                         get { return checkboxes; }
182                         set {
183                                 if (value == checkboxes)
184                                         return;
185                                 checkboxes = value;
186
187                                 // Match a "bug" in the MS implementation where disabling checkboxes
188                                 // collapses the entire tree, but enabling them does not affect the
189                                 // state of the tree.
190                                 if (!checkboxes)
191                                         root_node.CollapseAllUncheck ();
192
193                                 Invalidate ();
194                         }
195                 }
196
197                 public override Color ForeColor {
198                         get { return base.ForeColor; }
199                         set { base.ForeColor = value; }
200                 }
201                 [DefaultValue(false)]
202                 public bool FullRowSelect {
203                         get { return full_row_select; }
204                         set {
205                                 if (value == full_row_select)
206                                         return;
207                                 full_row_select = value;
208                                 Invalidate ();
209                         }
210                 }
211                 [DefaultValue(true)]
212                 public bool HideSelection {
213                         get { return hide_selection; }
214                         set {
215                                 if (hide_selection == value)
216                                         return;
217                                 hide_selection = value;
218                                 Invalidate ();
219                         }
220                 }
221
222                 [DefaultValue(false)]
223                 public bool HotTracking {
224                         get { return hot_tracking; }
225                         set { hot_tracking = value; }
226                 }
227
228                 [DefaultValue(0)]
229                 [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
230                 [Localizable(true)]
231                 [TypeConverter(typeof(TreeViewImageIndexConverter))]
232                 public int ImageIndex {
233                         get { return image_index; }
234                         set {
235                                 if (value < -1) {
236                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
237                                                 "'value' must be greater than or equal to 0.");
238                                 }
239                                 if (image_index == value)
240                                         return;
241                                 image_index = value;
242                                 Invalidate ();
243                         }
244                 }
245
246                 [DefaultValue(null)]
247                 public ImageList ImageList {
248                         get { return image_list; }
249                         set {
250                                 image_list = value;
251                                 Invalidate ();
252                         }
253                 }
254
255                 [Localizable(true)]
256                 public int Indent {
257                         get { return indent; }
258                         set {
259                                 if (indent == value)
260                                         return;
261                                 if (value > 32000) {
262                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'Indent'. " +
263                                                 "'Indent' must be less than or equal to 32000");
264                                 }       
265                                 if (value < 0) {
266                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'Indent'. " +
267                                                 "'Indent' must be greater than or equal to 0.");
268                                 }
269                                 indent = value;
270                                 Invalidate ();
271                         }
272                 }
273
274                 [Localizable(true)]
275                 public int ItemHeight {
276                         get {
277                                 if (item_height == -1)
278                                         return FontHeight + 3;
279                                 return item_height;
280                         }
281                         set {
282                                 if (value == item_height)
283                                         return;
284                                 item_height = value;
285                                 Invalidate ();
286                         }
287                 }
288
289                 internal int ActualItemHeight {
290                         get {
291                                 int res = ItemHeight;
292                                 if (ImageList != null && ImageList.ImageSize.Height > res)
293                                         res = ImageList.ImageSize.Height;
294                                 return res;
295                         }
296                 }
297
298                 [DefaultValue(false)]
299                 public bool LabelEdit {
300                         get { return label_edit; }
301                         set { label_edit = value; }
302                 }
303
304                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
305                 [MergableProperty(false)]
306                 [Localizable(true)]
307                 public TreeNodeCollection Nodes {
308                         get { return nodes; }
309                 }
310
311                 [DefaultValue("\\")]
312                 public string PathSeparator {
313                         get { return path_separator; }
314                         set { path_separator = value; }
315                 }
316
317                 [DefaultValue(true)]
318                 public bool Scrollable {
319                         get { return scrollable; }
320                         set {
321                                 if (scrollable == value)
322                                         return;
323                                 scrollable = value;
324                                 UpdateScrollBars ();
325                         }
326                 }
327
328                 [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
329                 [TypeConverter(typeof(TreeViewImageIndexConverter))]
330                 [Localizable(true)]
331                 [DefaultValue(0)]
332                 public int SelectedImageIndex {
333                         get { return selected_image_index; }
334                         set {
335                                 if (value < -1) {
336                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
337                                                 "'value' must be greater than or equal to 0.");
338                                 }
339                                 UpdateNode (SelectedNode);
340                         }
341                 }
342
343                 [Browsable(false)]
344                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
345                 public TreeNode SelectedNode {
346                         get {
347                                 if (!IsHandleCreated)
348                                         return pre_selected_node;
349                                 return selected_node;
350                         }
351                         set {
352                                 if (!IsHandleCreated) {
353                                         pre_selected_node = value;
354                                         return;
355                                 }
356
357                                 if (selected_node == value) {
358                                         selection_action = TreeViewAction.Unknown;
359                                         return;
360                                 }
361
362                                 TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (value, false, selection_action);
363                                 OnBeforeSelect (e);
364
365                                 if (e.Cancel)
366                                         return;
367
368                                 Rectangle invalid = Rectangle.Empty;
369
370                                 if (selected_node != null) {
371                                         invalid = Bloat (selected_node.Bounds);
372                                 }
373                                 if (focused_node != null) {
374                                         invalid = Rectangle.Union (invalid,
375                                                         Bloat (focused_node.Bounds));
376                                 }
377
378                                 if (value != null)
379                                         invalid = Rectangle.Union (invalid, Bloat (value.Bounds));
380
381                                 highlighted_node = value;
382                                 selected_node = value;
383                                 focused_node = value;
384
385                                 if (full_row_select || draw_mode != TreeViewDrawMode.Normal) {
386                                         invalid.X = 0;
387                                         invalid.Width = ViewportRectangle.Width;
388                                 }
389
390                                 if (invalid != Rectangle.Empty)
391                                         Invalidate (invalid);
392
393                                 // We ensure its visible after we update because
394                                 // scrolling is used for insure visible
395                                 if (selected_node != null)
396                                         selected_node.EnsureVisible ();
397
398                                 OnAfterSelect (new TreeViewEventArgs (value, TreeViewAction.Unknown));
399                                 selection_action = TreeViewAction.Unknown;
400                         }
401                 }
402
403                 private Rectangle Bloat (Rectangle rect)
404                 {
405                         rect.Y--;
406                         rect.X--;
407                         rect.Height += 2;
408                         rect.Width += 2;
409                         return rect;
410                 }
411
412                 [DefaultValue(true)]
413                 public bool ShowLines {
414                         get { return show_lines; }
415                         set {
416                                 if (show_lines == value)
417                                         return;
418                                 show_lines = value;
419                                 Invalidate ();
420                         }
421                 }
422
423                 [DefaultValue(true)]
424                 public bool ShowPlusMinus {
425                         get { return show_plus_minus; }
426                         set {
427                                 if (show_plus_minus == value)
428                                         return;
429                                 show_plus_minus = value;
430                                 Invalidate ();
431                         }
432                 }
433
434                 [DefaultValue(true)]
435                 public bool ShowRootLines {
436                         get { return show_root_lines; }
437                         set {
438                                 if (show_root_lines == value)
439                                         return;
440                                 show_root_lines = value;
441                                 Invalidate ();
442                         }
443                 }
444
445                 [DefaultValue(false)]
446                 public bool Sorted {
447                         get { return sorted; }
448                         set {
449 #if NET_2_0
450                                 if (sorted == value)
451                                         return;
452                                 sorted = value;
453                                 //LAMESPEC: The documentation says that setting this to true should sort alphabetically if TreeViewNodeSorter is set.
454                                 // There seems to be a bug in the Microsoft implementation.
455                                 if (sorted && tree_view_node_sorter == null) {
456                                         Sort (null);
457                                 }
458 #else
459                                 if (sorted != value)
460                                         sorted = value;
461                                 if (sorted) {
462                                         Sort (null);
463                                 }
464 #endif
465                         }
466                 }
467
468                 [Browsable(false)]
469                 [EditorBrowsable(EditorBrowsableState.Never)]
470                 [Bindable(false)]
471                 public override string Text {
472                         get { return base.Text; }
473                         set { base.Text = value; }
474                 }
475
476                 [Browsable(false)]
477                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
478                 public TreeNode TopNode {
479                         get {
480                                 if (root_node.FirstNode == null)
481                                         return null;
482                                 OpenTreeNodeEnumerator one = new OpenTreeNodeEnumerator (root_node.FirstNode);
483                                 one.MoveNext ();
484                                 for (int i = 0; i < skipped_nodes; i++)
485                                         one.MoveNext ();
486                                 return one.CurrentNode;
487                         }
488 #if NET_2_0
489                         set {
490                                 SetTop (value);
491                         }
492 #endif
493                 }
494
495 #if NET_2_0
496                 public IComparer TreeViewNodeSorter {
497                         get {
498                                 return tree_view_node_sorter;
499                         }
500                         set {
501                                 tree_view_node_sorter = value;
502                                 if (tree_view_node_sorter != null) {
503                                         Sort();
504                                         //LAMESPEC: The documentation says that setting this should set Sorted to false.
505                                         // There seems to be a bug in the Microsoft implementation.
506                                         sorted = true;
507                                 }
508                         }
509                 }
510 #endif
511
512                 [Browsable(false)]
513                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
514                 public int VisibleCount {
515                         get {
516                                 return ViewportRectangle.Height / ActualItemHeight;
517                         }
518                 }
519
520 #if NET_2_0
521                 /// According to MSDN this property has no effect on the treeview
522                 protected override bool DoubleBuffered {
523                         get { return true; }
524                         set { /* whatever */ }
525                 }
526 #endif
527
528 #if NET_2_0
529                 public
530 #else
531                 private
532 #endif
533                 Color LineColor {
534                         get {
535                                 if (line_color == Color.Empty) {
536                                         Color res = ControlPaint.Dark (BackColor);
537                                         if (res == BackColor)
538                                                 res = ControlPaint.Light (BackColor);
539                                         return res;
540                                 }
541                                 return line_color;
542                         }
543                         set {
544                                 line_color = value;
545                                 if (show_lines) {
546                                         CreateDashPen ();
547                                         Invalidate ();
548                                 }
549                         }
550                 }
551 #if NET_2_0
552                 [Localizable (true)]
553                 public string ImageKey {
554                         get { return image_key; }
555                         set {
556                                 if (image_key == value)
557                                         return;
558                                 image_index = -1;
559                                 image_key = value;
560                                 Invalidate ();
561                         }
562                 }
563
564                 public string SelectedImageKey {
565                         get { return selected_image_key; }
566                         set {
567                                 if (selected_image_key == value)
568                                         return;
569                                 selected_image_index = -1;
570                                 selected_image_key = value;
571                                 UpdateNode (SelectedNode);
572                         }
573                 }
574 #endif
575
576 #if NET_2_0
577                 public override ImageLayout BackgroundImageLayout {
578                         get { return base.BackgroundImageLayout; }
579                         set { base.BackgroundImageLayout = value; }
580                 }
581 #endif
582
583 #if NET_2_0
584                 public TreeViewDrawMode DrawMode {
585                         get { return draw_mode; }
586                         set { draw_mode = value; }
587                 }
588 #endif
589                 #endregion      // Public Instance Properties
590
591                 #region Protected Instance Properties
592                 protected override CreateParams CreateParams {
593                         get {
594                                 CreateParams cp = base.CreateParams;
595                                 return cp;
596                         }
597                 }
598
599                 protected override Size DefaultSize {
600                         get { return new Size (121, 97); }
601                 }
602
603                 #endregion      // Protected Instance Properties
604
605                 #region Public Instance Methods
606                 public void BeginUpdate ()
607                 {
608                         update_stack++;
609                 }
610
611                 public void EndUpdate ()
612                 {
613                         if (update_stack > 1) {
614                                 update_stack--;
615                         } else {
616                                 update_stack = 0;
617                                 if (update_needed) {
618                                         RecalculateVisibleOrder (root_node);
619                                         UpdateScrollBars ();
620                                         //      if (SelectedNode != null)
621                                         //              SelectedNode.EnsureVisible ();
622                                         Invalidate (ViewportRectangle);
623                                         update_needed = false;
624                                 }
625                         }
626                 }
627
628 #if NET_2_0
629                 public
630 #else
631                 private
632 #endif
633                 void Sort ()
634                 {
635 #if NET_2_0
636                         Sort (Nodes.Count >= 2 ? tree_view_node_sorter : null);
637 #else
638                         Sort (null);
639 #endif
640                 }
641
642                 void Sort (IComparer sorter) 
643                 {
644                         Nodes.Sort (sorter);
645                         RecalculateVisibleOrder (root_node);
646                         UpdateScrollBars ();
647                         Invalidate ();
648                 }
649
650                 public void ExpandAll ()
651                 {
652                         BeginUpdate ();
653                         root_node.ExpandAll ();
654
655                         EndUpdate ();
656
657                         ///
658                         /// Everything below this is basically an emulation of a strange bug on MS
659                         /// where they don't always scroll to the last node on ExpandAll
660                         ///
661 #if NET_2_0
662                         if (!IsHandleCreated)
663                                 return;
664 #endif
665                         
666                         bool found = false;
667                         foreach (TreeNode child in Nodes) {
668                                 if (child.Nodes.Count > 0)
669                                         found = true;
670                         }
671                         
672                         if (!found)
673                                 return;
674
675                         vbar.Value = vbar.Maximum - VisibleCount + 1;
676                 }
677
678                 
679                 public void CollapseAll ()
680                 {
681                         TreeNode walk = TopNode;
682                         
683                         while (walk.parent != root_node)
684                                 walk = walk.parent;
685
686                         BeginUpdate ();
687                         root_node.CollapseAll ();
688                         EndUpdate ();
689
690                         SetTop (walk);
691                 }
692
693                 public TreeNode GetNodeAt (Point pt) {
694                         return GetNodeAt (pt.Y);
695                 }
696
697                 public TreeNode GetNodeAt (int x, int y)
698                 {
699                         return GetNodeAt (y);
700                 }
701
702                 private TreeNode GetNodeAtUseX (int x, int y) {
703                         TreeNode node = GetNodeAt (y);
704                         if (node == null || !(IsTextArea (node, x) || full_row_select))
705                                 return null;
706                         return node;
707                                         
708                 }
709
710                 public int GetNodeCount (bool include_subtrees) {
711                         return root_node.GetNodeCount (include_subtrees);
712                 }
713
714                 public override string ToString () {
715                         int count = Nodes.Count;
716                         if (count <= 0)
717                                 return String.Concat (base.ToString (), "Node Count: 0");
718                         return String.Concat (base.ToString (), "Node Count: ", count, " Nodes[0]: ", Nodes [0]);
719                                                 
720                 }
721
722                 #endregion      // Public Instance Methods
723
724                 #region Protected Instance Methods
725                 protected override void CreateHandle () {
726                         base.CreateHandle ();
727                         RecalculateVisibleOrder (root_node);
728                         UpdateScrollBars ();
729
730                         if (pre_selected_node != null)
731                                 SelectedNode = pre_selected_node;
732                 }
733
734                 protected override void Dispose (bool disposing) {
735                         if (disposing)
736                                 image_list = null;
737
738                         base.Dispose (disposing);
739                 }
740
741                 protected OwnerDrawPropertyBag GetItemRenderStyles (TreeNode node, int state) {
742                         return node.prop_bag;
743                 }
744
745                 protected override bool IsInputKey (Keys key_data)
746                 {
747                         if ((key_data & Keys.Alt) == 0) {
748                                 switch (key_data & Keys.KeyCode) {
749                                 case Keys.Enter:
750                                 case Keys.Escape:
751                                 case Keys.Prior:
752                                 case Keys.Next:
753                                 case Keys.End:
754                                 case Keys.Home:
755                                 case Keys.Left:
756                                 case Keys.Up:
757                                 case Keys.Right:
758                                 case Keys.Down:
759                                         return true;
760                                 }
761                         }
762                         return base.IsInputKey (key_data);
763                 }
764
765                 protected override void OnKeyDown (KeyEventArgs e)
766                 {
767                         OpenTreeNodeEnumerator ne;
768
769                         switch (e.KeyData & Keys.KeyCode) {
770                         case Keys.Add:
771                                 if (selected_node != null && selected_node.IsExpanded)
772                                         selected_node.Expand ();
773                                 break;
774                         case Keys.Subtract:
775                                 if (selected_node != null && selected_node.IsExpanded)
776                                         selected_node.Collapse ();
777                                 break;
778                         case Keys.Left:
779                                 if (selected_node != null) {
780                                         if (selected_node.IsExpanded)
781                                                 selected_node.Collapse ();
782                                         else {
783                                                 TreeNode parent = selected_node.Parent;
784                                                 if (parent != null) {
785                                                         selection_action = TreeViewAction.ByKeyboard;
786                                                         SelectedNode = parent;
787                                                 }
788                                         }
789                                 }
790                                 break;
791                         case Keys.Right:
792                                 if (selected_node != null) {
793                                         if (!selected_node.IsExpanded)
794                                                 selected_node.Expand ();
795                                         else {
796                                                 TreeNode child = selected_node.FirstNode;
797                                                 if (child != null)
798                                                         SelectedNode = child;
799                                         }
800                                 }
801                                 break;
802                         case Keys.Up:
803                                 if (selected_node != null) {
804                                         ne = new OpenTreeNodeEnumerator (selected_node);
805                                         if (ne.MovePrevious () && ne.MovePrevious ()) {
806                                                 selection_action = TreeViewAction.ByKeyboard;
807                                                 SelectedNode = ne.CurrentNode;
808                                         }
809                                 }
810                                 break;
811                         case Keys.Down:
812                                 if (selected_node != null) {
813                                         ne = new OpenTreeNodeEnumerator (selected_node);
814                                         if (ne.MoveNext () && ne.MoveNext ()) {
815                                                 selection_action = TreeViewAction.ByKeyboard;
816                                                 SelectedNode = ne.CurrentNode;
817                                         }
818                                 }
819                                 break;
820                         case Keys.Home:
821                                 if (root_node.Nodes.Count > 0) {
822                                         ne = new OpenTreeNodeEnumerator (root_node.Nodes [0]);
823                                         if (ne.MoveNext ()) {
824                                                 selection_action = TreeViewAction.ByKeyboard;
825                                                 SelectedNode = ne.CurrentNode;
826                                         }
827                                 }
828                                 break;
829                         case Keys.End:
830                                 if (root_node.Nodes.Count > 0) {
831                                         ne = new OpenTreeNodeEnumerator (root_node.Nodes [0]);
832                                         while (ne.MoveNext ())
833                                         { }
834                                         selection_action = TreeViewAction.ByKeyboard;
835                                         SelectedNode = ne.CurrentNode;
836                                 }
837                                 break;
838                         case Keys.PageDown:
839                                 if (selected_node != null) {
840                                         ne = new OpenTreeNodeEnumerator (selected_node);
841                                         int move = VisibleCount;
842                                         for (int i = 0; i < move && ne.MoveNext (); i++) {
843                                                 
844                                         }
845                                         selection_action = TreeViewAction.ByKeyboard;
846                                         SelectedNode = ne.CurrentNode;
847                                 }
848                                 break;
849                         case Keys.PageUp:
850                                 if (selected_node != null) {
851                                         ne = new OpenTreeNodeEnumerator (selected_node);
852                                         int move = VisibleCount;
853                                         for (int i = 0; i < move && ne.MovePrevious (); i++)
854                                         { }
855                                         selection_action = TreeViewAction.ByKeyboard;
856                                         SelectedNode = ne.CurrentNode;
857                                 }
858                                 break;
859                         case Keys.Multiply:
860                                 if (selected_node != null)
861                                         selected_node.ExpandAll ();
862                                 break;
863                         }
864                         base.OnKeyDown (e);
865
866                         if (!e.Handled && checkboxes &&
867                              selected_node != null &&
868                             (e.KeyData & Keys.KeyCode) == Keys.Space) {
869                                 selected_node.check_reason = TreeViewAction.ByKeyboard;
870                                 selected_node.Checked = !selected_node.Checked;         
871                                 e.Handled = true;
872                         }
873                 }
874
875                 protected override void OnKeyPress (KeyPressEventArgs e)
876                 {
877                         base.OnKeyPress (e);
878                         if (e.KeyChar == ' ')
879                                 e.Handled = true;
880                 }
881
882                 protected override void OnKeyUp (KeyEventArgs e)
883                 {
884                         base.OnKeyUp (e);
885                         if ((e.KeyData & Keys.KeyCode) == Keys.Space)
886                                 e.Handled = true;
887                 }
888
889                 protected virtual void OnItemDrag (ItemDragEventArgs e)
890                 {
891                         ItemDragEventHandler eh = (ItemDragEventHandler)(Events [ItemDragEvent]);
892                         if (eh != null)
893                                 eh (this, e);
894                 }
895
896 #if NET_2_0
897                 protected virtual void OnDrawNode(DrawTreeNodeEventArgs e) {
898                         DrawTreeNodeEventHandler eh = (DrawTreeNodeEventHandler)(Events[DrawNodeEvent]);
899                         if (eh != null)
900                                 eh(this, e);
901                 }
902 #endif
903
904                 protected internal virtual void OnAfterCheck (TreeViewEventArgs e) {
905                         TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterCheckEvent]);
906                         if (eh != null)
907                                 eh (this, e);
908                 }
909
910                 protected internal virtual void OnAfterCollapse (TreeViewEventArgs e) {
911                         TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterCollapseEvent]);
912                         if (eh != null)
913                                 eh (this, e);
914                 }
915
916                 protected internal virtual void OnAfterExpand (TreeViewEventArgs e) {
917                         TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterExpandEvent]);
918                         if (eh != null)
919                                 eh (this, e);
920                 }
921
922                 protected virtual void OnAfterLabelEdit (NodeLabelEditEventArgs e) {
923                         NodeLabelEditEventHandler eh = (NodeLabelEditEventHandler)(Events [AfterLabelEditEvent]);
924                         if (eh != null)
925                                 eh (this, e);
926                 }
927
928                 protected virtual void OnAfterSelect (TreeViewEventArgs e) {
929                         TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterSelectEvent]);
930                         if (eh != null)
931                                 eh (this, e);
932                 }
933
934                 protected internal virtual void OnBeforeCheck (TreeViewCancelEventArgs e) {
935                         TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeCheckEvent]);
936                         if (eh != null)
937                                 eh (this, e);
938                 }
939
940                 protected internal virtual void OnBeforeCollapse (TreeViewCancelEventArgs e) {
941                         TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeCollapseEvent]);
942                         if (eh != null)
943                                 eh (this, e);
944                 }
945
946                 protected internal virtual void OnBeforeExpand (TreeViewCancelEventArgs e) {
947                         TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeExpandEvent]);
948                         if (eh != null)
949                                 eh (this, e);
950                 }
951
952                 protected virtual void OnBeforeLabelEdit (NodeLabelEditEventArgs e) {
953                         NodeLabelEditEventHandler eh = (NodeLabelEditEventHandler)(Events [BeforeLabelEditEvent]);
954                         if (eh != null)
955                                 eh (this, e);
956                 }
957
958                 protected virtual void OnBeforeSelect (TreeViewCancelEventArgs e) {
959                         TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeSelectEvent]);
960                         if (eh != null)
961                                 eh (this, e);
962                 }
963
964                 protected override void OnHandleCreated (EventArgs e) {
965                         base.OnHandleCreated (e);
966                 }
967
968                 protected override void OnHandleDestroyed (EventArgs e) {
969                         base.OnHandleDestroyed (e);
970                 }
971
972                 protected override void WndProc(ref Message m) {
973                         switch ((Msg) m.Msg) {
974
975                         case Msg.WM_LBUTTONDBLCLK:
976                                 int val = m.LParam.ToInt32();
977                                 DoubleClickHandler (null, new
978                                                 MouseEventArgs (MouseButtons.Left,
979                                                                 2, val & 0xffff,
980                                                                 (val>>16) & 0xffff, 0));
981                                         break;
982                         }
983                         base.WndProc (ref m);
984                 }
985
986                 #endregion      // Protected Instance Methods
987
988                 #region Internal & Private Methods and Properties
989                 internal IntPtr CreateNodeHandle ()
990                 {
991                         return (IntPtr) handle_count++;
992                 }
993
994                 internal TreeNode NodeFromHandle (IntPtr handle)
995                 {
996                         // This method is called rarely, so instead of maintaining a table
997                         // we just walk the tree nodes to find the matching handle
998                         return NodeFromHandleRecursive (root_node,  handle);
999                 }
1000
1001                 private TreeNode NodeFromHandleRecursive (TreeNode node, IntPtr handle)
1002                 {
1003                         if (node.handle == handle)
1004                                 return node;
1005                         foreach (TreeNode child in node.Nodes) {
1006                                 TreeNode match = NodeFromHandleRecursive (child, handle);
1007                                 if (match != null)
1008                                         return match;
1009                         }
1010                         return null;
1011                 }
1012
1013                 internal Rectangle ViewportRectangle {
1014                         get {
1015                                 Rectangle res = ClientRectangle;
1016
1017                                 if (vbar != null && vbar.Visible)
1018                                         res.Width -= vbar.Width;
1019                                 if (hbar != null && hbar.Visible)
1020                                         res.Height -= hbar.Height;
1021                                 return res;
1022                         }
1023                 }
1024
1025                 private TreeNode GetNodeAt (int y)
1026                 {
1027                         if (nodes.Count <= 0)
1028                                 return null;
1029
1030                         OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (TopNode);
1031                         int move = y / ActualItemHeight;
1032                         for (int i = -1; i < move; i++) {
1033                                 if (!o.MoveNext ())
1034                                         return null;
1035                         }
1036
1037                         return o.CurrentNode;
1038                 }
1039
1040                 private bool IsTextArea (TreeNode node, int x)
1041                 {
1042                         return node != null && node.Bounds.Left <= x && node.Bounds.Right >= x;
1043                 }
1044
1045                 private bool IsSelectableArea (TreeNode node, int x)
1046                 {
1047                         if (node == null)
1048                                 return false;
1049                         int l = node.Bounds.Left;
1050                         if (ImageList != null)
1051                                 l -= ImageList.ImageSize.Width;
1052                         return l <= x && node.Bounds.Right >= x;
1053                                 
1054                 }
1055
1056                 private bool IsPlusMinusArea (TreeNode node, int x)
1057                 {
1058                         if (node.Nodes.Count == 0 || (node.parent == root_node && !show_root_lines))
1059                                 return false;
1060
1061                         int l = node.Bounds.Left + 5;
1062
1063                         if (show_root_lines || node.Parent != null)
1064                                 l -= indent;
1065                         if (ImageList != null)
1066                                 l -= ImageList.ImageSize.Width + 3;
1067                         if (checkboxes)
1068                                 l -= 19;
1069                         return (x > l && x < l + 8);
1070                 }
1071
1072                 private bool IsCheckboxArea (TreeNode node, int x)
1073                 {
1074                         int l = CheckBoxLeft (node);
1075                         return (x > l && x < l + 10);
1076                 }
1077
1078                 private int CheckBoxLeft (TreeNode node)
1079                 {
1080                         int l = node.Bounds.Left + 5;
1081
1082                         if (show_root_lines || node.Parent != null)
1083                                 l -= indent;
1084                         if (ImageList != null)
1085                                 l -= ImageList.ImageSize.Width + 3;
1086
1087                         return l;
1088                 }
1089
1090                 internal void RecalculateVisibleOrder (TreeNode start)
1091                 {
1092                         if (update_stack > 0)
1093                                 return;
1094
1095                         int order;
1096                         if (start == null) {
1097                                 start = root_node;
1098                                 order = 0;
1099                         } else
1100                                 order = start.visible_order;
1101
1102                         
1103                         
1104                         OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (start);
1105                         while (walk.MoveNext ()) {
1106                                 walk.CurrentNode.visible_order = order;
1107                                 order++;
1108                         }
1109
1110                         max_visible_order = order;
1111                 }
1112
1113                 internal void SetTop (TreeNode node)
1114                 {
1115                         if (!vbar.is_visible) {
1116                                 skipped_nodes = node.visible_order;
1117                                 return;
1118                         }
1119
1120                         vbar.Value = Math.Min (node.visible_order, vbar.Maximum - VisibleCount + 1);
1121                 }
1122
1123                 internal void SetBottom (TreeNode node)
1124                 {
1125                         if (!vbar.is_visible)
1126                                 return;
1127
1128                         OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (node);
1129
1130                         int bottom = ViewportRectangle.Bottom;
1131                         int offset = 0;
1132                         while (walk.MovePrevious ()) {
1133                                 if (walk.CurrentNode.Bounds.Bottom <= bottom)
1134                                         break;
1135                                 offset++;
1136                         }
1137
1138                         int nv = vbar.Value + offset;
1139                         if (vbar.Value + offset < vbar.Maximum) {
1140                                 vbar.Value = nv;
1141                         } else {
1142 #if DEBUG
1143                                 Console.Error.WriteLine ("setting bottom to value greater then maximum ({0}, {1})",
1144                                                 nv, vbar.Maximum);
1145 #endif
1146                         }
1147                                 
1148                 }
1149
1150                 internal void UpdateBelow (TreeNode node)
1151                 {
1152                         if (update_stack > 0) {
1153                                 update_needed = true;
1154                                 return;
1155                         }
1156
1157                         if (node == root_node) {
1158                                 Invalidate (ViewportRectangle);
1159                                 return;
1160                         }
1161                                 
1162                         // We need to update the current node so the plus/minus block gets update too
1163                         int top = Math.Max (node.Bounds.Top - 1, 0);
1164                         Rectangle invalid = new Rectangle (0, top,
1165                                         Width, Height - top);
1166                         Invalidate (invalid);
1167                 }
1168
1169                 internal void UpdateNode (TreeNode node)
1170                 {
1171                         if (node == null)
1172                                 return;
1173
1174                         if (update_stack > 0) {
1175                                 update_needed = true;
1176                                 return;
1177                         }
1178
1179                         if (node == root_node) {
1180                                 Invalidate ();
1181                                 return;
1182                         }
1183
1184                         Rectangle invalid = new Rectangle (0, node.Bounds.Top - 1, Width,
1185                                         node.Bounds.Height + 1);
1186                         Invalidate (invalid);
1187                 }
1188
1189                 internal void UpdateNodePlusMinus (TreeNode node)
1190                 {
1191                         if (update_stack > 0) {
1192                                 update_needed = true;
1193                                 return;
1194                         }
1195
1196                         int l = node.Bounds.Left + 5;
1197
1198                         if (show_root_lines || node.Parent != null)
1199                                 l -= indent;
1200                         if (ImageList != null)
1201                                 l -= ImageList.ImageSize.Width + 3;
1202                         if (checkboxes)
1203                                 l -= 19;
1204
1205                         Invalidate (new Rectangle (l, node.Bounds.Top, 8, node.Bounds.Height));
1206                 }
1207
1208                 internal override void OnPaintInternal (PaintEventArgs pe)
1209                 {
1210                         Draw (pe.ClipRectangle, pe.Graphics);
1211                 }
1212
1213                 internal void CreateDashPen ()
1214                 {
1215                         dash = new Pen (LineColor, 1);
1216                         dash.DashStyle = DashStyle.Dot;
1217                 }
1218
1219                 private void Draw (Rectangle clip, Graphics dc)
1220                 {
1221                         dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), clip);
1222
1223                         if (dash == null)
1224                                 CreateDashPen ();
1225
1226                         Rectangle viewport = ViewportRectangle;
1227                         Rectangle original_clip = clip;
1228                         if (clip.Bottom > viewport.Bottom)
1229                                 clip.Height = viewport.Bottom - clip.Top;
1230
1231                         OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (TopNode);
1232                         while (walk.MoveNext ()) {
1233                                 TreeNode current = walk.CurrentNode;
1234
1235                                 // Haven't gotten to visible nodes yet
1236                                 if (current.GetY () + ActualItemHeight < clip.Top)
1237                                         continue;
1238
1239                                 // Past the visible nodes
1240                                 if (current.GetY () > clip.Bottom)
1241                                         break;
1242
1243                                 DrawTreeNode (current, dc, clip);
1244                         }
1245
1246                         if (hbar.Visible && vbar.Visible) {
1247                                 Rectangle corner = new Rectangle (hbar.Right, vbar.Bottom, vbar.Width, hbar.Height);
1248                                 if (original_clip.IntersectsWith (corner))
1249                                         dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorControl),
1250                                                         corner);
1251                         }
1252                 }
1253
1254                 private void DrawNodePlusMinus (TreeNode node, Graphics dc, int x, int middle)
1255                 {
1256                         dc.DrawRectangle (SystemPens.ControlDarkDark, x, middle - 4, 8, 8);
1257
1258                         if (node.IsExpanded) {
1259                                 dc.DrawLine (SystemPens.ControlDarkDark, x + 2, middle, x + 6, middle); 
1260                         } else {
1261                                 dc.DrawLine (SystemPens.ControlDarkDark, x + 2, middle, x + 6, middle);
1262                                 dc.DrawLine (SystemPens.ControlDarkDark, x + 4, middle - 2, x + 4, middle + 2);
1263                         }
1264                 }
1265
1266                 private void DrawNodeCheckBox (TreeNode node, Graphics dc, int x, int middle)
1267                 {
1268                         Pen pen = ThemeEngine.Current.ResPool.GetSizedPen(Color.Black, 2);
1269                                 dc.DrawRectangle (pen, x + 3, middle - 4, 11, 11);
1270
1271                         if (node.Checked) {
1272                                 Pen check_pen = ThemeEngine.Current.ResPool.GetPen(Color.Black);
1273                                 
1274                                 int check_size = 5;
1275                                 int lineWidth = 3;
1276                                 
1277                                 Rectangle rect = new Rectangle (x + 5, middle - 2, check_size, check_size);
1278                                 
1279                                 for (int i = 0; i < lineWidth; i++) {
1280                                         dc.DrawLine (check_pen, rect.Left + 1, rect.Top + lineWidth + i, rect.Left + 3, rect.Top + 5 + i);
1281                                         dc.DrawLine (check_pen, rect.Left + 3, rect.Top + 5 + i, rect.Left + 7, rect.Top + 1 + i);
1282                                 }
1283                         }
1284                 }
1285
1286                 private void DrawNodeLines (TreeNode node, Graphics dc, Rectangle clip, Pen dash, int x, int y, int middle)
1287                 {
1288                         int ladjust = 9;
1289                         int radjust = 0;
1290
1291                         if (node.nodes.Count > 0 && show_plus_minus)
1292                                 ladjust = 13;
1293                         if (checkboxes)
1294                                 radjust = 3;
1295
1296                         dc.DrawLine (dash, x - indent + ladjust, middle, x + radjust, middle);
1297
1298                         if (node.PrevNode != null || node.Parent != null) {
1299                                 ladjust = 9;
1300                                 dc.DrawLine (dash, x - indent + ladjust, node.Bounds.Top,
1301                                                 x - indent + ladjust, middle - (show_plus_minus && node.Nodes.Count > 0 ? 4 : 0));
1302                         }
1303
1304                         if (node.NextNode != null) {
1305                                 ladjust = 9;
1306                                 dc.DrawLine (dash, x - indent + ladjust, middle + (show_plus_minus && node.Nodes.Count > 0 ? 4 : 0),
1307                                                 x - indent + ladjust, node.Bounds.Bottom);
1308                                 
1309                         }
1310
1311                         ladjust = 0;
1312                         if (show_plus_minus)
1313                                 ladjust = 9;
1314                         TreeNode parent = node.Parent;
1315                         while (parent != null) {
1316                                 if (parent.NextNode != null) {
1317                                         int px = parent.GetLinesX () - indent + ladjust;
1318                                         dc.DrawLine (dash, px, node.Bounds.Top, px, node.Bounds.Bottom);
1319                                 }
1320                                 parent = parent.Parent;
1321                         }
1322                 }
1323
1324                 private void DrawNodeImage (TreeNode node, Graphics dc, Rectangle clip, int x, int y)
1325                 {
1326                         // Rectangle r = new Rectangle (x, y + 2, ImageList.ImageSize.Width, ImageList.ImageSize.Height);
1327
1328                         if (!RectsIntersect (clip, x, y, ImageList.ImageSize.Width, ImageList.ImageSize.Height))
1329                                 return;
1330
1331                         if (ImageList == null)
1332                                 return;
1333
1334                         int use_index = -1;
1335
1336                         if (!node.IsSelected) {
1337                                 if (node.ImageIndex > -1 && node.ImageIndex < ImageList.Images.Count) {
1338                                         use_index = node.ImageIndex;
1339                                 } else if (ImageIndex > -1 && ImageIndex < ImageList.Images.Count) {
1340                                         use_index = ImageIndex;
1341                                 }
1342                         } else {
1343                                 if (node.SelectedImageIndex > -1 && node.SelectedImageIndex < ImageList.Images.Count) {
1344                                         use_index = node.SelectedImageIndex;
1345                                 } else if (SelectedImageIndex > -1 && SelectedImageIndex < ImageList.Images.Count) {
1346                                         use_index = SelectedImageIndex;
1347                                 }
1348                         }
1349
1350 #if NET_2_0
1351
1352                         if (!node.IsSelected) {
1353                                 if (use_index == -1 && !String.IsNullOrEmpty (node.ImageKey)) {
1354                                         use_index = image_list.Images.IndexOfKey (node.ImageKey);
1355                                 }
1356
1357                                 if (use_index == -1 && !String.IsNullOrEmpty (ImageKey)) {
1358                                         use_index = image_list.Images.IndexOfKey (ImageKey);
1359                                 }
1360                         } else {
1361                                 if (use_index == -1 && !String.IsNullOrEmpty (node.SelectedImageKey)) {
1362                                         use_index = image_list.Images.IndexOfKey (node.SelectedImageKey);
1363                                 }
1364
1365                                 if (use_index == -1 && !String.IsNullOrEmpty (SelectedImageKey)) {
1366                                         use_index = image_list.Images.IndexOfKey (SelectedImageKey);
1367                                 }
1368                         }
1369 #endif
1370
1371                         if (use_index == -1 && ImageList.Images.Count > 0) {
1372                                 use_index = 0;
1373                         }
1374
1375                         if (use_index != -1) {
1376                                 ImageList.Draw (dc, x, y, ImageList.ImageSize.Width, 
1377                                                 ImageList.ImageSize.Height, use_index);
1378                         }
1379                 }
1380
1381                 private void LabelEditFinished (object sender, EventArgs e)
1382                 {
1383                         EndEdit (edit_node);
1384                 }
1385
1386                 internal void BeginEdit (TreeNode node)
1387                 {
1388                         if (edit_node != null)
1389                                 EndEdit (edit_node);
1390
1391                         if (edit_text_box == null) {
1392                                 edit_text_box = new LabelEditTextBox ();
1393                                 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
1394                                 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
1395                                 Controls.Add (edit_text_box);
1396                         }
1397
1398                         edit_text_box.Bounds = node.Bounds;
1399                         edit_text_box.Width += 4;
1400
1401                         edit_text_box.Text = node.Text;
1402                         edit_text_box.Visible = true;
1403                         edit_text_box.Focus ();
1404                         edit_text_box.SelectAll ();
1405
1406                         edit_args = new NodeLabelEditEventArgs (edit_node);
1407                         OnBeforeLabelEdit (edit_args);
1408
1409                         if (edit_args.CancelEdit)
1410                                 EndEdit (node);
1411                         
1412                         edit_node = node;
1413                 }
1414
1415                 internal void EndEdit (TreeNode node)
1416                 {
1417                         if (edit_text_box != null && edit_text_box.Visible) {
1418                                 edit_text_box.Visible = false;
1419                         }
1420
1421                         if (edit_node != null && edit_node == node) {
1422                                 OnAfterLabelEdit (edit_args);
1423
1424                                 if (!edit_args.CancelEdit) {
1425                                         if (edit_args.Label != null)
1426                                                 edit_node.Text = edit_args.Label;
1427                                         else
1428                                                 edit_node.Text = edit_text_box.Text;
1429                                 }
1430
1431                         }
1432
1433                         
1434                         edit_node = null;
1435                         UpdateNode (node);
1436                 }
1437
1438                 internal int GetNodeWidth (TreeNode node)
1439                 {
1440                         Font font = node.NodeFont;
1441                         if (node.NodeFont == null)
1442                                 font = Font;
1443                         return (int) DeviceContext.MeasureString (node.Text, font, 0, string_format).Width + 3;
1444                 }
1445
1446                 private void DrawSelectionAndFocus(TreeNode node, Graphics dc, Rectangle r)
1447                 {
1448                         if (Focused && focused_node == node) {
1449                                 ControlPaint.DrawFocusRectangle (dc, r, ForeColor, BackColor);
1450                         }
1451                         if (draw_mode != TreeViewDrawMode.Normal)
1452                                 return;
1453
1454                         r.Inflate (-1, -1);
1455                         if (Focused && node == highlighted_node) {
1456                                 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight), r);
1457                         } else if (!hide_selection && node == highlighted_node) {
1458                                 dc.FillRectangle (SystemBrushes.Control, r);
1459                         } else {
1460                                 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (node.BackColor), r);
1461                         }
1462                 }
1463                  
1464                 private void DrawStaticNode (TreeNode node, Graphics dc)
1465                 {
1466                         if (!full_row_select)
1467                                 DrawSelectionAndFocus(node, dc, node.Bounds);
1468
1469                         
1470                         Font font = node.NodeFont;
1471                         if (node.NodeFont == null)
1472                                 font = Font;
1473                         Color text_color = (Focused && node == highlighted_node ?
1474                                         ThemeEngine.Current.ColorHighlightText : node.ForeColor);
1475                         if (text_color.IsEmpty)
1476                                 text_color = ForeColor;
1477                         dc.DrawString (node.Text, font,
1478                                         ThemeEngine.Current.ResPool.GetSolidBrush (text_color),
1479                                         node.Bounds, string_format);
1480                 }
1481
1482                 private void DrawTreeNode (TreeNode node, Graphics dc, Rectangle clip)
1483                 {
1484                         int child_count = node.nodes.Count;
1485                         int y = node.GetY ();
1486                         int middle = y + (ActualItemHeight / 2);
1487
1488                         if (full_row_select) {
1489                                 Rectangle r = new Rectangle (1, y + 2, ViewportRectangle.Width - 2, ActualItemHeight);
1490                                 DrawSelectionAndFocus (node, dc, r);
1491                         }
1492
1493                         if (draw_mode == TreeViewDrawMode.Normal || draw_mode == TreeViewDrawMode.OwnerDrawText) {
1494                                 if ((show_root_lines || node.Parent != null) && show_plus_minus && child_count > 0)
1495                                         DrawNodePlusMinus (node, dc, node.GetLinesX () - Indent + 5, middle);
1496
1497                                 if (checkboxes)
1498                                         DrawNodeCheckBox (node, dc, CheckBoxLeft (node) - 3, middle);
1499
1500                                 if (show_lines)
1501                                         DrawNodeLines (node, dc, clip, dash, node.GetLinesX (), y, middle);
1502
1503                                 if (ImageList != null)
1504                                         DrawNodeImage (node, dc, clip, node.GetImageX (), y);
1505                         }
1506
1507                         
1508 #if NET_2_0
1509                         if (draw_mode != TreeViewDrawMode.Normal) {
1510                                 dc.FillRectangle (Brushes.White, node.Bounds);
1511                                 TreeNodeStates tree_node_state = TreeNodeStates.Default;;
1512                                 if (node.IsSelected)
1513                                         tree_node_state = TreeNodeStates.Selected;
1514                                 if (node.Checked)
1515                                         tree_node_state |= TreeNodeStates.Checked;
1516                                 if (node == focused_node)
1517                                         tree_node_state |= TreeNodeStates.Focused;
1518                                 Rectangle node_bounds = node.Bounds;
1519                                 if (draw_mode == TreeViewDrawMode.OwnerDrawText) {
1520                                         node_bounds.X += 3;
1521                                         node_bounds.Y += 1;
1522                                 } else {
1523                                         node_bounds.X = 0;
1524                                         node_bounds.Width = Width;
1525                                 }
1526
1527                                 DrawTreeNodeEventArgs e = new DrawTreeNodeEventArgs (dc, node, node_bounds, tree_node_state);
1528
1529                                 OnDrawNode (e);                         
1530                                 if (!e.DrawDefault)
1531                                         return;
1532                         }
1533 #endif
1534
1535                         if (!node.IsEditing)
1536                                 DrawStaticNode (node, dc);
1537                 }
1538
1539                 internal void UpdateScrollBars ()
1540                 {
1541                         if (IsDisposed || update_stack > 0 || !IsHandleCreated || !Visible)
1542                                 return;
1543
1544                         bool vert = false;
1545                         bool horz = false;
1546                         int height = -1;
1547                         int width = -1;
1548
1549                         if (scrollable) {
1550                                 OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (root_node);
1551                                 
1552                                 while (walk.MoveNext ()) {
1553                                         int r = walk.CurrentNode.Bounds.Right;
1554                                         int b = walk.CurrentNode.Bounds.Bottom;
1555
1556                                         if (r > width)
1557                                                 width = r;
1558                                         if (b > height)
1559                                                 height = b;
1560                                 }
1561
1562                                 // Remove scroll adjustments
1563                                 if (nodes.Count > 0)
1564                                         height -= nodes [0].Bounds.Top;
1565                                 width += hbar_offset;
1566
1567                                 if (height > ClientRectangle.Height) {
1568                                         vert = true;
1569
1570                                         if (width > ClientRectangle.Width - SystemInformation.VerticalScrollBarWidth)
1571                                                 horz = true;
1572                                 } else if (width > ClientRectangle.Width) {
1573                                         horz = true;
1574                                 }
1575
1576                                 if (!vert && horz && height > ClientRectangle.Height - SystemInformation.HorizontalScrollBarHeight)
1577                                         vert = true;
1578                         }
1579
1580                         if (vert) {
1581                                 int visible_height = horz ? ClientRectangle.Height - hbar.Height : ClientRectangle.Height;
1582                                 vbar.SetValues (Math.Max (0, max_visible_order - 2), visible_height / ActualItemHeight);
1583                                 /*
1584                                 vbar.Maximum = max_visible_order;
1585                                 vbar.LargeChange = ClientRectangle.Height / ItemHeight;
1586                                 */
1587
1588                                 if (!vbar_bounds_set) {
1589                                         vbar.Bounds = new Rectangle (ClientRectangle.Width - vbar.Width, 0, vbar.Width,
1590                                                         ClientRectangle.Height -
1591                                                         (horz ? SystemInformation.VerticalScrollBarWidth : 0));
1592                                         vbar_bounds_set = true;
1593
1594                                         // We need to recalc the hbar if the vbar is now visible
1595                                         hbar_bounds_set = false;
1596                                 }
1597
1598                                 
1599                                 vbar.Visible = true;
1600                                 if (skipped_nodes > 0) {
1601                                         int skip = Math.Min (skipped_nodes, vbar.Maximum - VisibleCount + 1);
1602                                         skipped_nodes = 0;
1603                                         vbar.Value = skip;
1604                                         skipped_nodes = skip;
1605                                 }
1606                         } else {
1607                                 skipped_nodes = 0;
1608                                 RecalculateVisibleOrder (root_node);
1609                                 vbar.Visible = false;
1610                                 vbar_bounds_set = false;
1611                         }
1612
1613                         if (horz) {
1614                                 hbar.SetValues (width + 1, ClientRectangle.Width - (vert ? SystemInformation.VerticalScrollBarWidth : 0));
1615                                 /*
1616                                 hbar.LargeChange = ClientRectangle.Width;
1617                                 hbar.Maximum = width + 1;
1618                                 */
1619
1620                                 if (!hbar_bounds_set) {
1621                                         hbar.Bounds = new Rectangle (0, ClientRectangle.Height - hbar.Height,
1622                                                         ClientRectangle.Width - (vert ? SystemInformation.VerticalScrollBarWidth : 0),
1623                                                         hbar.Height);
1624                                         hbar_bounds_set = true;
1625                                 }
1626                                 hbar.Visible = true;
1627                         } else {
1628                                 hbar_offset = 0;
1629                                 hbar.Visible = false;
1630                                 hbar_bounds_set = false;
1631                         }
1632                 }
1633
1634                 private void SizeChangedHandler (object sender, EventArgs e)
1635                 {
1636                         if (IsHandleCreated) {
1637                                 if (max_visible_order == -1)
1638                                         RecalculateVisibleOrder (root_node);
1639                                 UpdateScrollBars ();
1640                         }
1641
1642                         if (vbar.Visible) {
1643                                 vbar.Bounds = new Rectangle (ClientRectangle.Width - vbar.Width, 0, vbar.Width,
1644                                                 ClientRectangle.Height - (hbar.Visible ? SystemInformation.HorizontalScrollBarHeight : 0));
1645                         }
1646
1647                         if (hbar.Visible) {
1648                                 hbar.Bounds = new Rectangle (0, ClientRectangle.Height - hbar.Height,
1649                                                 ClientRectangle.Width - (vbar.Visible ? SystemInformation.VerticalScrollBarWidth : 0), hbar.Height);
1650                         }
1651                 }
1652
1653                 private void VScrollBarValueChanged (object sender, EventArgs e)
1654                 {
1655                         EndEdit (edit_node);
1656
1657                         SetVScrollPos (vbar.Value, null);
1658                 }
1659
1660                 private void SetVScrollPos (int pos, TreeNode new_top)
1661                 {
1662                         if (pos < 0)
1663                                 pos = 0;
1664
1665                         if (skipped_nodes == pos)
1666                                 return;
1667
1668                         int diff = skipped_nodes - pos;
1669                         skipped_nodes = pos;
1670
1671                         int y_move = diff * ActualItemHeight;
1672                         XplatUI.ScrollWindow (Handle, ViewportRectangle, 0, y_move, false);
1673                 }
1674
1675                 private void SetVScrollTop (TreeNode new_top)
1676                 {
1677                         vbar.Value = new_top.visible_order - VisibleCount;
1678                 }
1679
1680                 private void HScrollBarValueChanged(object sender, EventArgs e)
1681                 {
1682                         EndEdit (edit_node);
1683
1684                         int old_offset = hbar_offset;
1685                         hbar_offset = hbar.Value;
1686
1687                         if (hbar_offset < 0) {
1688                                 hbar_offset = 0;
1689                         }
1690
1691                         XplatUI.ScrollWindow (Handle, ViewportRectangle, old_offset - hbar_offset, 0, false);
1692                 }
1693
1694                 internal void ExpandBelow (TreeNode node, int count_to_next)
1695                 {
1696                         if (update_stack > 0) {
1697                                 update_needed = true;
1698                                 return;
1699                         }
1700
1701                         Rectangle below = new Rectangle (0, node.Bounds.Bottom, ViewportRectangle.Width,
1702                                         ViewportRectangle.Height - node.Bounds.Bottom);
1703
1704                         int amount = count_to_next * ActualItemHeight;
1705
1706                         if (amount > 0)
1707                                 XplatUI.ScrollWindow (Handle, below, 0, amount, false);
1708
1709                         if (show_plus_minus) {
1710                                 Invalidate (new Rectangle (0, node.GetY (), Width, ActualItemHeight));
1711                         }
1712                 }
1713
1714                 internal void CollapseBelow (TreeNode node, int count_to_next)
1715                 {
1716                         if (update_stack > 0) {
1717                                 update_needed = true;
1718                                 return;
1719                         }
1720
1721                         Rectangle below = new Rectangle (0, node.Bounds.Bottom, ViewportRectangle.Width,
1722                                         ViewportRectangle.Height - node.Bounds.Bottom);
1723
1724                         int amount = count_to_next * ActualItemHeight;
1725
1726                         if (amount > 0)
1727                                 XplatUI.ScrollWindow (Handle, below, 0, -amount, false);
1728
1729                         if (show_plus_minus) {
1730                                 Invalidate (new Rectangle (0, node.GetY (), Width, ActualItemHeight));
1731                         }
1732                 }
1733
1734                 private void MouseWheelHandler(object sender, MouseEventArgs e) {
1735
1736                         if (vbar == null || !vbar.is_visible) {
1737                                 return;
1738                         }
1739
1740                         if (e.Delta < 0) {
1741                                 vbar.Value = Math.Min(vbar.Value + SystemInformation.MouseWheelScrollLines, vbar.Maximum - VisibleCount + 1);
1742                         } else {
1743                                 vbar.Value = Math.Max(0, vbar.Value - SystemInformation.MouseWheelScrollLines);
1744                         }
1745                 }
1746
1747                 private void VisibleChangedHandler (object sender, EventArgs e)
1748                 {
1749                         if (Visible) {
1750                                 UpdateScrollBars ();
1751                         }
1752                 }
1753
1754                 private void FontChangedHandler (object sender, EventArgs e)
1755                 {
1756                         if (IsHandleCreated) {
1757                                 TreeNode top = TopNode;
1758                                 InvalidateNodeWidthRecursive (root_node);
1759
1760                                 SetTop (top);
1761                         }
1762                 }
1763
1764                 private void InvalidateNodeWidthRecursive (TreeNode node)
1765                 {
1766                         node.InvalidateWidth ();
1767                         foreach (TreeNode child in node.Nodes) {
1768                                 InvalidateNodeWidthRecursive (child);
1769                         }
1770                 }
1771
1772                 private void GotFocusHandler (object sender, EventArgs e)
1773                 {
1774                         if (selected_node == null && pre_selected_node != null)
1775                                 SelectedNode = pre_selected_node;
1776                         else if (selected_node != null)
1777                                 UpdateNode (selected_node);
1778                 }
1779
1780                 private void LostFocusHandler (object sender, EventArgs e)
1781                 {
1782                         UpdateNode (SelectedNode);
1783                 }
1784
1785                 private void MouseDownHandler (object sender, MouseEventArgs e)
1786                 {
1787                         if (e.Button == MouseButtons.Right)
1788                                 Focus ();
1789
1790                         TreeNode node = GetNodeAt (e.Y);
1791                         if (node == null)
1792                                 return;
1793
1794                         if (show_plus_minus && IsPlusMinusArea (node, e.X)) {
1795                                 node.Toggle ();
1796                                 return;
1797                         } else if (checkboxes && IsCheckboxArea (node, e.X)) {
1798                                 node.check_reason = TreeViewAction.ByMouse;
1799                                 node.Checked = !node.Checked;
1800                                 UpdateNode(node);
1801                                 return;
1802                         } else if (IsSelectableArea (node, e.X) || full_row_select) {
1803                                 TreeNode old_highlighted = highlighted_node;
1804                                 highlighted_node = node;
1805                                 if (label_edit && e.Clicks == 1 && highlighted_node == old_highlighted) {
1806                                         BeginEdit (node);
1807                                 } else if (highlighted_node != focused_node) {
1808                                         Size ds = SystemInformation.DragSize;
1809                                         mouse_rect.X = e.X - ds.Width;
1810                                         mouse_rect.Y = e.Y - ds.Height;
1811                                         mouse_rect.Width = ds.Width * 2;
1812                                         mouse_rect.Height = ds.Height * 2;
1813
1814                                         select_mmove = true;
1815                                 }
1816
1817                                 Invalidate (highlighted_node.Bounds);
1818                                 if (old_highlighted != null)
1819                                         Invalidate (Bloat (old_highlighted.Bounds));
1820                         } 
1821                 }
1822
1823                 private void MouseUpHandler (object sender, MouseEventArgs e) {
1824
1825                         drag_begin_x = -1;
1826                         drag_begin_y = -1;
1827
1828                         if (!select_mmove)
1829                                 return;
1830
1831                         if (e.Button == MouseButtons.Right) {
1832                                 Invalidate (highlighted_node.Bounds);
1833                                 highlighted_node = selected_node;
1834                                 Invalidate (selected_node.Bounds);
1835                         }
1836                         select_mmove = false;
1837
1838                         TreeViewCancelEventArgs ce = new TreeViewCancelEventArgs (highlighted_node, false, TreeViewAction.ByMouse);
1839                         OnBeforeSelect (ce);
1840
1841                         Rectangle invalid;
1842                         if (!ce.Cancel) {
1843                                 TreeNode prev_focused_node = focused_node;
1844                                 TreeNode prev_highlighted_node = highlighted_node;
1845                                 
1846                                 selected_node = highlighted_node;
1847                                 focused_node = highlighted_node;
1848                                 OnAfterSelect (new TreeViewEventArgs (selected_node, TreeViewAction.ByMouse));
1849
1850                                 if (prev_focused_node != null) {
1851                                         invalid = Rectangle.Union (Bloat (prev_focused_node.Bounds),
1852                                                         Bloat (prev_highlighted_node.Bounds));
1853                                 } else {
1854                                         invalid = Bloat (prev_highlighted_node.Bounds);
1855                                 }
1856
1857                                 Invalidate (invalid);
1858                         } else {
1859                                 highlighted_node = focused_node;
1860                                 selected_node = focused_node;
1861                         }
1862                 }
1863
1864                 private void MouseMoveHandler (object sender, MouseEventArgs e) {
1865
1866                         if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right) {
1867                                 if (drag_begin_x == -1 && drag_begin_y == -1) {
1868                                         drag_begin_x = e.X;
1869                                         drag_begin_y = e.Y;
1870                                 } else {
1871                                         double rise = Math.Pow (drag_begin_x - e.X, 2);
1872                                         double run = Math.Pow (drag_begin_y - e.Y, 2);
1873                                         double move = Math.Sqrt (rise + run);
1874                                         if (move > 3) {
1875                                                 TreeNode drag = GetNodeAtUseX (e.X, e.Y);
1876                                                 
1877                                                 if (drag != null) {
1878                                                         OnItemDrag (new ItemDragEventArgs (e.Button, drag));
1879                                                 }
1880                                                 drag_begin_x = -1;
1881                                                 drag_begin_y = -1;
1882                                         }
1883                                 }
1884                                 
1885                         }
1886
1887                         // If there is enough movement before the mouse comes up,
1888                         // selection is reverted back to the originally selected node
1889                         if (!select_mmove || mouse_rect.Contains (e.X, e.Y))
1890                                 return;
1891
1892                         Invalidate (highlighted_node.Bounds);
1893                         Invalidate (selected_node.Bounds);
1894                         Invalidate (focused_node.Bounds);
1895
1896                         highlighted_node = selected_node;
1897                         focused_node = selected_node;
1898
1899                         select_mmove = false;
1900                 }
1901
1902                 private void DoubleClickHandler (object sender, MouseEventArgs e) {
1903                         TreeNode node = GetNodeAtUseX (e.X,e.Y);
1904                         if(node != null) {
1905                                 node.Toggle();
1906                         }
1907                 }
1908
1909                 
1910                 private bool RectsIntersect (Rectangle r, int left, int top, int width, int height)
1911                 {
1912                         return !((r.Left > left + width) || (r.Right < left) ||
1913                                         (r.Top > top + height) || (r.Bottom < top));
1914                 }
1915
1916                 #endregion      // Internal & Private Methods and Properties
1917
1918                 #region Events
1919                 static object ItemDragEvent = new object ();
1920                 static object AfterCheckEvent = new object ();
1921                 static object AfterCollapseEvent = new object ();
1922                 static object AfterExpandEvent = new object ();
1923                 static object AfterLabelEditEvent = new object ();
1924                 static object AfterSelectEvent = new object ();
1925                 static object BeforeCheckEvent = new object ();
1926                 static object BeforeCollapseEvent = new object ();
1927                 static object BeforeExpandEvent = new object ();
1928                 static object BeforeLabelEditEvent = new object ();
1929                 static object BeforeSelectEvent = new object ();
1930 #if NET_2_0
1931                 static object DrawNodeEvent = new object ();
1932                 static object NodeMouseClickEvent = new object ();
1933                 static object NodeMouseDoubleClickEvent = new object();
1934 #endif
1935
1936                 public event ItemDragEventHandler ItemDrag {
1937                         add { Events.AddHandler (ItemDragEvent, value); }
1938                         remove { Events.RemoveHandler (ItemDragEvent, value); }
1939                 }
1940
1941                 public event TreeViewEventHandler AfterCheck {
1942                         add { Events.AddHandler (AfterCheckEvent, value); }
1943                         remove { Events.RemoveHandler (AfterCheckEvent, value); }
1944                 }
1945
1946                 public event TreeViewEventHandler AfterCollapse {
1947                         add { Events.AddHandler (AfterCollapseEvent, value); }
1948                         remove { Events.RemoveHandler (AfterCollapseEvent, value); }
1949                 }
1950
1951                 public event TreeViewEventHandler AfterExpand {
1952                         add { Events.AddHandler (AfterExpandEvent, value); }
1953                         remove { Events.RemoveHandler (AfterExpandEvent, value); }
1954                 }
1955
1956                 public event NodeLabelEditEventHandler AfterLabelEdit {
1957                         add { Events.AddHandler (AfterLabelEditEvent, value); }
1958                         remove { Events.RemoveHandler (AfterLabelEditEvent, value); }
1959                 }
1960
1961                 public event TreeViewEventHandler AfterSelect {
1962                         add { Events.AddHandler (AfterSelectEvent, value); }
1963                         remove { Events.RemoveHandler (AfterSelectEvent, value); }
1964                 }
1965
1966                 public event TreeViewCancelEventHandler BeforeCheck {
1967                         add { Events.AddHandler (BeforeCheckEvent, value); }
1968                         remove { Events.RemoveHandler (BeforeCheckEvent, value); }
1969                 }
1970
1971                 public event TreeViewCancelEventHandler BeforeCollapse {
1972                         add { Events.AddHandler (BeforeCollapseEvent, value); }
1973                         remove { Events.RemoveHandler (BeforeCollapseEvent, value); }
1974                 }
1975
1976                 public event TreeViewCancelEventHandler BeforeExpand {
1977                         add { Events.AddHandler (BeforeExpandEvent, value); }
1978                         remove { Events.RemoveHandler (BeforeExpandEvent, value); }
1979                 }
1980
1981                 public event NodeLabelEditEventHandler BeforeLabelEdit {
1982                         add { Events.AddHandler (BeforeLabelEditEvent, value); }
1983                         remove { Events.RemoveHandler (BeforeLabelEditEvent, value); }
1984                 }
1985
1986                 public event TreeViewCancelEventHandler BeforeSelect {
1987                         add { Events.AddHandler (BeforeSelectEvent, value); }
1988                         remove { Events.RemoveHandler (BeforeSelectEvent, value); }
1989                 }
1990
1991 #if NET_2_0
1992                 public event DrawTreeNodeEventHandler DrawNode {
1993                         add { Events.AddHandler (DrawNodeEvent, value); }
1994                         remove { Events.RemoveHandler (DrawNodeEvent, value); }
1995                 }
1996
1997                 public event TreeNodeMouseClickEventHandler NodeMouseClick {
1998                         add { Events.AddHandler (NodeMouseClickEvent, value); }
1999                         remove { Events.RemoveHandler (NodeMouseClickEvent, value); }
2000                 }
2001
2002
2003                 public event TreeNodeMouseClickEventHandler NodeMouseDoubleClick {
2004                         add { Events.AddHandler (NodeMouseDoubleClickEvent, value); }
2005                         remove { Events.RemoveHandler (NodeMouseDoubleClickEvent, value); }
2006                 }
2007 #endif
2008
2009                 [Browsable (false)]
2010                 [EditorBrowsable (EditorBrowsableState.Never)]  
2011                 public new event EventHandler BackgroundImageChanged {
2012                         add { base.BackgroundImageChanged += value; }
2013                         remove { base.BackgroundImageChanged -= value; }
2014                 }
2015
2016                 [EditorBrowsable (EditorBrowsableState.Never)]  
2017                 [Browsable (false)]
2018                 public new event PaintEventHandler Paint {
2019                         add { base.Paint += value; }
2020                         remove { base.Paint -= value; }
2021                 }
2022
2023                 [EditorBrowsable (EditorBrowsableState.Never)]  
2024                 [Browsable (false)]
2025                 public new event EventHandler TextChanged {
2026                         add { base.TextChanged += value; }
2027                         remove { base.TextChanged -= value; }
2028                 }
2029                 #endregion      // Events
2030         }
2031 }
2032