2008-09-23 Jonathan Pobst <monkey@jpobst.com>
[mcs.git] / class / Managed.Windows.Forms / System.Windows.Forms / TreeView.cs
blobe510943db41567f8dce6d92ba57f2f50daa4c65c
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.
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.
20 // Copyright (c) 2004-2005 Novell, Inc.
22 // Authors:
23 // Jackson Harper (jackson@ximian.com)
24 // Kazuki Oikawa (kazuki@panicode.com)
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;
34 namespace System.Windows.Forms {
35 #if NET_2_0
36 [ComVisible (true)]
37 [Docking (DockingBehavior.Ask)]
38 [ClassInterface (ClassInterfaceType.AutoDispatch)]
39 #endif
40 [DefaultProperty("Nodes")]
41 [DefaultEvent("AfterSelect")]
42 [Designer("System.Windows.Forms.Design.TreeViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
43 public class TreeView : Control {
44 #region Fields
45 private string path_separator = "\\";
46 private int item_height = -1;
47 private bool sorted;
48 internal TreeNode root_node;
49 internal bool nodes_added;
50 private TreeNodeCollection nodes;
52 private TreeViewAction selection_action;
53 internal TreeNode selected_node;
54 private TreeNode pre_selected_node;
55 private TreeNode focused_node;
56 internal TreeNode highlighted_node;
57 private Rectangle mouse_rect;
58 private bool select_mmove;
60 private ImageList image_list;
61 private int image_index = -1;
62 private int selected_image_index = -1;
64 #if NET_2_0
65 private string image_key;
66 private bool is_hovering;
67 private TreeNode mouse_click_node;
68 private bool right_to_left_layout;
69 private string selected_image_key;
70 private bool show_node_tool_tips;
71 private ImageList state_image_list;
72 private TreeNode tooltip_currently_showing;
73 private ToolTip tooltip_window;
74 #endif
75 private bool full_row_select;
76 private bool hot_tracking;
77 private int indent = 19;
79 private NodeLabelEditEventArgs edit_args;
80 private LabelEditTextBox edit_text_box;
81 internal TreeNode edit_node;
83 private bool checkboxes;
84 private bool label_edit;
85 private bool scrollable = true;
86 private bool show_lines = true;
87 private bool show_root_lines = true;
88 private bool show_plus_minus = true;
89 private bool hide_selection = true;
91 private int max_visible_order = -1;
92 internal VScrollBar vbar;
93 internal HScrollBar hbar;
94 private bool vbar_bounds_set;
95 private bool hbar_bounds_set;
96 internal int skipped_nodes;
97 internal int hbar_offset;
99 private int update_stack;
100 private bool update_needed;
102 private Pen dash;
103 private Color line_color;
104 private StringFormat string_format;
106 private int drag_begin_x = -1;
107 private int drag_begin_y = -1;
108 private long handle_count = 1;
110 private TreeViewDrawMode draw_mode;
112 #if NET_2_0
113 IComparer tree_view_node_sorter;
114 #endif
115 #endregion // Fields
117 #region Public Constructors
118 public TreeView ()
120 vbar = new ImplicitVScrollBar ();
121 hbar = new ImplicitHScrollBar ();
123 InternalBorderStyle = BorderStyle.Fixed3D;
124 base.background_color = ThemeEngine.Current.ColorWindow;
125 base.foreground_color = ThemeEngine.Current.ColorWindowText;
127 root_node = new TreeNode (this);
128 root_node.Text = "ROOT NODE";
129 nodes = new TreeNodeCollection (root_node);
130 root_node.SetNodes (nodes);
132 MouseDown += new MouseEventHandler (MouseDownHandler);
133 MouseUp += new MouseEventHandler(MouseUpHandler);
134 MouseMove += new MouseEventHandler(MouseMoveHandler);
135 SizeChanged += new EventHandler (SizeChangedHandler);
136 FontChanged += new EventHandler (FontChangedHandler);
137 LostFocus += new EventHandler (LostFocusHandler);
138 GotFocus += new EventHandler (GotFocusHandler);
139 MouseWheel += new MouseEventHandler(MouseWheelHandler);
140 VisibleChanged += new EventHandler (VisibleChangedHandler);
142 SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick
143 #if NET_2_0
144 | ControlStyles.UseTextForAccessibility
145 #endif
146 , false);
148 string_format = new StringFormat ();
149 string_format.LineAlignment = StringAlignment.Center;
150 string_format.Alignment = StringAlignment.Center;
152 vbar.Visible = false;
153 hbar.Visible = false;
154 vbar.ValueChanged += new EventHandler (VScrollBarValueChanged);
155 hbar.ValueChanged += new EventHandler (HScrollBarValueChanged);
157 SuspendLayout ();
158 Controls.AddImplicit (vbar);
159 Controls.AddImplicit (hbar);
160 ResumeLayout ();
163 #endregion // Public Constructors
165 #region Public Instance Properties
166 public override Color BackColor {
167 get { return base.BackColor;}
168 set {
169 base.BackColor = value;
171 CreateDashPen ();
172 Invalidate ();
177 [Browsable(false)]
178 [EditorBrowsable(EditorBrowsableState.Never)]
179 public override Image BackgroundImage {
180 get { return base.BackgroundImage; }
181 set { base.BackgroundImage = value; }
184 [DefaultValue(BorderStyle.Fixed3D)]
185 [DispId(-504)]
186 public BorderStyle BorderStyle {
187 get { return InternalBorderStyle; }
188 set { InternalBorderStyle = value; }
191 [DefaultValue(false)]
192 public bool CheckBoxes {
193 get { return checkboxes; }
194 set {
195 if (value == checkboxes)
196 return;
197 checkboxes = value;
199 // Match a "bug" in the MS implementation where disabling checkboxes
200 // collapses the entire tree, but enabling them does not affect the
201 // state of the tree.
202 if (!checkboxes)
203 root_node.CollapseAllUncheck ();
205 Invalidate ();
209 public override Color ForeColor {
210 get { return base.ForeColor; }
211 set { base.ForeColor = value; }
213 [DefaultValue(false)]
214 public bool FullRowSelect {
215 get { return full_row_select; }
216 set {
217 if (value == full_row_select)
218 return;
219 full_row_select = value;
220 Invalidate ();
223 [DefaultValue(true)]
224 public bool HideSelection {
225 get { return hide_selection; }
226 set {
227 if (hide_selection == value)
228 return;
229 hide_selection = value;
230 Invalidate ();
234 [DefaultValue(false)]
235 public bool HotTracking {
236 get { return hot_tracking; }
237 set { hot_tracking = value; }
240 #if NET_2_0
241 [DefaultValue (-1)]
242 [RelatedImageList ("ImageList")]
243 [RefreshProperties (RefreshProperties.Repaint)]
244 [TypeConverter (typeof (NoneExcludedImageIndexConverter))]
245 #else
246 [DefaultValue (0)]
247 [TypeConverter (typeof (TreeViewImageIndexConverter))]
248 #endif
249 [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
250 [Localizable(true)]
251 public int ImageIndex {
252 get { return image_index; }
253 set {
254 if (value < -1) {
255 throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
256 "'value' must be greater than or equal to 0.");
258 if (image_index == value)
259 return;
260 image_index = value;
261 Invalidate ();
265 #if NET_2_0
266 [RefreshProperties (RefreshProperties.Repaint)]
267 #endif
268 [DefaultValue(null)]
269 public ImageList ImageList {
270 get { return image_list; }
271 set {
272 image_list = value;
273 Invalidate ();
277 [Localizable(true)]
278 public int Indent {
279 get { return indent; }
280 set {
281 if (indent == value)
282 return;
283 if (value > 32000) {
284 throw new ArgumentException ("'" + value + "' is not a valid value for 'Indent'. " +
285 "'Indent' must be less than or equal to 32000");
287 if (value < 0) {
288 throw new ArgumentException ("'" + value + "' is not a valid value for 'Indent'. " +
289 "'Indent' must be greater than or equal to 0.");
291 indent = value;
292 Invalidate ();
296 #if !NET_2_0
297 [Localizable(true)]
298 #endif
299 public int ItemHeight {
300 get {
301 if (item_height == -1)
302 return FontHeight + 3;
303 return item_height;
305 set {
306 if (value == item_height)
307 return;
308 item_height = value;
309 Invalidate ();
313 internal int ActualItemHeight {
314 get {
315 int res = ItemHeight;
316 if (ImageList != null && ImageList.ImageSize.Height > res)
317 res = ImageList.ImageSize.Height;
318 return res;
322 [DefaultValue(false)]
323 public bool LabelEdit {
324 get { return label_edit; }
325 set { label_edit = value; }
328 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
329 [MergableProperty(false)]
330 [Localizable(true)]
331 public TreeNodeCollection Nodes {
332 get { return nodes; }
335 #if NET_2_0
336 [Browsable (false)]
337 [EditorBrowsable (EditorBrowsableState.Never)]
338 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
339 public new Padding Padding {
340 get { return base.Padding; }
341 set { base.Padding = value; }
343 #endif
345 [DefaultValue("\\")]
346 public string PathSeparator {
347 get { return path_separator; }
348 set { path_separator = value; }
351 #if NET_2_0
352 [Localizable (true)]
353 [DefaultValue (false)]
354 public virtual bool RightToLeftLayout {
355 get { return right_to_left_layout; }
356 set {
357 if (right_to_left_layout != value) {
358 right_to_left_layout = value;
359 OnRightToLeftLayoutChanged (EventArgs.Empty);
363 #endif
365 [DefaultValue(true)]
366 public bool Scrollable {
367 get { return scrollable; }
368 set {
369 if (scrollable == value)
370 return;
371 scrollable = value;
372 UpdateScrollBars (false);
376 #if NET_2_0
377 [DefaultValue (-1)]
378 [RelatedImageList ("ImageList")]
379 [TypeConverter (typeof (NoneExcludedImageIndexConverter))]
380 #else
381 [DefaultValue (0)]
382 [TypeConverter (typeof (TreeViewImageIndexConverter))]
383 #endif
384 [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
385 [Localizable(true)]
386 public int SelectedImageIndex {
387 get { return selected_image_index; }
388 set {
389 if (value < -1) {
390 throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
391 "'value' must be greater than or equal to 0.");
393 UpdateNode (SelectedNode);
397 [Browsable(false)]
398 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
399 public TreeNode SelectedNode {
400 get {
401 if (!IsHandleCreated)
402 return pre_selected_node;
403 return selected_node;
405 set {
406 if (!IsHandleCreated) {
407 pre_selected_node = value;
408 return;
411 if (selected_node == value) {
412 selection_action = TreeViewAction.Unknown;
413 return;
416 if (value != null) {
417 TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (value, false, selection_action);
418 OnBeforeSelect (e);
420 if (e.Cancel)
421 return;
424 Rectangle invalid = Rectangle.Empty;
426 if (selected_node != null) {
427 invalid = Bloat (selected_node.Bounds);
429 if (focused_node != null) {
430 invalid = Rectangle.Union (invalid,
431 Bloat (focused_node.Bounds));
434 if (value != null)
435 invalid = Rectangle.Union (invalid, Bloat (value.Bounds));
437 highlighted_node = value;
438 selected_node = value;
439 focused_node = value;
441 if (full_row_select || draw_mode != TreeViewDrawMode.Normal) {
442 invalid.X = 0;
443 invalid.Width = ViewportRectangle.Width;
446 if (invalid != Rectangle.Empty)
447 Invalidate (invalid);
449 // We ensure its visible after we update because
450 // scrolling is used for insure visible
451 if (selected_node != null)
452 selected_node.EnsureVisible ();
454 if (value != null) {
455 OnAfterSelect (new TreeViewEventArgs (value, TreeViewAction.Unknown));
457 selection_action = TreeViewAction.Unknown;
461 private Rectangle Bloat (Rectangle rect)
463 rect.Y--;
464 rect.X--;
465 rect.Height += 2;
466 rect.Width += 2;
467 return rect;
470 [DefaultValue(true)]
471 public bool ShowLines {
472 get { return show_lines; }
473 set {
474 if (show_lines == value)
475 return;
476 show_lines = value;
477 Invalidate ();
481 #if NET_2_0
482 [DefaultValue (false)]
483 public bool ShowNodeToolTips {
484 get { return show_node_tool_tips; }
485 set { show_node_tool_tips = value; }
487 #endif
489 [DefaultValue(true)]
490 public bool ShowPlusMinus {
491 get { return show_plus_minus; }
492 set {
493 if (show_plus_minus == value)
494 return;
495 show_plus_minus = value;
496 Invalidate ();
500 [DefaultValue(true)]
501 public bool ShowRootLines {
502 get { return show_root_lines; }
503 set {
504 if (show_root_lines == value)
505 return;
506 show_root_lines = value;
507 Invalidate ();
511 #if NET_2_0
512 [Browsable (false)]
513 [EditorBrowsable (EditorBrowsableState.Never)]
514 #endif
515 [DefaultValue(false)]
516 public bool Sorted {
517 get { return sorted; }
518 set {
519 #if NET_2_0
520 if (sorted == value)
521 return;
522 sorted = value;
523 //LAMESPEC: The documentation says that setting this to true should sort alphabetically if TreeViewNodeSorter is set.
524 // There seems to be a bug in the Microsoft implementation.
525 if (sorted && tree_view_node_sorter == null) {
526 Sort (null);
528 #else
529 if (sorted != value)
530 sorted = value;
531 if (sorted) {
532 Sort (null);
534 #endif
538 #if NET_2_0
539 [DefaultValue (null)]
540 public ImageList StateImageList {
541 get { return state_image_list; }
542 set {
543 state_image_list = value;
544 Invalidate ();
547 #endif
549 [Browsable(false)]
550 [EditorBrowsable(EditorBrowsableState.Never)]
551 [Bindable(false)]
552 public override string Text {
553 get { return base.Text; }
554 set { base.Text = value; }
557 [Browsable(false)]
558 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
559 public TreeNode TopNode {
560 get {
561 if (root_node.FirstNode == null)
562 return null;
563 OpenTreeNodeEnumerator one = new OpenTreeNodeEnumerator (root_node.FirstNode);
564 one.MoveNext ();
565 for (int i = 0; i < skipped_nodes; i++)
566 one.MoveNext ();
567 return one.CurrentNode;
569 #if NET_2_0
570 set {
571 SetTop (value);
573 #endif
576 #if NET_2_0
577 [Browsable (false)]
578 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
579 public IComparer TreeViewNodeSorter {
580 get {
581 return tree_view_node_sorter;
583 set {
584 tree_view_node_sorter = value;
585 if (tree_view_node_sorter != null) {
586 Sort();
587 //LAMESPEC: The documentation says that setting this should set Sorted to false.
588 // There seems to be a bug in the Microsoft implementation.
589 sorted = true;
593 #endif
595 [Browsable(false)]
596 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
597 public int VisibleCount {
598 get {
599 return ViewportRectangle.Height / ActualItemHeight;
603 #if NET_2_0
604 /// According to MSDN this property has no effect on the treeview
605 [EditorBrowsable (EditorBrowsableState.Never)]
606 protected override bool DoubleBuffered {
607 get { return base.DoubleBuffered; }
608 set { base.DoubleBuffered = value; }
610 #endif
612 #if NET_2_0
613 [DefaultValue ("Color [Black]")]
614 public
615 #else
616 private
617 #endif
618 Color LineColor {
619 get {
620 if (line_color == Color.Empty) {
621 Color res = ControlPaint.Dark (BackColor);
622 if (res == BackColor)
623 res = ControlPaint.Light (BackColor);
624 return res;
626 return line_color;
628 set {
629 line_color = value;
630 if (show_lines) {
631 CreateDashPen ();
632 Invalidate ();
636 #if NET_2_0
637 [Localizable (true)]
638 [DefaultValue ("")]
639 [RelatedImageList ("ImageList")]
640 [RefreshProperties (RefreshProperties.Repaint)]
641 [TypeConverter (typeof (ImageKeyConverter))]
642 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
643 public string ImageKey {
644 get { return image_key; }
645 set {
646 if (image_key == value)
647 return;
648 image_index = -1;
649 image_key = value;
650 Invalidate ();
654 [Localizable (true)]
655 [DefaultValue ("")]
656 [RelatedImageList ("ImageList")]
657 [RefreshProperties (RefreshProperties.Repaint)]
658 [TypeConverter (typeof (ImageKeyConverter))]
659 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
660 public string SelectedImageKey {
661 get { return selected_image_key; }
662 set {
663 if (selected_image_key == value)
664 return;
665 selected_image_index = -1;
666 selected_image_key = value;
667 UpdateNode (SelectedNode);
670 #endif
672 #if NET_2_0
673 [Browsable (false)]
674 [EditorBrowsable (EditorBrowsableState.Never)]
675 public override ImageLayout BackgroundImageLayout {
676 get { return base.BackgroundImageLayout; }
677 set { base.BackgroundImageLayout = value; }
679 #endif
681 #if NET_2_0
682 [DefaultValue (TreeViewDrawMode.Normal)]
683 public TreeViewDrawMode DrawMode {
684 get { return draw_mode; }
685 set { draw_mode = value; }
687 #endif
688 #endregion // Public Instance Properties
690 #region Protected Instance Properties
691 protected override CreateParams CreateParams {
692 get {
693 CreateParams cp = base.CreateParams;
694 return cp;
698 protected override Size DefaultSize {
699 get { return new Size (121, 97); }
702 #endregion // Protected Instance Properties
704 #region Public Instance Methods
705 public void BeginUpdate ()
707 update_stack++;
710 public void EndUpdate ()
712 if (update_stack > 1) {
713 update_stack--;
714 } else {
715 update_stack = 0;
716 if (update_needed) {
717 RecalculateVisibleOrder (root_node);
718 UpdateScrollBars (false);
719 // if (SelectedNode != null)
720 // SelectedNode.EnsureVisible ();
721 Invalidate (ViewportRectangle);
722 update_needed = false;
727 #if NET_2_0
728 public void Sort ()
730 Sort (Nodes.Count >= 2 ? tree_view_node_sorter : null);
732 #endif
734 void Sort (IComparer sorter)
736 sorted = true;
737 Nodes.Sort (sorter);
738 RecalculateVisibleOrder (root_node);
739 UpdateScrollBars (false);
740 Invalidate ();
743 public void ExpandAll ()
745 BeginUpdate ();
746 root_node.ExpandAll ();
748 EndUpdate ();
751 /// Everything below this is basically an emulation of a strange bug on MS
752 /// where they don't always scroll to the last node on ExpandAll
754 #if NET_2_0
755 if (!IsHandleCreated)
756 return;
757 #endif
759 bool found = false;
760 foreach (TreeNode child in Nodes) {
761 if (child.Nodes.Count > 0)
762 found = true;
765 if (!found)
766 return;
768 if (IsHandleCreated && vbar.VisibleInternal) {
769 vbar.Value = vbar.Maximum - VisibleCount + 1;
770 } else {
771 RecalculateVisibleOrder (root_node);
772 UpdateScrollBars (true);
773 SetTop (Nodes [Nodes.Count - 1]);
774 SelectedNode = Nodes [Nodes.Count - 1];
779 public void CollapseAll ()
781 TreeNode walk = TopNode;
783 if (walk == null)
784 return;
786 while (walk.parent != root_node)
787 walk = walk.parent;
789 BeginUpdate ();
790 root_node.CollapseAll ();
791 EndUpdate ();
793 SetTop (walk);
796 public TreeNode GetNodeAt (Point pt) {
797 return GetNodeAt (pt.Y);
800 public TreeNode GetNodeAt (int x, int y)
802 return GetNodeAt (y);
805 private TreeNode GetNodeAtUseX (int x, int y) {
806 TreeNode node = GetNodeAt (y);
807 if (node == null || !(IsTextArea (node, x) || full_row_select))
808 return null;
809 return node;
813 public int GetNodeCount (bool includeSubTrees) {
814 return root_node.GetNodeCount (includeSubTrees);
817 #if NET_2_0
818 public TreeViewHitTestInfo HitTest (Point pt)
820 return HitTest (pt.X, pt.Y);
823 public TreeViewHitTestInfo HitTest (int x, int y)
825 TreeNode n = GetNodeAt (y);
827 if (n == null)
828 return new TreeViewHitTestInfo (null, TreeViewHitTestLocations.None);
830 if (IsTextArea (n, x))
831 return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.Label);
832 else if (IsPlusMinusArea (n, x))
833 return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.PlusMinus);
834 else if ((checkboxes || n.StateImage != null) && IsCheckboxArea (n, x))
835 return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.StateImage);
836 else if (x > n.Bounds.Right)
837 return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.RightOfLabel);
838 else if (IsImage (n, x))
839 return new TreeViewHitTestInfo (n, TreeViewHitTestLocations.Image);
840 else
841 return new TreeViewHitTestInfo (null, TreeViewHitTestLocations.Indent);
843 #endif
845 public override string ToString () {
846 int count = Nodes.Count;
847 if (count <= 0)
848 return String.Concat (base.ToString (), ", Nodes.Count: 0");
849 return String.Concat (base.ToString (), ", Nodes.Count: ", count, ", Nodes[0]: ", Nodes [0]);
853 #endregion // Public Instance Methods
855 #region Protected Instance Methods
856 protected override void CreateHandle () {
857 base.CreateHandle ();
858 RecalculateVisibleOrder (root_node);
859 UpdateScrollBars (false);
861 if (pre_selected_node != null)
862 SelectedNode = pre_selected_node;
865 protected override void Dispose (bool disposing) {
866 if (disposing)
867 image_list = null;
869 base.Dispose (disposing);
872 protected OwnerDrawPropertyBag GetItemRenderStyles (TreeNode node, int state) {
873 return node.prop_bag;
876 protected override bool IsInputKey (Keys keyData)
878 if (IsHandleCreated && (keyData & Keys.Alt) == 0) {
879 switch (keyData & Keys.KeyCode) {
880 case Keys.Left:
881 case Keys.Up:
882 case Keys.Right:
883 case Keys.Down:
884 return true;
885 case Keys.Enter:
886 case Keys.Escape:
887 case Keys.Prior:
888 case Keys.Next:
889 case Keys.End:
890 case Keys.Home:
891 if (edit_node != null)
892 return true;
894 break;
897 return base.IsInputKey (keyData);
900 protected override void OnKeyDown (KeyEventArgs e)
902 OpenTreeNodeEnumerator ne;
904 switch (e.KeyData & Keys.KeyCode) {
905 case Keys.Add:
906 if (selected_node != null && selected_node.IsExpanded)
907 selected_node.Expand ();
908 break;
909 case Keys.Subtract:
910 if (selected_node != null && selected_node.IsExpanded)
911 selected_node.Collapse ();
912 break;
913 case Keys.Left:
914 if (selected_node != null) {
915 if (selected_node.IsExpanded && selected_node.Nodes.Count > 0)
916 selected_node.Collapse ();
917 else {
918 TreeNode parent = selected_node.Parent;
919 if (parent != null) {
920 selection_action = TreeViewAction.ByKeyboard;
921 SelectedNode = parent;
925 break;
926 case Keys.Right:
927 if (selected_node != null) {
928 if (!selected_node.IsExpanded)
929 selected_node.Expand ();
930 else {
931 TreeNode child = selected_node.FirstNode;
932 if (child != null)
933 SelectedNode = child;
936 break;
937 case Keys.Up:
938 if (selected_node != null) {
939 ne = new OpenTreeNodeEnumerator (selected_node);
940 if (ne.MovePrevious () && ne.MovePrevious ()) {
941 selection_action = TreeViewAction.ByKeyboard;
942 SelectedNode = ne.CurrentNode;
945 break;
946 case Keys.Down:
947 if (selected_node != null) {
948 ne = new OpenTreeNodeEnumerator (selected_node);
949 if (ne.MoveNext () && ne.MoveNext ()) {
950 selection_action = TreeViewAction.ByKeyboard;
951 SelectedNode = ne.CurrentNode;
954 break;
955 case Keys.Home:
956 if (root_node.Nodes.Count > 0) {
957 ne = new OpenTreeNodeEnumerator (root_node.Nodes [0]);
958 if (ne.MoveNext ()) {
959 selection_action = TreeViewAction.ByKeyboard;
960 SelectedNode = ne.CurrentNode;
963 break;
964 case Keys.End:
965 if (root_node.Nodes.Count > 0) {
966 ne = new OpenTreeNodeEnumerator (root_node.Nodes [0]);
967 while (ne.MoveNext ())
969 selection_action = TreeViewAction.ByKeyboard;
970 SelectedNode = ne.CurrentNode;
972 break;
973 case Keys.PageDown:
974 if (selected_node != null) {
975 ne = new OpenTreeNodeEnumerator (selected_node);
976 int move = VisibleCount;
977 for (int i = 0; i < move && ne.MoveNext (); i++) {
980 selection_action = TreeViewAction.ByKeyboard;
981 SelectedNode = ne.CurrentNode;
983 break;
984 case Keys.PageUp:
985 if (selected_node != null) {
986 ne = new OpenTreeNodeEnumerator (selected_node);
987 int move = VisibleCount;
988 for (int i = 0; i < move && ne.MovePrevious (); i++)
990 selection_action = TreeViewAction.ByKeyboard;
991 SelectedNode = ne.CurrentNode;
993 break;
994 case Keys.Multiply:
995 if (selected_node != null)
996 selected_node.ExpandAll ();
997 break;
999 base.OnKeyDown (e);
1001 if (!e.Handled && checkboxes &&
1002 selected_node != null &&
1003 (e.KeyData & Keys.KeyCode) == Keys.Space) {
1004 selected_node.check_reason = TreeViewAction.ByKeyboard;
1005 selected_node.Checked = !selected_node.Checked;
1006 e.Handled = true;
1010 protected override void OnKeyPress (KeyPressEventArgs e)
1012 base.OnKeyPress (e);
1013 if (e.KeyChar == ' ')
1014 e.Handled = true;
1017 protected override void OnKeyUp (KeyEventArgs e)
1019 base.OnKeyUp (e);
1020 if ((e.KeyData & Keys.KeyCode) == Keys.Space)
1021 e.Handled = true;
1024 #if NET_2_0
1025 protected override void OnMouseHover (EventArgs e)
1027 base.OnMouseHover (e);
1029 is_hovering = true;
1031 TreeNode tn = GetNodeAt (PointToClient (MousePosition));
1033 if (tn != null)
1034 MouseEnteredItem (tn);
1037 protected override void OnMouseLeave (EventArgs e)
1039 base.OnMouseLeave (e);
1041 is_hovering = false;
1043 if (tooltip_currently_showing != null)
1044 MouseLeftItem (tooltip_currently_showing);
1047 protected virtual void OnNodeMouseClick (TreeNodeMouseClickEventArgs e)
1049 TreeNodeMouseClickEventHandler eh = (TreeNodeMouseClickEventHandler)(Events[NodeMouseClickEvent]);
1050 if (eh != null)
1051 eh (this, e);
1054 protected virtual void OnNodeMouseDoubleClick (TreeNodeMouseClickEventArgs e)
1056 TreeNodeMouseClickEventHandler eh = (TreeNodeMouseClickEventHandler)(Events[NodeMouseDoubleClickEvent]);
1057 if (eh != null)
1058 eh (this, e);
1061 protected virtual void OnNodeMouseHover (TreeNodeMouseHoverEventArgs e)
1063 TreeNodeMouseHoverEventHandler eh = (TreeNodeMouseHoverEventHandler)(Events[NodeMouseHoverEvent]);
1064 if (eh != null)
1065 eh (this, e);
1067 #endif
1069 protected virtual void OnItemDrag (ItemDragEventArgs e)
1071 ItemDragEventHandler eh = (ItemDragEventHandler)(Events [ItemDragEvent]);
1072 if (eh != null)
1073 eh (this, e);
1076 #if NET_2_0
1077 protected virtual void OnDrawNode(DrawTreeNodeEventArgs e) {
1078 DrawTreeNodeEventHandler eh = (DrawTreeNodeEventHandler)(Events[DrawNodeEvent]);
1079 if (eh != null)
1080 eh(this, e);
1083 [EditorBrowsable (EditorBrowsableState.Advanced)]
1084 protected virtual void OnRightToLeftLayoutChanged (EventArgs e) {
1085 EventHandler eh = (EventHandler)(Events[RightToLeftLayoutChangedEvent]);
1086 if (eh != null)
1087 eh (this, e);
1089 #endif
1091 protected internal virtual void OnAfterCheck (TreeViewEventArgs e) {
1092 TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterCheckEvent]);
1093 if (eh != null)
1094 eh (this, e);
1097 protected internal virtual void OnAfterCollapse (TreeViewEventArgs e) {
1098 TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterCollapseEvent]);
1099 if (eh != null)
1100 eh (this, e);
1103 protected internal virtual void OnAfterExpand (TreeViewEventArgs e) {
1104 TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterExpandEvent]);
1105 if (eh != null)
1106 eh (this, e);
1109 protected virtual void OnAfterLabelEdit (NodeLabelEditEventArgs e) {
1110 NodeLabelEditEventHandler eh = (NodeLabelEditEventHandler)(Events [AfterLabelEditEvent]);
1111 if (eh != null)
1112 eh (this, e);
1115 protected virtual void OnAfterSelect (TreeViewEventArgs e) {
1116 TreeViewEventHandler eh = (TreeViewEventHandler)(Events [AfterSelectEvent]);
1117 if (eh != null)
1118 eh (this, e);
1121 protected internal virtual void OnBeforeCheck (TreeViewCancelEventArgs e) {
1122 TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeCheckEvent]);
1123 if (eh != null)
1124 eh (this, e);
1127 protected internal virtual void OnBeforeCollapse (TreeViewCancelEventArgs e) {
1128 TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeCollapseEvent]);
1129 if (eh != null)
1130 eh (this, e);
1133 protected internal virtual void OnBeforeExpand (TreeViewCancelEventArgs e) {
1134 TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeExpandEvent]);
1135 if (eh != null)
1136 eh (this, e);
1139 protected virtual void OnBeforeLabelEdit (NodeLabelEditEventArgs e) {
1140 NodeLabelEditEventHandler eh = (NodeLabelEditEventHandler)(Events [BeforeLabelEditEvent]);
1141 if (eh != null)
1142 eh (this, e);
1145 protected virtual void OnBeforeSelect (TreeViewCancelEventArgs e) {
1146 TreeViewCancelEventHandler eh = (TreeViewCancelEventHandler)(Events [BeforeSelectEvent]);
1147 if (eh != null)
1148 eh (this, e);
1151 protected override void OnHandleCreated (EventArgs e) {
1152 base.OnHandleCreated (e);
1155 protected override void OnHandleDestroyed (EventArgs e) {
1156 base.OnHandleDestroyed (e);
1159 protected override void WndProc(ref Message m) {
1160 switch ((Msg) m.Msg) {
1162 case Msg.WM_LBUTTONDBLCLK:
1163 int val = m.LParam.ToInt32();
1164 DoubleClickHandler (null, new
1165 MouseEventArgs (MouseButtons.Left,
1166 2, val & 0xffff,
1167 (val>>16) & 0xffff, 0));
1168 break;
1169 #if NET_2_0
1170 case Msg.WM_CONTEXTMENU:
1171 if (WmContextMenu (ref m))
1172 return;
1174 break;
1175 #endif
1177 base.WndProc (ref m);
1180 #endregion // Protected Instance Methods
1182 #region Internal & Private Methods and Properties
1183 internal override bool ScaleChildrenInternal {
1184 get { return false; }
1187 internal IntPtr CreateNodeHandle ()
1189 return (IntPtr) handle_count++;
1192 // According to MSDN docs, for these to be raised,
1193 // the click must occur over a TreeNode
1194 internal override void HandleClick (int clicks, MouseEventArgs me)
1196 if (GetNodeAt (me.Location) != null) {
1197 if ((clicks > 1) && GetStyle (ControlStyles.StandardDoubleClick)) {
1198 #if !NET_2_0
1199 OnDoubleClick(EventArgs.Empty);
1200 } else {
1201 OnClick(EventArgs.Empty);
1202 #else
1203 OnDoubleClick (me);
1204 OnMouseDoubleClick (me);
1205 } else {
1206 OnClick (me);
1207 OnMouseClick (me);
1208 #endif
1213 internal override bool IsInputCharInternal (char charCode)
1215 return true;
1218 internal TreeNode NodeFromHandle (IntPtr handle)
1220 // This method is called rarely, so instead of maintaining a table
1221 // we just walk the tree nodes to find the matching handle
1222 return NodeFromHandleRecursive (root_node, handle);
1225 private TreeNode NodeFromHandleRecursive (TreeNode node, IntPtr handle)
1227 if (node.handle == handle)
1228 return node;
1229 foreach (TreeNode child in node.Nodes) {
1230 TreeNode match = NodeFromHandleRecursive (child, handle);
1231 if (match != null)
1232 return match;
1234 return null;
1237 internal Rectangle ViewportRectangle {
1238 get {
1239 Rectangle res = ClientRectangle;
1241 if (vbar != null && vbar.Visible)
1242 res.Width -= vbar.Width;
1243 if (hbar != null && hbar.Visible)
1244 res.Height -= hbar.Height;
1245 return res;
1249 private TreeNode GetNodeAt (int y)
1251 if (nodes.Count <= 0)
1252 return null;
1254 OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (TopNode);
1255 int move = y / ActualItemHeight;
1256 for (int i = -1; i < move; i++) {
1257 if (!o.MoveNext ())
1258 return null;
1261 return o.CurrentNode;
1264 private bool IsTextArea (TreeNode node, int x)
1266 return node != null && node.Bounds.Left <= x && node.Bounds.Right >= x;
1269 private bool IsSelectableArea (TreeNode node, int x)
1271 if (node == null)
1272 return false;
1273 int l = node.Bounds.Left;
1274 if (ImageList != null)
1275 l -= ImageList.ImageSize.Width;
1276 return l <= x && node.Bounds.Right >= x;
1280 private bool IsPlusMinusArea (TreeNode node, int x)
1282 if (node.Nodes.Count == 0 || (node.parent == root_node && !show_root_lines))
1283 return false;
1285 int l = node.Bounds.Left + 5;
1287 if (show_root_lines || node.Parent != null)
1288 l -= indent;
1289 if (ImageList != null)
1290 l -= ImageList.ImageSize.Width + 3;
1291 if (checkboxes)
1292 l -= 19;
1293 #if NET_2_0
1294 // StateImage is basically a custom checkbox
1295 else if (node.StateImage != null)
1296 l -= 19;
1297 #endif
1298 return (x > l && x < l + 8);
1301 private bool IsCheckboxArea (TreeNode node, int x)
1303 int l = CheckBoxLeft (node);
1304 return (x > l && x < l + 10);
1307 #if NET_2_0
1308 private bool IsImage (TreeNode node, int x)
1310 if (ImageList == null)
1311 return false;
1313 int l = node.Bounds.Left;
1315 l -= ImageList.ImageSize.Width + 5;
1317 if (x >= l && x <= (l + ImageList.ImageSize.Width + 5))
1318 return true;
1320 return false;
1322 #endif
1324 private int CheckBoxLeft (TreeNode node)
1326 int l = node.Bounds.Left + 5;
1328 if (show_root_lines || node.Parent != null)
1329 l -= indent;
1331 if (!show_root_lines && node.Parent == null)
1332 l -= indent;
1334 if (ImageList != null)
1335 l -= ImageList.ImageSize.Width + 3;
1337 return l;
1340 internal void RecalculateVisibleOrder (TreeNode start)
1342 if (update_stack > 0)
1343 return;
1345 int order;
1346 if (start == null) {
1347 start = root_node;
1348 order = 0;
1349 } else
1350 order = start.visible_order;
1354 OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (start);
1355 while (walk.MoveNext ()) {
1356 walk.CurrentNode.visible_order = order;
1357 order++;
1360 max_visible_order = order;
1363 internal void SetTop (TreeNode node)
1365 int order = 0;
1366 if (node != null)
1367 order = Math.Max (0, node.visible_order - 1);
1369 if (!vbar.is_visible) {
1370 skipped_nodes = order;
1371 return;
1374 vbar.Value = Math.Min (order, vbar.Maximum - VisibleCount + 1);
1377 internal void SetBottom (TreeNode node)
1379 if (!vbar.is_visible)
1380 return;
1382 OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (node);
1384 int bottom = ViewportRectangle.Bottom;
1385 int offset = 0;
1386 while (walk.MovePrevious ()) {
1387 if (walk.CurrentNode.Bounds.Bottom <= bottom)
1388 break;
1389 offset++;
1392 int nv = vbar.Value + offset;
1393 if (vbar.Value + offset < vbar.Maximum) {
1394 vbar.Value = nv;
1395 } else {
1396 #if DEBUG
1397 Console.Error.WriteLine ("setting bottom to value greater then maximum ({0}, {1})",
1398 nv, vbar.Maximum);
1399 #endif
1404 internal void UpdateBelow (TreeNode node)
1406 if (update_stack > 0) {
1407 update_needed = true;
1408 return;
1411 if (node == root_node) {
1412 Invalidate (ViewportRectangle);
1413 return;
1416 // We need to update the current node so the plus/minus block gets update too
1417 int top = Math.Max (node.Bounds.Top - 1, 0);
1418 Rectangle invalid = new Rectangle (0, top,
1419 Width, Height - top);
1420 Invalidate (invalid);
1423 internal void UpdateNode (TreeNode node)
1425 if (node == null)
1426 return;
1428 if (update_stack > 0) {
1429 update_needed = true;
1430 return;
1433 if (node == root_node) {
1434 Invalidate ();
1435 return;
1438 Rectangle invalid = new Rectangle (0, node.Bounds.Top - 1, Width,
1439 node.Bounds.Height + 1);
1440 Invalidate (invalid);
1443 internal void UpdateNodePlusMinus (TreeNode node)
1445 if (update_stack > 0) {
1446 update_needed = true;
1447 return;
1450 int l = node.Bounds.Left + 5;
1452 if (show_root_lines || node.Parent != null)
1453 l -= indent;
1454 if (ImageList != null)
1455 l -= ImageList.ImageSize.Width + 3;
1456 if (checkboxes)
1457 l -= 19;
1459 Invalidate (new Rectangle (l, node.Bounds.Top, 8, node.Bounds.Height));
1462 internal override void OnPaintInternal (PaintEventArgs pe)
1464 Draw (pe.ClipRectangle, pe.Graphics);
1467 internal void CreateDashPen ()
1469 dash = new Pen (LineColor, 1);
1470 dash.DashStyle = DashStyle.Dot;
1473 private void Draw (Rectangle clip, Graphics dc)
1475 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), clip);
1477 if (dash == null)
1478 CreateDashPen ();
1480 Rectangle viewport = ViewportRectangle;
1481 Rectangle original_clip = clip;
1482 if (clip.Bottom > viewport.Bottom)
1483 clip.Height = viewport.Bottom - clip.Top;
1485 OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (TopNode);
1486 while (walk.MoveNext ()) {
1487 TreeNode current = walk.CurrentNode;
1489 // Haven't gotten to visible nodes yet
1490 if (current.GetY () + ActualItemHeight < clip.Top)
1491 continue;
1493 // Past the visible nodes
1494 if (current.GetY () > clip.Bottom)
1495 break;
1497 DrawTreeNode (current, dc, clip);
1500 if (hbar.Visible && vbar.Visible) {
1501 Rectangle corner = new Rectangle (hbar.Right, vbar.Bottom, vbar.Width, hbar.Height);
1502 if (original_clip.IntersectsWith (corner))
1503 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorControl),
1504 corner);
1508 #if NET_2_0
1509 private void DrawNodeState (TreeNode node, Graphics dc, int x, int y)
1511 if (node.Checked) {
1512 if (StateImageList.Images[1] != null)
1513 dc.DrawImage (StateImageList.Images[1], new Rectangle (x, y, 16, 16));
1514 } else {
1515 if (StateImageList.Images[0] != null)
1516 dc.DrawImage (StateImageList.Images[0], new Rectangle (x, y, 16, 16));
1519 #endif
1521 private void DrawNodeCheckBox (TreeNode node, Graphics dc, int x, int middle)
1523 Pen pen = ThemeEngine.Current.ResPool.GetSizedPen(Color.Black, 2);
1524 dc.DrawRectangle (pen, x + 3, middle - 4, 11, 11);
1526 if (node.Checked) {
1527 Pen check_pen = ThemeEngine.Current.ResPool.GetPen(Color.Black);
1529 int check_size = 5;
1530 int lineWidth = 3;
1532 Rectangle rect = new Rectangle (x + 4, middle - 3, check_size, check_size);
1534 for (int i = 0; i < lineWidth; i++) {
1535 dc.DrawLine (check_pen, rect.Left + 1, rect.Top + lineWidth + i, rect.Left + 3, rect.Top + 5 + i);
1536 dc.DrawLine (check_pen, rect.Left + 3, rect.Top + 5 + i, rect.Left + 7, rect.Top + 1 + i);
1541 private void DrawNodeLines (TreeNode node, Graphics dc, Rectangle clip, Pen dash, int x, int y, int middle)
1543 int ladjust = 9;
1544 int radjust = 0;
1546 if (node.nodes.Count > 0 && show_plus_minus)
1547 ladjust = 13;
1548 if (checkboxes)
1549 radjust = 3;
1551 if (show_root_lines || node.Parent != null)
1552 dc.DrawLine (dash, x - indent + ladjust, middle, x + radjust, middle);
1554 if (node.PrevNode != null || node.Parent != null) {
1555 ladjust = 9;
1556 dc.DrawLine (dash, x - indent + ladjust, node.Bounds.Top,
1557 x - indent + ladjust, middle - (show_plus_minus && node.Nodes.Count > 0 ? 4 : 0));
1560 if (node.NextNode != null) {
1561 ladjust = 9;
1562 dc.DrawLine (dash, x - indent + ladjust, middle + (show_plus_minus && node.Nodes.Count > 0 ? 4 : 0),
1563 x - indent + ladjust, node.Bounds.Bottom);
1567 ladjust = 0;
1568 if (show_plus_minus)
1569 ladjust = 9;
1570 TreeNode parent = node.Parent;
1571 while (parent != null) {
1572 if (parent.NextNode != null) {
1573 int px = parent.GetLinesX () - indent + ladjust;
1574 dc.DrawLine (dash, px, node.Bounds.Top, px, node.Bounds.Bottom);
1576 parent = parent.Parent;
1580 private void DrawNodeImage (TreeNode node, Graphics dc, Rectangle clip, int x, int y)
1582 // Rectangle r = new Rectangle (x, y + 2, ImageList.ImageSize.Width, ImageList.ImageSize.Height);
1584 if (!RectsIntersect (clip, x, y, ImageList.ImageSize.Width, ImageList.ImageSize.Height))
1585 return;
1587 if (ImageList == null)
1588 return;
1590 int use_index = -1;
1592 if (!node.IsSelected) {
1593 if (node.ImageIndex > -1 && node.ImageIndex < ImageList.Images.Count) {
1594 use_index = node.ImageIndex;
1595 } else if (ImageIndex > -1 && ImageIndex < ImageList.Images.Count) {
1596 use_index = ImageIndex;
1598 } else {
1599 if (node.SelectedImageIndex > -1 && node.SelectedImageIndex < ImageList.Images.Count) {
1600 use_index = node.SelectedImageIndex;
1601 } else if (SelectedImageIndex > -1 && SelectedImageIndex < ImageList.Images.Count) {
1602 use_index = SelectedImageIndex;
1606 #if NET_2_0
1608 if (!node.IsSelected) {
1609 if (use_index == -1 && !String.IsNullOrEmpty (node.ImageKey)) {
1610 use_index = image_list.Images.IndexOfKey (node.ImageKey);
1613 if (use_index == -1 && !String.IsNullOrEmpty (ImageKey)) {
1614 use_index = image_list.Images.IndexOfKey (ImageKey);
1616 } else {
1617 if (use_index == -1 && !String.IsNullOrEmpty (node.SelectedImageKey)) {
1618 use_index = image_list.Images.IndexOfKey (node.SelectedImageKey);
1621 if (use_index == -1 && !String.IsNullOrEmpty (SelectedImageKey)) {
1622 use_index = image_list.Images.IndexOfKey (SelectedImageKey);
1625 #endif
1627 if (use_index == -1 && ImageList.Images.Count > 0) {
1628 use_index = 0;
1631 if (use_index != -1) {
1632 ImageList.Draw (dc, x, y, ImageList.ImageSize.Width,
1633 ImageList.ImageSize.Height, use_index);
1637 private void LabelEditFinished (object sender, EventArgs e)
1639 EndEdit (edit_node);
1642 internal void BeginEdit (TreeNode node)
1644 if (edit_node != null)
1645 EndEdit (edit_node);
1647 if (edit_text_box == null) {
1648 edit_text_box = new LabelEditTextBox ();
1649 edit_text_box.BorderStyle = BorderStyle.FixedSingle;
1650 edit_text_box.Visible = false;
1651 edit_text_box.EditingCancelled += new EventHandler (LabelEditCancelled);
1652 edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
1653 edit_text_box.TextChanged += new EventHandler (LabelTextChanged);
1654 Controls.Add (edit_text_box);
1657 node.EnsureVisible ();
1659 edit_text_box.Bounds = node.Bounds;
1660 edit_text_box.Text = node.Text;
1661 edit_text_box.Visible = true;
1662 edit_text_box.Focus ();
1663 edit_text_box.SelectAll ();
1665 edit_args = new NodeLabelEditEventArgs (node);
1666 OnBeforeLabelEdit (edit_args);
1668 edit_node = node;
1670 if (edit_args.CancelEdit) {
1671 edit_node = null;
1672 EndEdit (node);
1676 private void LabelEditCancelled (object sender, EventArgs e)
1678 edit_args.SetLabel (null);
1679 EndEdit (edit_node);
1682 private void LabelTextChanged (object sender, EventArgs e)
1684 int width = TextRenderer.MeasureTextInternal (edit_text_box.Text, edit_text_box.Font, false).Width + 4;
1685 edit_text_box.Width = width;
1687 if (edit_args != null)
1688 edit_args.SetLabel (edit_text_box.Text);
1691 internal void EndEdit (TreeNode node)
1693 if (edit_text_box != null && edit_text_box.Visible) {
1694 edit_text_box.Visible = false;
1695 Focus ();
1699 // If we get a call to BeginEdit from any AfterLabelEdit handler,
1700 // the focus seems to always remain in the TreeView. This call seems
1701 // to synchronize the focus events - I don't like it but it works
1703 Application.DoEvents ();
1705 if (edit_node != null && edit_node == node) {
1706 edit_node = null;
1708 NodeLabelEditEventArgs e = new NodeLabelEditEventArgs (edit_args.Node, edit_args.Label);
1710 OnAfterLabelEdit (e);
1712 if (e.CancelEdit)
1713 return;
1715 if (e.Label != null)
1716 e.Node.Text = e.Label;
1719 // EndEdit ends editing even if not called on the editing node
1720 edit_node = null;
1721 UpdateNode (node);
1724 internal void CancelEdit (TreeNode node)
1726 edit_args.SetLabel (null);
1728 if (edit_text_box != null && edit_text_box.Visible) {
1729 edit_text_box.Visible = false;
1730 Focus ();
1733 edit_node = null;
1734 UpdateNode (node);
1737 internal int GetNodeWidth (TreeNode node)
1739 Font font = node.NodeFont;
1740 if (node.NodeFont == null)
1741 font = Font;
1742 return (int)TextRenderer.MeasureString (node.Text, font, 0, string_format).Width + 3;
1745 private void DrawSelectionAndFocus(TreeNode node, Graphics dc, Rectangle r)
1747 if (Focused && focused_node == node && !full_row_select) {
1748 ControlPaint.DrawFocusRectangle (dc, r, ForeColor, BackColor);
1750 if (draw_mode != TreeViewDrawMode.Normal)
1751 return;
1753 r.Inflate (-1, -1);
1754 if (Focused && node == highlighted_node) {
1755 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight), r);
1756 } else if (!hide_selection && node == highlighted_node) {
1757 dc.FillRectangle (SystemBrushes.Control, r);
1758 } else {
1759 dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (node.BackColor), r);
1763 private void DrawStaticNode (TreeNode node, Graphics dc)
1765 if (!full_row_select || show_lines)
1766 DrawSelectionAndFocus(node, dc, node.Bounds);
1769 Font font = node.NodeFont;
1770 if (node.NodeFont == null)
1771 font = Font;
1772 Color text_color = (Focused && node == highlighted_node ?
1773 ThemeEngine.Current.ColorHighlightText : node.ForeColor);
1774 if (text_color.IsEmpty)
1775 text_color = ForeColor;
1776 dc.DrawString (node.Text, font,
1777 ThemeEngine.Current.ResPool.GetSolidBrush (text_color),
1778 node.Bounds, string_format);
1781 private void DrawTreeNode (TreeNode node, Graphics dc, Rectangle clip)
1783 int child_count = node.nodes.Count;
1784 int y = node.GetY ();
1785 int middle = y + (ActualItemHeight / 2);
1787 if (full_row_select && !show_lines) {
1788 Rectangle r = new Rectangle (1, y, ViewportRectangle.Width - 2, ActualItemHeight);
1789 DrawSelectionAndFocus (node, dc, r);
1792 if (draw_mode == TreeViewDrawMode.Normal || draw_mode == TreeViewDrawMode.OwnerDrawText) {
1793 if ((show_root_lines || node.Parent != null) && show_plus_minus && child_count > 0)
1794 ThemeEngine.Current.TreeViewDrawNodePlusMinus (this, node, dc, node.GetLinesX () - Indent + 5, middle);
1796 #if NET_2_0
1797 if (checkboxes && state_image_list == null)
1798 DrawNodeCheckBox (node, dc, CheckBoxLeft (node) - 3, middle);
1800 if (checkboxes && state_image_list != null)
1801 DrawNodeState (node, dc, CheckBoxLeft (node) - 3, y);
1803 if (!checkboxes && node.StateImage != null)
1804 dc.DrawImage (node.StateImage, new Rectangle (CheckBoxLeft (node) - 3, y, 16, 16));
1805 #else
1806 if (checkboxes)
1807 DrawNodeCheckBox (node, dc, CheckBoxLeft (node) - 3, middle);
1808 #endif
1810 if (show_lines)
1811 DrawNodeLines (node, dc, clip, dash, node.GetLinesX (), y, middle);
1813 if (ImageList != null)
1814 DrawNodeImage (node, dc, clip, node.GetImageX (), y);
1818 #if NET_2_0
1819 if (draw_mode != TreeViewDrawMode.Normal) {
1820 dc.FillRectangle (Brushes.White, node.Bounds);
1821 TreeNodeStates tree_node_state = TreeNodeStates.Default;;
1822 if (node.IsSelected)
1823 tree_node_state = TreeNodeStates.Selected;
1824 if (node.Checked)
1825 tree_node_state |= TreeNodeStates.Checked;
1826 if (node == focused_node)
1827 tree_node_state |= TreeNodeStates.Focused;
1828 Rectangle node_bounds = node.Bounds;
1829 if (draw_mode == TreeViewDrawMode.OwnerDrawText) {
1830 node_bounds.X += 3;
1831 node_bounds.Y += 1;
1832 } else {
1833 node_bounds.X = 0;
1834 node_bounds.Width = Width;
1837 DrawTreeNodeEventArgs e = new DrawTreeNodeEventArgs (dc, node, node_bounds, tree_node_state);
1839 OnDrawNode (e);
1840 if (!e.DrawDefault)
1841 return;
1843 #endif
1845 if (!node.IsEditing)
1846 DrawStaticNode (node, dc);
1849 internal void UpdateScrollBars (bool force)
1851 if (!force && (IsDisposed || update_stack > 0 || !IsHandleCreated || !Visible))
1852 return;
1854 bool vert = false;
1855 bool horz = false;
1856 int height = -1;
1857 int width = -1;
1859 if (scrollable) {
1860 OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (root_node);
1862 while (walk.MoveNext ()) {
1863 int r = walk.CurrentNode.Bounds.Right;
1864 int b = walk.CurrentNode.Bounds.Bottom;
1866 if (r > width)
1867 width = r;
1868 if (b > height)
1869 height = b;
1872 // Remove scroll adjustments
1873 if (nodes.Count > 0)
1874 height -= nodes [0].Bounds.Top;
1875 width += hbar_offset;
1877 if (height > ClientRectangle.Height) {
1878 vert = true;
1880 if (width > ClientRectangle.Width - SystemInformation.VerticalScrollBarWidth)
1881 horz = true;
1882 } else if (width > ClientRectangle.Width) {
1883 horz = true;
1886 if (!vert && horz && height > ClientRectangle.Height - SystemInformation.HorizontalScrollBarHeight)
1887 vert = true;
1890 if (vert) {
1891 int visible_height = horz ? ClientRectangle.Height - hbar.Height : ClientRectangle.Height;
1892 vbar.SetValues (Math.Max (0, max_visible_order - 2), visible_height / ActualItemHeight);
1894 vbar.Maximum = max_visible_order;
1895 vbar.LargeChange = ClientRectangle.Height / ItemHeight;
1898 if (!vbar_bounds_set) {
1899 vbar.Bounds = new Rectangle (ClientRectangle.Width - vbar.Width, 0, vbar.Width,
1900 ClientRectangle.Height -
1901 (horz ? SystemInformation.VerticalScrollBarWidth : 0));
1902 vbar_bounds_set = true;
1904 // We need to recalc the hbar if the vbar is now visible
1905 hbar_bounds_set = false;
1909 vbar.Visible = true;
1910 if (skipped_nodes > 0) {
1911 int skip = Math.Min (skipped_nodes, vbar.Maximum - VisibleCount + 1);
1912 skipped_nodes = 0;
1913 vbar.SafeValueSet (skip);
1914 skipped_nodes = skip;
1916 } else {
1917 skipped_nodes = 0;
1918 RecalculateVisibleOrder (root_node);
1919 vbar.Visible = false;
1920 vbar_bounds_set = false;
1923 if (horz) {
1924 hbar.SetValues (width + 1, ClientRectangle.Width - (vert ? SystemInformation.VerticalScrollBarWidth : 0));
1926 hbar.LargeChange = ClientRectangle.Width;
1927 hbar.Maximum = width + 1;
1930 if (!hbar_bounds_set) {
1931 hbar.Bounds = new Rectangle (0, ClientRectangle.Height - hbar.Height,
1932 ClientRectangle.Width - (vert ? SystemInformation.VerticalScrollBarWidth : 0),
1933 hbar.Height);
1934 hbar_bounds_set = true;
1936 hbar.Visible = true;
1937 } else {
1938 hbar_offset = 0;
1939 hbar.Visible = false;
1940 hbar_bounds_set = false;
1944 private void SizeChangedHandler (object sender, EventArgs e)
1946 if (IsHandleCreated) {
1947 if (max_visible_order == -1)
1948 RecalculateVisibleOrder (root_node);
1949 UpdateScrollBars (false);
1952 if (vbar.Visible) {
1953 vbar.Bounds = new Rectangle (ClientRectangle.Width - vbar.Width, 0, vbar.Width,
1954 ClientRectangle.Height - (hbar.Visible ? SystemInformation.HorizontalScrollBarHeight : 0));
1957 if (hbar.Visible) {
1958 hbar.Bounds = new Rectangle (0, ClientRectangle.Height - hbar.Height,
1959 ClientRectangle.Width - (vbar.Visible ? SystemInformation.VerticalScrollBarWidth : 0), hbar.Height);
1963 private void VScrollBarValueChanged (object sender, EventArgs e)
1965 EndEdit (edit_node);
1967 SetVScrollPos (vbar.Value, null);
1970 private void SetVScrollPos (int pos, TreeNode new_top)
1972 if (pos < 0)
1973 pos = 0;
1975 if (skipped_nodes == pos)
1976 return;
1978 int diff = skipped_nodes - pos;
1979 skipped_nodes = pos;
1981 if (!IsHandleCreated)
1982 return;
1984 int y_move = diff * ActualItemHeight;
1985 XplatUI.ScrollWindow (Handle, ViewportRectangle, 0, y_move, false);
1988 /*private void SetVScrollTop (TreeNode new_top)
1990 vbar.Value = new_top.visible_order - VisibleCount;
1993 private void HScrollBarValueChanged(object sender, EventArgs e)
1995 EndEdit (edit_node);
1997 int old_offset = hbar_offset;
1998 hbar_offset = hbar.Value;
2000 if (hbar_offset < 0) {
2001 hbar_offset = 0;
2004 XplatUI.ScrollWindow (Handle, ViewportRectangle, old_offset - hbar_offset, 0, false);
2007 internal void ExpandBelow (TreeNode node, int count_to_next)
2009 if (update_stack > 0) {
2010 update_needed = true;
2011 return;
2014 // If node Bottom is less than 0, the node is above and not visible,
2015 // and we need to scroll the entire viewport
2016 int node_bottom = node.Bounds.Bottom >= 0 ? node.Bounds.Bottom : 0;
2017 Rectangle below = new Rectangle (0, node_bottom, ViewportRectangle.Width,
2018 ViewportRectangle.Height - node_bottom);
2020 int amount = count_to_next * ActualItemHeight;
2022 if (amount > 0)
2023 XplatUI.ScrollWindow (Handle, below, 0, amount, false);
2025 if (show_plus_minus) {
2026 Invalidate (new Rectangle (0, node.GetY (), Width, ActualItemHeight));
2030 internal void CollapseBelow (TreeNode node, int count_to_next)
2032 if (update_stack > 0) {
2033 update_needed = true;
2034 return;
2037 Rectangle below = new Rectangle (0, node.Bounds.Bottom, ViewportRectangle.Width,
2038 ViewportRectangle.Height - node.Bounds.Bottom);
2040 int amount = count_to_next * ActualItemHeight;
2042 if (amount > 0)
2043 XplatUI.ScrollWindow (Handle, below, 0, -amount, false);
2045 if (show_plus_minus) {
2046 Invalidate (new Rectangle (0, node.GetY (), Width, ActualItemHeight));
2050 private void MouseWheelHandler(object sender, MouseEventArgs e) {
2052 if (vbar == null || !vbar.is_visible) {
2053 return;
2056 if (e.Delta < 0) {
2057 vbar.Value = Math.Min(vbar.Value + SystemInformation.MouseWheelScrollLines, vbar.Maximum - VisibleCount + 1);
2058 } else {
2059 vbar.Value = Math.Max(0, vbar.Value - SystemInformation.MouseWheelScrollLines);
2063 private void VisibleChangedHandler (object sender, EventArgs e)
2065 if (Visible) {
2066 UpdateScrollBars (false);
2070 private void FontChangedHandler (object sender, EventArgs e)
2072 if (IsHandleCreated) {
2073 TreeNode top = TopNode;
2074 InvalidateNodeWidthRecursive (root_node);
2076 SetTop (top);
2080 private void InvalidateNodeWidthRecursive (TreeNode node)
2082 node.InvalidateWidth ();
2083 foreach (TreeNode child in node.Nodes) {
2084 InvalidateNodeWidthRecursive (child);
2088 private void GotFocusHandler (object sender, EventArgs e)
2090 if (selected_node == null) {
2091 if (pre_selected_node != null) {
2092 SelectedNode = pre_selected_node;
2093 return;
2096 SelectedNode = TopNode;
2098 } else if (selected_node != null)
2099 UpdateNode (selected_node);
2102 private void LostFocusHandler (object sender, EventArgs e)
2104 UpdateNode (SelectedNode);
2107 private void MouseDownHandler (object sender, MouseEventArgs e)
2109 if (e.Button == MouseButtons.Right)
2110 Focus ();
2112 TreeNode node = GetNodeAt (e.Y);
2113 if (node == null)
2114 return;
2116 #if NET_2_0
2117 mouse_click_node = node;
2118 #endif
2120 if (show_plus_minus && IsPlusMinusArea (node, e.X) && e.Button == MouseButtons.Left) {
2121 node.Toggle ();
2122 return;
2123 } else if (checkboxes && IsCheckboxArea (node, e.X) && e.Button == MouseButtons.Left) {
2124 node.check_reason = TreeViewAction.ByMouse;
2125 node.Checked = !node.Checked;
2126 UpdateNode(node);
2127 return;
2128 } else if (IsSelectableArea (node, e.X) || full_row_select) {
2129 TreeNode old_highlighted = highlighted_node;
2130 highlighted_node = node;
2131 if (label_edit && e.Clicks == 1 && highlighted_node == old_highlighted && e.Button == MouseButtons.Left) {
2132 BeginEdit (node);
2133 } else if (highlighted_node != focused_node) {
2134 Size ds = SystemInformation.DragSize;
2135 mouse_rect.X = e.X - ds.Width;
2136 mouse_rect.Y = e.Y - ds.Height;
2137 mouse_rect.Width = ds.Width * 2;
2138 mouse_rect.Height = ds.Height * 2;
2140 select_mmove = true;
2143 Invalidate (highlighted_node.Bounds);
2144 if (old_highlighted != null)
2145 Invalidate (Bloat (old_highlighted.Bounds));
2149 private void MouseUpHandler (object sender, MouseEventArgs e) {
2150 #if NET_2_0
2151 TreeNode node = GetNodeAt (e.Y);
2153 if (node != null && node == mouse_click_node) {
2154 if (e.Clicks == 2)
2155 OnNodeMouseDoubleClick (new TreeNodeMouseClickEventArgs (node, e.Button, e.Clicks, e.X, e.Y));
2156 else
2157 OnNodeMouseClick (new TreeNodeMouseClickEventArgs (node, e.Button, e.Clicks, e.X, e.Y));
2160 mouse_click_node = null;
2161 #endif
2163 drag_begin_x = -1;
2164 drag_begin_y = -1;
2166 if (!select_mmove)
2167 return;
2169 select_mmove = false;
2171 if (e.Button == MouseButtons.Right && selected_node != null) {
2172 Invalidate (highlighted_node.Bounds);
2173 highlighted_node = selected_node;
2174 Invalidate (selected_node.Bounds);
2175 return;
2178 TreeViewCancelEventArgs ce = new TreeViewCancelEventArgs (highlighted_node, false, TreeViewAction.ByMouse);
2179 OnBeforeSelect (ce);
2181 Rectangle invalid;
2182 if (!ce.Cancel) {
2183 TreeNode prev_focused_node = focused_node;
2184 TreeNode prev_highlighted_node = highlighted_node;
2186 selected_node = highlighted_node;
2187 focused_node = highlighted_node;
2188 OnAfterSelect (new TreeViewEventArgs (selected_node, TreeViewAction.ByMouse));
2190 if (prev_focused_node != null) {
2191 invalid = Rectangle.Union (Bloat (prev_focused_node.Bounds),
2192 Bloat (prev_highlighted_node.Bounds));
2193 } else {
2194 invalid = Bloat (prev_highlighted_node.Bounds);
2197 invalid.X = 0;
2198 invalid.Width = ViewportRectangle.Width;
2200 Invalidate (invalid);
2201 } else {
2202 highlighted_node = focused_node;
2203 selected_node = focused_node;
2207 private void MouseMoveHandler (object sender, MouseEventArgs e) {
2208 #if NET_2_0
2209 // XXX - This should use HitTest and only fire when we are over
2210 // the important parts of a node, not things like gridlines or
2211 // whitespace
2212 TreeNode tn = GetNodeAt (e.Location);
2214 if (tn != tooltip_currently_showing)
2215 MouseLeftItem (tooltip_currently_showing);
2217 if (tn != null && tn != tooltip_currently_showing)
2218 MouseEnteredItem (tn);
2219 #endif
2221 if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right) {
2222 if (drag_begin_x == -1 && drag_begin_y == -1) {
2223 drag_begin_x = e.X;
2224 drag_begin_y = e.Y;
2225 } else {
2226 double rise = Math.Pow (drag_begin_x - e.X, 2);
2227 double run = Math.Pow (drag_begin_y - e.Y, 2);
2228 double move = Math.Sqrt (rise + run);
2229 if (move > 3) {
2230 TreeNode drag = GetNodeAtUseX (e.X, e.Y);
2232 if (drag != null) {
2233 OnItemDrag (new ItemDragEventArgs (e.Button, drag));
2235 drag_begin_x = -1;
2236 drag_begin_y = -1;
2242 // If there is enough movement before the mouse comes up,
2243 // selection is reverted back to the originally selected node
2244 if (!select_mmove || mouse_rect.Contains (e.X, e.Y))
2245 return;
2247 Invalidate (highlighted_node.Bounds);
2248 Invalidate (selected_node.Bounds);
2249 Invalidate (focused_node.Bounds);
2251 highlighted_node = selected_node;
2252 focused_node = selected_node;
2254 select_mmove = false;
2257 private void DoubleClickHandler (object sender, MouseEventArgs e) {
2258 TreeNode node = GetNodeAtUseX (e.X,e.Y);
2259 if(node != null) {
2260 node.Toggle();
2265 private bool RectsIntersect (Rectangle r, int left, int top, int width, int height)
2267 return !((r.Left > left + width) || (r.Right < left) ||
2268 (r.Top > top + height) || (r.Bottom < top));
2271 #if NET_2_0
2272 // Return true if message was handled, false to send it to base
2273 private bool WmContextMenu (ref Message m)
2275 Point pt;
2276 TreeNode tn;
2278 pt = new Point (LowOrder ((int)m.LParam.ToInt32 ()), HighOrder ((int)m.LParam.ToInt32 ()));
2280 // This means it's a keyboard menu request
2281 if (pt.X == -1 || pt.Y == -1) {
2282 tn = SelectedNode;
2284 if (tn == null)
2285 return false;
2287 pt = new Point (tn.Bounds.Left, tn.Bounds.Top + (tn.Bounds.Height / 2));
2288 } else {
2289 pt = PointToClient (pt);
2291 tn = GetNodeAt (pt);
2293 if (tn == null)
2294 return false;
2297 // At this point, we have a valid TreeNode
2298 if (tn.ContextMenu != null) {
2299 tn.ContextMenu.Show (this, pt);
2300 return true;
2301 } else if (tn.ContextMenuStrip != null) {
2302 tn.ContextMenuStrip.Show (this, pt);
2303 return true;
2306 // The node we found did not have its own menu, let the parent try to display its menu
2307 return false;
2309 #endif
2311 #region Stuff for ToolTips
2312 #if NET_2_0
2313 private void MouseEnteredItem (TreeNode item)
2315 tooltip_currently_showing = item;
2317 if (!is_hovering)
2318 return;
2320 if (ShowNodeToolTips && !string.IsNullOrEmpty (tooltip_currently_showing.ToolTipText))
2321 ToolTipWindow.Present (this, tooltip_currently_showing.ToolTipText);
2323 OnNodeMouseHover (new TreeNodeMouseHoverEventArgs (tooltip_currently_showing));
2326 private void MouseLeftItem (TreeNode item)
2328 ToolTipWindow.Hide (this);
2329 tooltip_currently_showing = null;
2332 private ToolTip ToolTipWindow {
2333 get {
2334 if (tooltip_window == null)
2335 tooltip_window = new ToolTip ();
2337 return tooltip_window;
2340 #endif
2341 #endregion
2343 #endregion // Internal & Private Methods and Properties
2345 #region Events
2346 static object ItemDragEvent = new object ();
2347 static object AfterCheckEvent = new object ();
2348 static object AfterCollapseEvent = new object ();
2349 static object AfterExpandEvent = new object ();
2350 static object AfterLabelEditEvent = new object ();
2351 static object AfterSelectEvent = new object ();
2352 static object BeforeCheckEvent = new object ();
2353 static object BeforeCollapseEvent = new object ();
2354 static object BeforeExpandEvent = new object ();
2355 static object BeforeLabelEditEvent = new object ();
2356 static object BeforeSelectEvent = new object ();
2357 #if NET_2_0
2358 static object DrawNodeEvent = new object ();
2359 static object NodeMouseClickEvent = new object ();
2360 static object NodeMouseDoubleClickEvent = new object();
2361 static object NodeMouseHoverEvent = new object ();
2362 static object RightToLeftLayoutChangedEvent = new object ();
2363 #endif
2365 public event ItemDragEventHandler ItemDrag {
2366 add { Events.AddHandler (ItemDragEvent, value); }
2367 remove { Events.RemoveHandler (ItemDragEvent, value); }
2370 public event TreeViewEventHandler AfterCheck {
2371 add { Events.AddHandler (AfterCheckEvent, value); }
2372 remove { Events.RemoveHandler (AfterCheckEvent, value); }
2375 public event TreeViewEventHandler AfterCollapse {
2376 add { Events.AddHandler (AfterCollapseEvent, value); }
2377 remove { Events.RemoveHandler (AfterCollapseEvent, value); }
2380 public event TreeViewEventHandler AfterExpand {
2381 add { Events.AddHandler (AfterExpandEvent, value); }
2382 remove { Events.RemoveHandler (AfterExpandEvent, value); }
2385 public event NodeLabelEditEventHandler AfterLabelEdit {
2386 add { Events.AddHandler (AfterLabelEditEvent, value); }
2387 remove { Events.RemoveHandler (AfterLabelEditEvent, value); }
2390 public event TreeViewEventHandler AfterSelect {
2391 add { Events.AddHandler (AfterSelectEvent, value); }
2392 remove { Events.RemoveHandler (AfterSelectEvent, value); }
2395 public event TreeViewCancelEventHandler BeforeCheck {
2396 add { Events.AddHandler (BeforeCheckEvent, value); }
2397 remove { Events.RemoveHandler (BeforeCheckEvent, value); }
2400 public event TreeViewCancelEventHandler BeforeCollapse {
2401 add { Events.AddHandler (BeforeCollapseEvent, value); }
2402 remove { Events.RemoveHandler (BeforeCollapseEvent, value); }
2405 public event TreeViewCancelEventHandler BeforeExpand {
2406 add { Events.AddHandler (BeforeExpandEvent, value); }
2407 remove { Events.RemoveHandler (BeforeExpandEvent, value); }
2410 public event NodeLabelEditEventHandler BeforeLabelEdit {
2411 add { Events.AddHandler (BeforeLabelEditEvent, value); }
2412 remove { Events.RemoveHandler (BeforeLabelEditEvent, value); }
2415 public event TreeViewCancelEventHandler BeforeSelect {
2416 add { Events.AddHandler (BeforeSelectEvent, value); }
2417 remove { Events.RemoveHandler (BeforeSelectEvent, value); }
2420 #if NET_2_0
2421 public event DrawTreeNodeEventHandler DrawNode {
2422 add { Events.AddHandler (DrawNodeEvent, value); }
2423 remove { Events.RemoveHandler (DrawNodeEvent, value); }
2426 public event TreeNodeMouseClickEventHandler NodeMouseClick {
2427 add { Events.AddHandler (NodeMouseClickEvent, value); }
2428 remove { Events.RemoveHandler (NodeMouseClickEvent, value); }
2432 public event TreeNodeMouseClickEventHandler NodeMouseDoubleClick {
2433 add { Events.AddHandler (NodeMouseDoubleClickEvent, value); }
2434 remove { Events.RemoveHandler (NodeMouseDoubleClickEvent, value); }
2437 public event TreeNodeMouseHoverEventHandler NodeMouseHover {
2438 add { Events.AddHandler (NodeMouseHoverEvent, value); }
2439 remove { Events.RemoveHandler (NodeMouseHoverEvent, value); }
2442 public event EventHandler RightToLeftLayoutChanged {
2443 add { Events.AddHandler (RightToLeftLayoutChangedEvent, value); }
2444 remove { Events.RemoveHandler (RightToLeftLayoutChangedEvent, value); }
2446 #endif
2448 [Browsable (false)]
2449 [EditorBrowsable (EditorBrowsableState.Never)]
2450 public new event EventHandler BackgroundImageChanged {
2451 add { base.BackgroundImageChanged += value; }
2452 remove { base.BackgroundImageChanged -= value; }
2455 #if NET_2_0
2456 [Browsable (false)]
2457 [EditorBrowsable (EditorBrowsableState.Never)]
2458 public new event EventHandler BackgroundImageLayoutChanged {
2459 add { base.BackgroundImageLayoutChanged += value; }
2460 remove { base.BackgroundImageLayoutChanged -= value; }
2463 [Browsable (false)]
2464 [EditorBrowsable (EditorBrowsableState.Never)]
2465 public new event EventHandler PaddingChanged {
2466 add { base.PaddingChanged += value; }
2467 remove { base.PaddingChanged -= value; }
2469 #endif
2471 [EditorBrowsable (EditorBrowsableState.Never)]
2472 [Browsable (false)]
2473 public new event PaintEventHandler Paint {
2474 add { base.Paint += value; }
2475 remove { base.Paint -= value; }
2478 [EditorBrowsable (EditorBrowsableState.Never)]
2479 [Browsable (false)]
2480 public new event EventHandler TextChanged {
2481 add { base.TextChanged += value; }
2482 remove { base.TextChanged -= value; }
2484 #endregion // Events