TreeView.cs 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531
  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 ([email protected])
  24. // Kazuki Oikawa ([email protected])
  25. using System;
  26. using System.Collections;
  27. using System.ComponentModel;
  28. using System.ComponentModel.Design;
  29. using System.Drawing;
  30. using System.Drawing.Drawing2D;
  31. using System.Runtime.InteropServices;
  32. namespace System.Windows.Forms {
  33. [DefaultProperty("Nodes")]
  34. [DefaultEvent("AfterSelect")]
  35. [Designer("System.Windows.Forms.Design.TreeViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
  36. public class TreeView : Control {
  37. #region Fields
  38. private string path_separator = "\\";
  39. private int item_height = -1;
  40. private bool sorted;
  41. private TreeNode top_node;
  42. internal TreeNode root_node;
  43. private TreeNodeCollection nodes;
  44. private int total_node_count;
  45. private TreeNode selected_node = null;
  46. private TreeNode focused_node = null;
  47. private bool select_mmove = false;
  48. private ImageList image_list;
  49. private int image_index = -1;
  50. private int selected_image_index = -1;
  51. private bool full_row_select;
  52. private bool hot_tracking;
  53. private int indent = 19;
  54. private TextBox edit_text_box;
  55. private TreeNode edit_node;
  56. private bool checkboxes;
  57. private bool label_edit;
  58. private bool scrollable;
  59. private bool show_lines = true;
  60. private bool show_root_lines = true;
  61. private bool show_plus_minus = true;
  62. private bool hide_selection = true;
  63. private bool add_hscroll;
  64. private bool add_vscroll;
  65. private int max_node_width;
  66. private VScrollBar vbar;
  67. private int skipped_nodes;
  68. private HScrollBar hbar;
  69. private int hbar_offset;
  70. private int used_height;
  71. private bool update_node_bounds;
  72. private int update_stack;
  73. private bool update_needed;
  74. private TreeViewEventHandler on_after_check;
  75. private TreeViewEventHandler on_after_collapse;
  76. private TreeViewEventHandler on_after_expand;
  77. private NodeLabelEditEventHandler on_after_label_edit;
  78. private TreeViewEventHandler on_after_select;
  79. private TreeViewCancelEventHandler on_before_check;
  80. private TreeViewCancelEventHandler on_before_collapse;
  81. private TreeViewCancelEventHandler on_before_expand;
  82. private NodeLabelEditEventHandler on_before_label_edit;
  83. private TreeViewCancelEventHandler on_before_select;
  84. private Pen dash;
  85. private StringFormat string_format;
  86. private int open_node_count = -1;
  87. private int drag_begin_x = 0;
  88. private int drag_begin_y = 0;
  89. private long handle_count = 1;
  90. #endregion // Fields
  91. #region Public Constructors
  92. public TreeView ()
  93. {
  94. base.background_color = ThemeEngine.Current.ColorWindow;
  95. base.foreground_color = ThemeEngine.Current.ColorWindowText;
  96. root_node = new TreeNode (this);
  97. root_node.Text = "ROOT NODE";
  98. nodes = new TreeNodeCollection (root_node);
  99. root_node.SetNodes (nodes);
  100. MouseDown += new MouseEventHandler (MouseDownHandler);
  101. MouseUp += new MouseEventHandler(MouseUpHandler);
  102. MouseMove += new MouseEventHandler(MouseMoveHandler);
  103. SizeChanged += new EventHandler (SizeChangedHandler);
  104. FontChanged += new EventHandler (FontChangedHandler);
  105. LostFocus += new EventHandler (LostFocusHandler);
  106. SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick, false);
  107. dash = new Pen (SystemColors.ControlLight, 1);
  108. dash.DashStyle = DashStyle.Dash;
  109. string_format = new StringFormat ();
  110. string_format.LineAlignment = StringAlignment.Center;
  111. string_format.Alignment = StringAlignment.Center;
  112. }
  113. #endregion // Public Constructors
  114. #region Public Instance Properties
  115. public override Color BackColor {
  116. get { return base.BackColor;}
  117. set { base.BackColor = value; }
  118. }
  119. [Browsable(false)]
  120. [EditorBrowsable(EditorBrowsableState.Never)]
  121. public override Image BackgroundImage {
  122. get { return base.BackgroundImage; }
  123. set { base.BackgroundImage = value; }
  124. }
  125. [DefaultValue(BorderStyle.Fixed3D)]
  126. [DispId(-504)]
  127. public BorderStyle BorderStyle {
  128. get { return InternalBorderStyle; }
  129. set { InternalBorderStyle = value; }
  130. }
  131. [DefaultValue(false)]
  132. public bool CheckBoxes {
  133. get { return checkboxes; }
  134. set {
  135. if (value == checkboxes)
  136. return;
  137. checkboxes = value;
  138. // Match a "bug" in the MS implementation where disabling checkboxes
  139. // collapses the entire tree, but enabling them does not affect the
  140. // state of the tree.
  141. if (!checkboxes)
  142. root_node.CollapseAllUncheck ();
  143. Refresh ();
  144. }
  145. }
  146. public override Color ForeColor {
  147. get { return base.ForeColor; }
  148. set { base.ForeColor = value; }
  149. }
  150. [DefaultValue(false)]
  151. public bool FullRowSelect {
  152. get { return full_row_select; }
  153. set {
  154. if (value == full_row_select)
  155. return;
  156. full_row_select = value;
  157. Refresh ();
  158. }
  159. }
  160. [DefaultValue(true)]
  161. public bool HideSelection {
  162. get { return hide_selection; }
  163. set {
  164. if (hide_selection == value)
  165. return;
  166. hide_selection = value;
  167. this.Refresh ();
  168. }
  169. }
  170. [DefaultValue(false)]
  171. public bool HotTracking {
  172. get { return hot_tracking; }
  173. set { hot_tracking = value; }
  174. }
  175. [DefaultValue(0)]
  176. [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
  177. [Localizable(true)]
  178. [TypeConverter(typeof(TreeViewImageIndexConverter))]
  179. public int ImageIndex {
  180. get { return image_index; }
  181. set {
  182. if (value < -1) {
  183. throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
  184. "'value' must be greater than or equal to 0.");
  185. }
  186. if (image_index == value)
  187. return;
  188. image_index = value;
  189. Refresh ();
  190. }
  191. }
  192. [DefaultValue(null)]
  193. public ImageList ImageList {
  194. get { return image_list; }
  195. set {
  196. image_list = value;
  197. Refresh ();
  198. }
  199. }
  200. [Localizable(true)]
  201. public int Indent {
  202. get { return indent; }
  203. set {
  204. if (indent == value)
  205. return;
  206. if (value > 32000) {
  207. throw new ArgumentException ("'" + value + "' is not a valid value for 'Indent'. " +
  208. "'Indent' must be less than or equal to 32000");
  209. }
  210. if (value < 0) {
  211. throw new ArgumentException ("'" + value + "' is not a valid value for 'Indent'. " +
  212. "'Indent' must be greater than or equal to 0.");
  213. }
  214. indent = value;
  215. Refresh ();
  216. }
  217. }
  218. [Localizable(true)]
  219. public int ItemHeight {
  220. get {
  221. if (item_height == -1)
  222. return FontHeight + 3;
  223. return item_height;
  224. }
  225. set {
  226. if (value == item_height)
  227. return;
  228. item_height = value;
  229. Refresh ();
  230. }
  231. }
  232. [DefaultValue(false)]
  233. public bool LabelEdit {
  234. get { return label_edit; }
  235. set { label_edit = value; }
  236. }
  237. [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
  238. [MergableProperty(false)]
  239. [Localizable(true)]
  240. public TreeNodeCollection Nodes {
  241. get { return nodes; }
  242. }
  243. [DefaultValue("\\")]
  244. public string PathSeparator {
  245. get { return path_separator; }
  246. set { path_separator = value; }
  247. }
  248. [DefaultValue(true)]
  249. public bool Scrollable {
  250. get { return scrollable; }
  251. set {
  252. if (scrollable == value)
  253. return;
  254. scrollable = value;
  255. }
  256. }
  257. [Editor("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
  258. [TypeConverter(typeof(TreeViewImageIndexConverter))]
  259. [Localizable(true)]
  260. [DefaultValue(0)]
  261. public int SelectedImageIndex {
  262. get { return selected_image_index; }
  263. set {
  264. if (value < -1) {
  265. throw new ArgumentException ("'" + value + "' is not a valid value for 'value'. " +
  266. "'value' must be greater than or equal to 0.");
  267. }
  268. }
  269. }
  270. [Browsable(false)]
  271. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  272. public TreeNode SelectedNode {
  273. get { return selected_node; }
  274. set {
  275. if (selected_node == value)
  276. return;
  277. TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (value, false, TreeViewAction.Unknown);
  278. OnBeforeSelect (e);
  279. if (e.Cancel)
  280. return;
  281. Rectangle invalid = Rectangle.Empty;
  282. if (selected_node != null) {
  283. invalid = Bloat (selected_node.Bounds);
  284. }
  285. if (focused_node != null) {
  286. invalid = Rectangle.Union (invalid,
  287. Bloat (focused_node.Bounds));
  288. }
  289. invalid = Rectangle.Union (invalid, Bloat (value.Bounds));
  290. selected_node = value;
  291. focused_node = value;
  292. if (full_row_select) {
  293. invalid.X = 0;
  294. invalid.Width = ViewportRectangle.Width;
  295. }
  296. Invalidate (invalid);
  297. // We ensure its visible after we update because
  298. // scrolling is used for insure visible
  299. selected_node.EnsureVisible ();
  300. OnAfterSelect (new TreeViewEventArgs (value, TreeViewAction.Unknown));
  301. }
  302. }
  303. private Rectangle Bloat (Rectangle rect)
  304. {
  305. rect.Y--;
  306. rect.X--;
  307. rect.Height += 2;
  308. rect.Width += 2;
  309. return rect;
  310. }
  311. [DefaultValue(true)]
  312. public bool ShowLines {
  313. get { return show_lines; }
  314. set {
  315. if (show_lines == value)
  316. return;
  317. show_lines = value;
  318. Refresh ();
  319. }
  320. }
  321. [DefaultValue(true)]
  322. public bool ShowPlusMinus {
  323. get { return show_plus_minus; }
  324. set {
  325. if (show_plus_minus == value)
  326. return;
  327. show_plus_minus = value;
  328. Refresh ();
  329. }
  330. }
  331. [DefaultValue(true)]
  332. public bool ShowRootLines {
  333. get { return show_root_lines; }
  334. set {
  335. if (show_root_lines == value)
  336. return;
  337. show_root_lines = value;
  338. Refresh ();
  339. }
  340. }
  341. [DefaultValue(false)]
  342. public bool Sorted {
  343. get { return sorted; }
  344. set {
  345. if (sorted != value)
  346. sorted = value;
  347. if (sorted) {
  348. Nodes.Sort ();
  349. Refresh ();
  350. }
  351. }
  352. }
  353. [Browsable(false)]
  354. [EditorBrowsable(EditorBrowsableState.Never)]
  355. [Bindable(false)]
  356. public override string Text {
  357. get { return base.Text; }
  358. set { base.Text = value; }
  359. }
  360. [Browsable(false)]
  361. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  362. public TreeNode TopNode {
  363. get { return top_node; }
  364. }
  365. [Browsable(false)]
  366. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  367. public int VisibleCount {
  368. get {
  369. return ClientRectangle.Height / ItemHeight;
  370. }
  371. }
  372. #endregion // Public Instance Properties
  373. #region Protected Instance Properties
  374. protected override CreateParams CreateParams {
  375. get {
  376. CreateParams cp = base.CreateParams;
  377. return cp;
  378. }
  379. }
  380. protected override Size DefaultSize {
  381. get { return new Size (121, 97); }
  382. }
  383. #endregion // Protected Instance Properties
  384. #region Public Instance Methods
  385. public void BeginUpdate () {
  386. update_stack++;
  387. }
  388. public void CollapseAll ()
  389. {
  390. root_node.CollapseAll ();
  391. }
  392. public void EndUpdate ()
  393. {
  394. if (update_stack > 1) {
  395. update_stack--;
  396. } else {
  397. update_stack = 0;
  398. if (update_needed) {
  399. Invalidate (ViewportRectangle);
  400. update_needed = false;
  401. }
  402. }
  403. }
  404. public void ExpandAll () {
  405. root_node.ExpandAll ();
  406. }
  407. public TreeNode GetNodeAt (Point pt) {
  408. return GetNodeAt (pt.X, pt.Y);
  409. }
  410. public TreeNode GetNodeAt (int x, int y) {
  411. TreeNode node = GetNodeAt (y);
  412. if (node == null || !(IsTextArea (node, x) || full_row_select))
  413. return null;
  414. return node;
  415. }
  416. public int GetNodeCount (bool include_subtrees) {
  417. return root_node.GetNodeCount (include_subtrees);
  418. }
  419. public override string ToString () {
  420. int count = Nodes.Count;
  421. if (count <= 0)
  422. return String.Concat (base.ToString (), "Node Count: 0");
  423. return String.Concat (base.ToString (), "Node Count: ", count, " Nodes[0]: ", Nodes [0]);
  424. }
  425. #endregion // Public Instance Methods
  426. #region Protected Instance Methods
  427. protected override void CreateHandle () {
  428. base.CreateHandle ();
  429. }
  430. protected override void Dispose (bool disposing) {
  431. if (disposing)
  432. image_list = null;
  433. base.Dispose (disposing);
  434. }
  435. protected OwnerDrawPropertyBag GetItemRenderStyles (TreeNode node, int state) {
  436. return node.prop_bag;
  437. }
  438. protected override bool IsInputKey (Keys key_data) {
  439. if ((key_data & Keys.Alt) == 0) {
  440. switch (key_data & Keys.KeyCode) {
  441. case Keys.Enter:
  442. case Keys.Escape:
  443. case Keys.Prior:
  444. case Keys.Next:
  445. case Keys.End:
  446. case Keys.Home:
  447. case Keys.Left:
  448. case Keys.Up:
  449. case Keys.Right:
  450. case Keys.Down:
  451. return true;
  452. }
  453. }
  454. return base.IsInputKey (key_data);
  455. }
  456. protected override void OnKeyDown (KeyEventArgs e)
  457. {
  458. OpenTreeNodeEnumerator ne;
  459. switch (e.KeyData & Keys.KeyCode) {
  460. case Keys.Add:
  461. if (selected_node != null && selected_node.IsExpanded)
  462. selected_node.Expand ();
  463. break;
  464. case Keys.Subtract:
  465. if (selected_node != null && selected_node.IsExpanded)
  466. selected_node.Collapse ();
  467. break;
  468. case Keys.Left:
  469. if (selected_node != null) {
  470. if (selected_node.IsExpanded)
  471. selected_node.Collapse ();
  472. else {
  473. ne = new OpenTreeNodeEnumerator (selected_node);
  474. if (ne.MovePrevious () && ne.MovePrevious ())
  475. SelectedNode = ne.CurrentNode;
  476. }
  477. }
  478. break;
  479. case Keys.Right:
  480. if (selected_node != null) {
  481. if (!selected_node.IsExpanded)
  482. selected_node.Expand ();
  483. else {
  484. ne = new OpenTreeNodeEnumerator (selected_node);
  485. if (ne.MoveNext () && ne.MoveNext ())
  486. SelectedNode = ne.CurrentNode;
  487. }
  488. }
  489. break;
  490. case Keys.Up:
  491. if (selected_node != null) {
  492. ne = new OpenTreeNodeEnumerator (selected_node);
  493. if (ne.MovePrevious () && ne.MovePrevious ())
  494. SelectedNode = ne.CurrentNode;
  495. }
  496. break;
  497. case Keys.Down:
  498. if (selected_node != null) {
  499. ne = new OpenTreeNodeEnumerator (selected_node);
  500. if (ne.MoveNext () && ne.MoveNext ())
  501. SelectedNode = ne.CurrentNode;
  502. }
  503. break;
  504. case Keys.Home:
  505. if (root_node.Nodes.Count > 0) {
  506. ne = new OpenTreeNodeEnumerator (root_node.Nodes [0]);
  507. if (ne.MoveNext ())
  508. SelectedNode = ne.CurrentNode;
  509. }
  510. break;
  511. case Keys.End:
  512. if (root_node.Nodes.Count > 0) {
  513. ne = new OpenTreeNodeEnumerator (root_node.Nodes [0]);
  514. while (ne.MoveNext ())
  515. { }
  516. SelectedNode = ne.CurrentNode;
  517. }
  518. break;
  519. case Keys.PageDown:
  520. if (selected_node != null) {
  521. ne = new OpenTreeNodeEnumerator (selected_node);
  522. int move = ViewportRectangle.Height / ItemHeight;
  523. for (int i = 0; i < move && ne.MoveNext (); i++) {
  524. }
  525. SelectedNode = ne.CurrentNode;
  526. }
  527. break;
  528. case Keys.PageUp:
  529. if (selected_node != null) {
  530. ne = new OpenTreeNodeEnumerator (selected_node);
  531. int move = ViewportRectangle.Height / ItemHeight;
  532. for (int i = 0; i < move && ne.MovePrevious (); i++)
  533. { }
  534. SelectedNode = ne.CurrentNode;
  535. }
  536. break;
  537. case Keys.Multiply:
  538. if (selected_node != null)
  539. selected_node.ExpandAll ();
  540. break;
  541. }
  542. base.OnKeyDown (e);
  543. if (!e.Handled && checkboxes &&
  544. selected_node != null &&
  545. (e.KeyData & Keys.KeyCode) == Keys.Space) {
  546. TreeViewCancelEventArgs args = new TreeViewCancelEventArgs (
  547. selected_node, false, TreeViewAction.ByKeyboard);
  548. OnBeforeCheck (args);
  549. if (!args.Cancel) {
  550. selected_node.Checked = !selected_node.Checked;
  551. OnAfterCheck (new TreeViewEventArgs (selected_node, TreeViewAction.ByKeyboard));
  552. }
  553. e.Handled = true;
  554. }
  555. }
  556. protected virtual void OnItemDrag (ItemDragEventArgs e)
  557. {
  558. if (ItemDrag != null)
  559. ItemDrag (this, e);
  560. }
  561. protected virtual void OnAfterCheck (TreeViewEventArgs e) {
  562. if (on_after_check != null)
  563. on_after_check (this, e);
  564. }
  565. protected internal virtual void OnAfterCollapse (TreeViewEventArgs e) {
  566. if (on_after_collapse != null)
  567. on_after_collapse (this, e);
  568. }
  569. protected internal virtual void OnAfterExpand (TreeViewEventArgs e) {
  570. if (on_after_expand != null)
  571. on_after_expand (this, e);
  572. }
  573. protected virtual void OnAfterLabelEdit (NodeLabelEditEventArgs e) {
  574. if (on_after_label_edit != null)
  575. on_after_label_edit (this, e);
  576. }
  577. protected virtual void OnAfterSelect (TreeViewEventArgs e) {
  578. if (on_after_select != null)
  579. on_after_select (this, e);
  580. }
  581. protected virtual void OnBeforeCheck (TreeViewCancelEventArgs e) {
  582. if (on_before_check != null)
  583. on_before_check (this, e);
  584. }
  585. protected internal virtual void OnBeforeCollapse (TreeViewCancelEventArgs e) {
  586. if (on_before_collapse != null)
  587. on_before_collapse (this, e);
  588. }
  589. protected internal virtual void OnBeforeExpand (TreeViewCancelEventArgs e) {
  590. if (on_before_expand != null)
  591. on_before_expand (this, e);
  592. }
  593. protected virtual void OnBeforeLabelEdit (NodeLabelEditEventArgs e) {
  594. if (on_before_label_edit != null)
  595. on_before_label_edit (this, e);
  596. }
  597. protected virtual void OnBeforeSelect (TreeViewCancelEventArgs e) {
  598. if (on_before_select != null)
  599. on_before_select (this, e);
  600. }
  601. protected override void OnHandleCreated (EventArgs e) {
  602. base.OnHandleCreated (e);
  603. vbar = new VScrollBar ();
  604. hbar = new HScrollBar ();
  605. vbar.Visible = false;
  606. hbar.Visible = false;
  607. vbar.ValueChanged += new EventHandler (VScrollBarValueChanged);
  608. hbar.ValueChanged += new EventHandler (HScrollBarValueChanged);
  609. SuspendLayout ();
  610. Controls.AddImplicit (vbar);
  611. Controls.AddImplicit (hbar);
  612. ResumeLayout ();
  613. }
  614. protected override void OnHandleDestroyed (EventArgs e) {
  615. base.OnHandleDestroyed (e);
  616. }
  617. protected override void WndProc(ref Message m) {
  618. switch ((Msg) m.Msg) {
  619. case Msg.WM_PAINT: {
  620. PaintEventArgs paint_event;
  621. paint_event = XplatUI.PaintEventStart (Handle, true);
  622. DoPaint (paint_event);
  623. XplatUI.PaintEventEnd (Handle, true);
  624. return;
  625. }
  626. case Msg.WM_LBUTTONDBLCLK:
  627. int val = m.LParam.ToInt32();
  628. DoubleClickHandler (null, new
  629. MouseEventArgs (MouseButtons.Left,
  630. 2, val & 0xffff,
  631. (val>>16) & 0xffff, 0));
  632. break;
  633. }
  634. base.WndProc (ref m);
  635. }
  636. #endregion // Protected Instance Methods
  637. #region Internal & Private Methods and Properties
  638. internal string LabelEditText {
  639. get {
  640. if (edit_text_box == null)
  641. return String.Empty;
  642. return edit_text_box.Text;
  643. }
  644. }
  645. internal IntPtr CreateNodeHandle ()
  646. {
  647. return (IntPtr) handle_count++;
  648. }
  649. internal TreeNode NodeFromHandle (IntPtr handle)
  650. {
  651. // This method is called rarely, so instead of maintaining a table
  652. // we just walk the tree nodes to find the matching handle
  653. return NodeFromHandleRecursive (root_node, handle);
  654. }
  655. private TreeNode NodeFromHandleRecursive (TreeNode node, IntPtr handle)
  656. {
  657. if (node.handle == handle)
  658. return node;
  659. foreach (TreeNode child in node.Nodes) {
  660. TreeNode match = NodeFromHandleRecursive (child, handle);
  661. if (match != null)
  662. return match;
  663. }
  664. return null;
  665. }
  666. // TODO: we shouldn't have to compute this on the fly
  667. internal Rectangle ViewportRectangle {
  668. get {
  669. Rectangle res = ClientRectangle;
  670. if (vbar != null && vbar.Visible)
  671. res.Width -= vbar.Width;
  672. if (hbar != null && hbar.Visible)
  673. res.Height -= hbar.Height;
  674. return res;
  675. }
  676. }
  677. [MonoTODO ("Need to know if we are editing, not if editing is enabled")]
  678. private TreeNode GetNodeAt (int y)
  679. {
  680. if (nodes.Count <= 0)
  681. return null;
  682. if (top_node == null)
  683. top_node = nodes [0];
  684. OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (TopNode);
  685. int move = y / ItemHeight;
  686. for (int i = -1; i < move; i++) {
  687. if (!o.MoveNext ())
  688. return null;
  689. }
  690. return o.CurrentNode;
  691. }
  692. private bool IsTextArea (TreeNode node, int x) {
  693. return node != null && node.Bounds.Left <= x && node.Bounds.Right >= x;
  694. }
  695. private bool IsPlusMinusArea (TreeNode node, int x)
  696. {
  697. if (node.Nodes.Count == 0 || (node.parent == root_node && !show_root_lines))
  698. return false;
  699. int l = node.Bounds.Left + 5;
  700. if (show_root_lines || node.Parent != null)
  701. l -= indent;
  702. if (ImageList != null)
  703. l -= ImageList.ImageSize.Width + 3;
  704. if (checkboxes)
  705. l -= 19;
  706. return (x > l && x < l + 8);
  707. }
  708. private bool IsCheckboxArea (TreeNode node, int x)
  709. {
  710. int l = node.Bounds.Left + 5;
  711. if (show_root_lines || node.Parent != null)
  712. l -= indent;
  713. if (ImageList != null)
  714. l -= ImageList.ImageSize.Width + 3;
  715. return (x > l && x < l + 10);
  716. }
  717. internal void SetTop (TreeNode node)
  718. {
  719. OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (root_node);
  720. int offset = 0;
  721. while (walk.CurrentNode != node && walk.MoveNext ())
  722. offset++;
  723. vbar.Value = offset;
  724. }
  725. internal void SetBottom (TreeNode node)
  726. {
  727. OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (node);
  728. int bottom = ViewportRectangle.Bottom;
  729. int offset = 0;
  730. while (walk.MovePrevious ()) {
  731. if (walk.CurrentNode.Bounds.Bottom <= bottom)
  732. break;
  733. offset++;
  734. }
  735. vbar.Value += offset;
  736. }
  737. internal void UpdateBelow (TreeNode node)
  738. {
  739. if (update_stack > 0) {
  740. update_needed = true;
  741. return;
  742. }
  743. if (node == root_node) {
  744. Refresh ();
  745. return;
  746. }
  747. // We need to update the current node so the plus/minus block gets update too
  748. Rectangle invalid = new Rectangle (0, node.Bounds.Top - 1,
  749. Width, Height - node.Bounds.Top + 1);
  750. Invalidate (invalid);
  751. }
  752. internal void UpdateNode (TreeNode node)
  753. {
  754. if (update_stack > 0) {
  755. update_needed = true;
  756. return;
  757. }
  758. if (node == root_node) {
  759. Refresh ();
  760. return;
  761. }
  762. Rectangle invalid = new Rectangle (0, node.Bounds.Top - 1, Width,
  763. node.Bounds.Height + 1);
  764. Invalidate (invalid);
  765. }
  766. internal void UpdateNodePlusMinus (TreeNode node)
  767. {
  768. if (update_stack > 0) {
  769. update_needed = true;
  770. return;
  771. }
  772. int l = node.Bounds.Left + 5;
  773. if (show_root_lines || node.Parent != null)
  774. l -= indent;
  775. if (ImageList != null)
  776. l -= ImageList.ImageSize.Width + 3;
  777. if (checkboxes)
  778. l -= 19;
  779. Invalidate (new Rectangle (l, node.Bounds.Top, 8, node.Bounds.Height));
  780. }
  781. private void DoPaint (PaintEventArgs pe)
  782. {
  783. if (Width <= 0 || Height <= 0 || Visible == false)
  784. return;
  785. Draw (pe.ClipRectangle, pe.Graphics);
  786. }
  787. private void Draw (Rectangle clip, Graphics dc)
  788. {
  789. if (top_node == null && Nodes.Count > 0)
  790. top_node = nodes [0];
  791. // Decide if we need a scrollbar
  792. int old_open_node_count = open_node_count;
  793. //Rectangle fill = ClientRectangle;
  794. add_vscroll = false;
  795. add_hscroll = false;
  796. dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), clip);
  797. Color dash_color = ControlPaint.Dark (BackColor);
  798. if (dash_color == BackColor)
  799. dash_color = ControlPaint.Light (BackColor);
  800. dash = new Pen (dash_color, 1);
  801. dash.DashStyle = DashStyle.Dash;
  802. int depth = 0;
  803. int item_height = ItemHeight;
  804. int height = ClientRectangle.Height;
  805. open_node_count = 0;
  806. used_height = 0;
  807. foreach (TreeNode node in nodes) {
  808. DrawNode (node, dc, clip, ref depth, item_height, height);
  809. depth = 0;
  810. }
  811. add_vscroll = (open_node_count * ItemHeight) > ClientRectangle.Height;
  812. if (max_node_width > ClientRectangle.Width)
  813. add_hscroll = true;
  814. if (add_vscroll)
  815. add_hscroll = max_node_width > ClientRectangle.Width - ThemeEngine.Current.VScrollBarDefaultSize.Width;
  816. if (add_hscroll)
  817. add_vscroll = (open_node_count * ItemHeight) > ClientRectangle.Height - ThemeEngine.Current.HScrollBarDefaultSize.Height;
  818. if (add_hscroll) {
  819. AddHorizontalScrollBar ();
  820. } else if (hbar != null) {
  821. hbar_offset = 0;
  822. hbar.Visible = false;
  823. }
  824. if (add_vscroll) {
  825. AddVerticalScrollBar (open_node_count, old_open_node_count != open_node_count);
  826. } else if (vbar != null) {
  827. vbar.Visible = false;
  828. skipped_nodes = 0;
  829. }
  830. if (add_hscroll && add_vscroll) {
  831. Rectangle corner = new Rectangle (hbar.Right, vbar.Bottom, vbar.Width, hbar.Height);
  832. if (clip.IntersectsWith (corner))
  833. dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorControl), corner);
  834. }
  835. }
  836. private void DrawNodePlusMinus (TreeNode node, Graphics dc, int x, int middle)
  837. {
  838. dc.DrawRectangle (SystemPens.ControlDark, x, middle - 4, 8, 8);
  839. if (node.IsExpanded) {
  840. dc.DrawLine (SystemPens.ControlDarkDark, x + 2, middle, x + 6, middle);
  841. } else {
  842. dc.DrawLine (SystemPens.ControlDarkDark, x + 2, middle, x + 6, middle);
  843. dc.DrawLine (SystemPens.ControlDarkDark, x + 4, middle - 2, x + 4, middle + 2);
  844. }
  845. }
  846. private void DrawNodeCheckBox (TreeNode node, Graphics dc, int x, int middle)
  847. {
  848. using(Pen pen = new Pen (Color.Black, 2) )
  849. dc.DrawRectangle (pen, x+ 3, middle - 4, 11, 11);
  850. if (node.Checked) {
  851. using(Pen check_pen = new Pen (Color.Black, 1)) {
  852. dc.DrawLine (check_pen, x + 6, middle + 0, x + 8, middle + 3);
  853. dc.DrawLine (check_pen, x + 6, middle + 1, x + 8, middle + 4);
  854. dc.DrawLine (check_pen, x + 7, middle + 3, x + 13, middle - 2);
  855. dc.DrawLine (check_pen, x + 7, middle + 4, x + 13, middle - 1);
  856. }
  857. }
  858. }
  859. private void DrawNodeLines (TreeNode node, Graphics dc, bool visible, Pen dash, int x, int y,
  860. int middle, int item_height, int node_count)
  861. {
  862. int ladjust = 9; // left adjust
  863. int radjust = 0; // right adjust
  864. if (node_count > 0 && show_plus_minus)
  865. ladjust = 13;
  866. if (checkboxes)
  867. radjust = 3;
  868. dc.DrawLine (dash, x - indent + ladjust, middle, x + radjust, middle);
  869. //if (!visible)
  870. // return;
  871. int ly = 0;
  872. if (node.PrevNode != null) {
  873. int prevadjust = (node.Nodes.Count > 0 && show_plus_minus ? (node.PrevNode.Nodes.Count == 0 ? 0 : 4) :
  874. (node.PrevNode.Nodes.Count == 0 ? 0 : 4));
  875. int myadjust = (node.Nodes.Count > 0 && show_plus_minus ? 4 : 0);
  876. ly = node.PrevNode.Bounds.Bottom - (item_height / 2) + prevadjust;
  877. dc.DrawLine (dash, x - indent + 9, middle - myadjust, x - indent + 9, ly);
  878. } else if (node.Parent != null) {
  879. int myadjust = (node.Nodes.Count > 0 && show_plus_minus ? 4 : 0);
  880. ly = node.Parent.Bounds.Bottom + 1;
  881. dc.DrawLine (dash, x - indent + 9, middle - myadjust, x - indent + 9, ly);
  882. }
  883. }
  884. private void DrawNodeImage (TreeNode node, Graphics dc, Rectangle clip, int x, int y)
  885. {
  886. // Rectangle r = new Rectangle (x, y + 2, ImageList.ImageSize.Width, ImageList.ImageSize.Height);
  887. if (!RectsIntersect (clip, x, y + 2, ImageList.ImageSize.Width, ImageList.ImageSize.Height))
  888. return;
  889. if (node.ImageIndex > -1 && ImageList != null && node.ImageIndex < ImageList.Images.Count) {
  890. ImageList.Draw (dc, x, y + 2, ImageList.ImageSize.Width,
  891. ImageList.ImageSize.Height, node.ImageIndex);
  892. } else if (ImageIndex > -1 && ImageList != null && ImageIndex < ImageList.Images.Count) {
  893. ImageList.Draw (dc, x, y + 2, ImageList.ImageSize.Width,
  894. ImageList.ImageSize.Height, ImageIndex);
  895. }
  896. }
  897. private void DrawEditNode (TreeNode node)
  898. {
  899. SuspendLayout ();
  900. if (edit_text_box == null) {
  901. edit_text_box = new TextBox ();
  902. edit_text_box.BorderStyle = BorderStyle.FixedSingle;
  903. edit_text_box.KeyUp += new KeyEventHandler (EditTextBoxKeyDown);
  904. edit_text_box.Leave += new EventHandler (EditTextBoxLeave);
  905. Controls.AddImplicit (edit_text_box);
  906. }
  907. edit_text_box.Bounds = node.Bounds;
  908. edit_text_box.Width += 4;
  909. edit_text_box.Text = node.Text;
  910. edit_text_box.Visible = true;
  911. edit_text_box.Focus ();
  912. edit_text_box.SelectAll ();
  913. ResumeLayout ();
  914. }
  915. private void EditTextBoxKeyDown (object sender, KeyEventArgs e)
  916. {
  917. if (e.KeyCode == Keys.Return)
  918. EndEdit ();
  919. }
  920. private void EditTextBoxLeave (object sender, EventArgs e)
  921. {
  922. EndEdit ();
  923. }
  924. private void EndEdit ()
  925. {
  926. edit_text_box.Visible = false;
  927. edit_node.EndEdit (false);
  928. UpdateNode(edit_node);
  929. }
  930. private void UpdateNodeBounds (TreeNode node, int x, int y, int item_height, Graphics dc)
  931. {
  932. Font font = node.NodeFont;
  933. if (node.NodeFont == null)
  934. font = Font;
  935. if (node.NeedsWidth || update_node_bounds)
  936. node.SetWidth ((int) dc.MeasureString (node.Text, font, 0,
  937. string_format).Width + 3);
  938. node.SetHeight (item_height);
  939. node.SetPosition (x, y);
  940. }
  941. private void DrawSelectionAndFocus(TreeNode node, Graphics dc, Rectangle r)
  942. {
  943. if ((!HideSelection || Focused) && SelectedNode == node)
  944. dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight), r);
  945. else
  946. dc.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (node.BackColor), r);
  947. if (Focused && focused_node == node)
  948. ControlPaint.DrawFocusRectangle (dc, r, ForeColor, BackColor);
  949. }
  950. private void DrawStaticNode (TreeNode node, Graphics dc)
  951. {
  952. if (!full_row_select)
  953. DrawSelectionAndFocus(node, dc, node.Bounds);
  954. Font font = node.NodeFont;
  955. if (node.NodeFont == null)
  956. font = Font;
  957. Color text_color = ((Focused || !HideSelection) && SelectedNode == node ?
  958. ThemeEngine.Current.ColorHighlightText : node.ForeColor);
  959. dc.DrawString (node.Text, font,
  960. ThemeEngine.Current.ResPool.GetSolidBrush (text_color),
  961. node.Bounds, string_format);
  962. }
  963. private void DrawNode (TreeNode node, Graphics dc, Rectangle clip, ref int depth, int item_height, int max_height)
  964. {
  965. open_node_count++;
  966. int x = (!show_root_lines && node.Parent != null ? depth - 1 : depth) * indent - hbar_offset;
  967. int y = item_height * (open_node_count - skipped_nodes - 1);
  968. bool visible = (y >= 0 && y < max_height);
  969. int _n_count = node.nodes.Count;
  970. int middle = y + (item_height / 2);
  971. // The thing is totally out of the clipping rectangle
  972. if (clip.Top > y + ItemHeight || clip.Bottom < y)
  973. visible = false;
  974. if (visible && full_row_select) {
  975. Rectangle r = new Rectangle(1, y+2, ViewportRectangle.Width-2, item_height);
  976. DrawSelectionAndFocus(node, dc, r);
  977. }
  978. if (show_root_lines || node.Parent != null) {
  979. x += 5;
  980. if (_n_count > 0) {
  981. if (show_plus_minus && visible) {
  982. DrawNodePlusMinus (node, dc, x, middle);
  983. }
  984. }
  985. x += indent - 5;
  986. }
  987. int ox = x;
  988. if (checkboxes) {
  989. if (visible)
  990. DrawNodeCheckBox (node, dc, ox, middle);
  991. ox += 19;
  992. }
  993. if (show_lines)
  994. DrawNodeLines (node, dc, visible, dash, x, y, middle, item_height, _n_count);
  995. if (ImageList != null) {
  996. if (visible)
  997. DrawNodeImage (node, dc, clip, ox, y);
  998. // MS leaves the space for the image if the ImageList is
  999. // non null regardless of whether or not an image is drawn
  1000. ox += ImageList.ImageSize.Width + 3; // leave a little space so the text isn't against the image
  1001. }
  1002. UpdateNodeBounds (node, ox, y, item_height, dc);
  1003. bool bounds_in_clip = clip.IntersectsWith (node.Bounds) || full_row_select;
  1004. if (visible && bounds_in_clip) {
  1005. if (node.IsEditing)
  1006. DrawEditNode (node);
  1007. else
  1008. DrawStaticNode (node, dc);
  1009. }
  1010. if (node.Bounds.Right > max_node_width) {
  1011. max_node_width = node.Bounds.Right;
  1012. if (max_node_width > ClientRectangle.Width && !add_hscroll) {
  1013. max_height -= ItemHeight;
  1014. add_hscroll = true;
  1015. }
  1016. }
  1017. if (node.Bounds.Bottom > used_height)
  1018. used_height = node.Bounds.Bottom;
  1019. depth++;
  1020. if (node.IsExpanded) {
  1021. for (int i = 0; i < _n_count; i++) {
  1022. int tdepth = depth;
  1023. DrawNode (node.nodes [i], dc, clip, ref tdepth, item_height, max_height);
  1024. }
  1025. }
  1026. }
  1027. private void AddVerticalScrollBar (int total_nodes, bool count_changed)
  1028. {
  1029. vbar.Bounds = new Rectangle (ClientRectangle.Width - vbar.Width,
  1030. 0, vbar.Width, (add_hscroll ? Height - ThemeEngine.Current.HScrollBarDefaultSize.Height : Height));
  1031. if (count_changed) {
  1032. vbar.Maximum = total_nodes;
  1033. int height = ClientRectangle.Height;
  1034. vbar.LargeChange = height / ItemHeight;
  1035. }
  1036. vbar.Visible = true;
  1037. }
  1038. private void AddHorizontalScrollBar ()
  1039. {
  1040. hbar.Bounds = new Rectangle (ClientRectangle.Left,
  1041. ClientRectangle.Bottom - hbar.Height,
  1042. (add_vscroll ? Width - ThemeEngine.Current.VScrollBarDefaultSize.Width : Width), hbar.Height);
  1043. int width = ClientRectangle.Width;
  1044. if (vbar.Visible)
  1045. width -= vbar.Width;
  1046. hbar.SmallChange = 15;
  1047. hbar.LargeChange = 50;
  1048. int num_pixels = max_node_width - width;
  1049. hbar.Maximum = num_pixels + 50;
  1050. hbar.Visible = true;
  1051. }
  1052. private void SizeChangedHandler (object sender, EventArgs e)
  1053. {
  1054. SuspendLayout ();
  1055. if (max_node_width > ClientRectangle.Width && ClientRectangle.Width >= 0) {
  1056. add_hscroll = true;
  1057. AddHorizontalScrollBar ();
  1058. return;
  1059. }
  1060. if (used_height > ClientRectangle.Height && ClientRectangle.Height >= 0) {
  1061. add_vscroll = true;
  1062. AddVerticalScrollBar (open_node_count, true);
  1063. return;
  1064. }
  1065. if (vbar != null && vbar.Visible) {
  1066. int height = (hbar != null && hbar.Visible ? Height - hbar.Height : Height);
  1067. vbar.SetBounds (Right - vbar.Width, 0, 0, height, BoundsSpecified.X | BoundsSpecified.Height);
  1068. }
  1069. if (hbar != null && hbar.Visible) {
  1070. int width = (vbar != null && vbar.Visible ? Width - vbar.Width : Width);
  1071. hbar.SetBounds (0, Bottom - hbar.Height, width, 0, BoundsSpecified.Y | BoundsSpecified.Width);
  1072. }
  1073. ResumeLayout ();
  1074. }
  1075. private void VScrollBarValueChanged (object sender, EventArgs e)
  1076. {
  1077. SetVScrollPos (vbar.Value, null);
  1078. }
  1079. private void SetVScrollPos (int pos, TreeNode new_top)
  1080. {
  1081. if (pos < 0)
  1082. pos = 0;
  1083. if (skipped_nodes == pos)
  1084. return;
  1085. int old_skip = skipped_nodes;
  1086. skipped_nodes = pos;
  1087. int diff = old_skip - skipped_nodes;
  1088. // Determine the new top node if we have to
  1089. if (new_top == null) {
  1090. if (top_node == null)
  1091. top_node = nodes [0];
  1092. OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (TopNode);
  1093. if (diff < 0) {
  1094. for (int i = diff; i <= 0; i++)
  1095. walk.MoveNext ();
  1096. new_top = walk.CurrentNode;
  1097. } else {
  1098. for (int i = 0; i <= diff; i++)
  1099. walk.MovePrevious ();
  1100. new_top = walk.CurrentNode;
  1101. }
  1102. }
  1103. top_node = new_top;
  1104. int y_move = diff * ItemHeight;
  1105. XplatUI.ScrollWindow (Handle, ViewportRectangle, 0, y_move, false);
  1106. }
  1107. private void HScrollBarValueChanged(object sender, EventArgs e)
  1108. {
  1109. int old_offset = hbar_offset;
  1110. hbar_offset = hbar.Value;
  1111. if (hbar_offset < 0)
  1112. hbar_offset = 0;
  1113. XplatUI.ScrollWindow (Handle, ViewportRectangle, old_offset - hbar_offset, 0, false);
  1114. }
  1115. private void FontChangedHandler (object sender, EventArgs e)
  1116. {
  1117. update_node_bounds = true;
  1118. }
  1119. private void LostFocusHandler (object sender, EventArgs e)
  1120. {
  1121. if (selected_node != null)
  1122. UpdateNode (selected_node);
  1123. }
  1124. private void MouseDownHandler (object sender, MouseEventArgs e)
  1125. {
  1126. TreeNode node = GetNodeAt (e.Y);
  1127. if (node == null)
  1128. return;
  1129. if (show_plus_minus && IsPlusMinusArea (node, e.X)) {
  1130. node.Toggle ();
  1131. return;
  1132. } else if (checkboxes && IsCheckboxArea (node, e.X)) {
  1133. node.Checked = !node.Checked;
  1134. UpdateNode(node);
  1135. return;
  1136. } else if (IsTextArea (node, e.X) || full_row_select) {
  1137. TreeNode old_selected = selected_node;
  1138. selected_node = node;
  1139. if (label_edit && e.Clicks == 1 && selected_node == old_selected) {
  1140. node.BeginEdit ();
  1141. if (edit_node != null) {
  1142. edit_node.EndEdit (false);
  1143. UpdateNode (edit_node);
  1144. }
  1145. edit_node = node;
  1146. UpdateNode (edit_node);
  1147. } else if (selected_node != focused_node) {
  1148. select_mmove = true;
  1149. if (old_selected != null) {
  1150. Invalidate (Rectangle.Union (Bloat (old_selected.Bounds),
  1151. Bloat (selected_node.Bounds)));
  1152. } else {
  1153. Invalidate (Bloat (selected_node.Bounds));
  1154. }
  1155. }
  1156. // We ensure its visible after we update because
  1157. // scrolling is used for insure visible
  1158. selected_node.EnsureVisible ();
  1159. }
  1160. }
  1161. private void MouseUpHandler (object sender, MouseEventArgs e) {
  1162. drag_begin_x = -1;
  1163. drag_begin_y = -1;
  1164. if (!select_mmove)
  1165. return;
  1166. select_mmove = false;
  1167. TreeViewCancelEventArgs ce = new TreeViewCancelEventArgs (selected_node, false, TreeViewAction.ByMouse);
  1168. OnBeforeSelect (ce);
  1169. Rectangle invalid;
  1170. if (!ce.Cancel) {
  1171. if (focused_node != null) {
  1172. invalid = Rectangle.Union (Bloat (focused_node.Bounds),
  1173. Bloat (selected_node.Bounds));
  1174. } else {
  1175. invalid = Bloat (selected_node.Bounds);
  1176. }
  1177. focused_node = selected_node;
  1178. OnAfterSelect (new TreeViewEventArgs (selected_node, TreeViewAction.ByMouse));
  1179. Invalidate (invalid);
  1180. } else {
  1181. selected_node = focused_node;
  1182. }
  1183. }
  1184. private void MouseMoveHandler (object sender, MouseEventArgs e) {
  1185. if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right) {
  1186. if (drag_begin_x == -1 && drag_begin_y == -1) {
  1187. drag_begin_x = e.X;
  1188. drag_begin_y = e.Y;
  1189. } else {
  1190. double rise = Math.Pow (drag_begin_x - e.X, 2);
  1191. double run = Math.Pow (drag_begin_y - e.Y, 2);
  1192. double move = Math.Sqrt (rise + run);
  1193. if (move > 3) {
  1194. TreeNode drag = GetNodeAt (e.X, e.Y);
  1195. if (drag != null) {
  1196. OnItemDrag (new ItemDragEventArgs (e.Button, drag));
  1197. }
  1198. drag_begin_x = -1;
  1199. drag_begin_y = -1;
  1200. }
  1201. }
  1202. }
  1203. if(!select_mmove)
  1204. return;
  1205. TreeNode node = GetNodeAt(e.X,e.Y);
  1206. if(node == selected_node)
  1207. return;
  1208. selected_node = focused_node;
  1209. select_mmove = false;
  1210. Refresh();
  1211. }
  1212. private void DoubleClickHandler (object sender, MouseEventArgs e) {
  1213. TreeNode node = GetNodeAt(e.X,e.Y);
  1214. if(node != null) {
  1215. node.Toggle();
  1216. }
  1217. }
  1218. private bool RectsIntersect (Rectangle r, int left, int top, int width, int height)
  1219. {
  1220. return !((r.Left > left + width) || (r.Right < left) ||
  1221. (r.Top > top + height) || (r.Bottom < top));
  1222. }
  1223. #endregion // Internal & Private Methods and Properties
  1224. #region Events
  1225. public event ItemDragEventHandler ItemDrag;
  1226. public event TreeViewEventHandler AfterCheck {
  1227. add { on_after_check += value; }
  1228. remove { on_after_check -= value; }
  1229. }
  1230. public event TreeViewEventHandler AfterCollapse {
  1231. add { on_after_collapse += value; }
  1232. remove { on_after_collapse -= value; }
  1233. }
  1234. public event TreeViewEventHandler AfterExpand {
  1235. add { on_after_expand += value; }
  1236. remove { on_after_expand -= value; }
  1237. }
  1238. public event NodeLabelEditEventHandler AfterLabelEdit {
  1239. add { on_after_label_edit += value; }
  1240. remove { on_after_label_edit -= value; }
  1241. }
  1242. public event TreeViewEventHandler AfterSelect {
  1243. add { on_after_select += value; }
  1244. remove { on_after_select -= value; }
  1245. }
  1246. public event EventHandler BackgroundImageChanged {
  1247. add { base.BackgroundImageChanged += value; }
  1248. remove { base.BackgroundImageChanged -= value; }
  1249. }
  1250. public event TreeViewCancelEventHandler BeforeCheck {
  1251. add { on_before_check += value; }
  1252. remove { on_before_check -= value; }
  1253. }
  1254. public event TreeViewCancelEventHandler BeforeCollapse {
  1255. add { on_before_collapse += value; }
  1256. remove { on_before_collapse -= value; }
  1257. }
  1258. public event TreeViewCancelEventHandler BeforeExpand {
  1259. add { on_before_expand += value; }
  1260. remove { on_before_expand -= value; }
  1261. }
  1262. public event NodeLabelEditEventHandler BeforeLabelEdit {
  1263. add { on_before_label_edit += value; }
  1264. remove { on_before_label_edit -= value; }
  1265. }
  1266. public event TreeViewCancelEventHandler BeforeSelect {
  1267. add { on_before_select += value; }
  1268. remove { on_before_select -= value; }
  1269. }
  1270. [EditorBrowsable (EditorBrowsableState.Never)]
  1271. [Browsable (false)]
  1272. public new event PaintEventHandler Paint {
  1273. add { base.Paint += value; }
  1274. remove { base.Paint -= value; }
  1275. }
  1276. [EditorBrowsable (EditorBrowsableState.Never)]
  1277. [Browsable (false)]
  1278. public new event EventHandler TextChanged {
  1279. add { base.TextChanged += value; }
  1280. remove { base.TextChanged -= value; }
  1281. }
  1282. #endregion // Events
  1283. }
  1284. }