1 // Written by Christopher E. Miller 2 // See the included license.txt for copyright and license details. 3 4 5 /// 6 module dfl.treeview; 7 8 private import dfl.internal.dlib; 9 10 private import dfl.control, dfl.application, dfl.base, dfl.internal.winapi; 11 private import dfl.event, dfl.drawing, dfl.collections, dfl.internal.utf; 12 13 version(DFL_NO_IMAGELIST) 14 { 15 } 16 else 17 { 18 private import dfl.imagelist; 19 } 20 21 22 private extern(Windows) void _initTreeview(); 23 24 25 /// 26 enum TreeViewAction: ubyte 27 { 28 UNKNOWN, /// 29 COLLAPSE, /// ditto 30 EXPAND, /// ditto 31 BY_KEYBOARD, /// ditto 32 BY_MOUSE, /// ditto 33 } 34 35 36 /// 37 class TreeViewCancelEventArgs: CancelEventArgs 38 { 39 /// 40 this(TreeNode node, bool cancel, TreeViewAction action) 41 { 42 super(cancel); 43 44 _node = node; 45 _action = action; 46 } 47 48 49 /// 50 final @property TreeViewAction action() // getter 51 { 52 return _action; 53 } 54 55 56 /// 57 final @property TreeNode node() // getter 58 { 59 return _node; 60 } 61 62 63 private: 64 TreeNode _node; 65 TreeViewAction _action; 66 } 67 68 69 /// 70 class TreeViewEventArgs: EventArgs 71 { 72 /// 73 this(TreeNode node, TreeViewAction action) 74 { 75 _node = node; 76 _action = action; 77 } 78 79 /// ditto 80 this(TreeNode node) 81 { 82 _node = node; 83 //_action = TreeViewAction.UNKNOWN; 84 } 85 86 87 /// 88 final @property TreeViewAction action() // getter 89 { 90 return _action; 91 } 92 93 94 /// 95 final @property TreeNode node() // getter 96 { 97 return _node; 98 } 99 100 101 private: 102 TreeNode _node; 103 TreeViewAction _action = TreeViewAction.UNKNOWN; 104 } 105 106 107 /// 108 class NodeLabelEditEventArgs: EventArgs 109 { 110 /// 111 this(TreeNode node, Dstring label) 112 { 113 _node = node; 114 _label = label; 115 } 116 117 /// ditto 118 this(TreeNode node) 119 { 120 _node = node; 121 } 122 123 124 /// 125 final @property TreeNode node() // getter 126 { 127 return _node; 128 } 129 130 131 /// 132 final @property Dstring label() // getter 133 { 134 return _label; 135 } 136 137 138 /// 139 final @property void cancelEdit(bool byes) // setter 140 { 141 _cancel = byes; 142 } 143 144 /// ditto 145 final @property bool cancelEdit() // getter 146 { 147 return _cancel; 148 } 149 150 151 private: 152 TreeNode _node; 153 Dstring _label; 154 bool _cancel = false; 155 } 156 157 158 /// 159 class TreeNode: DObject 160 { 161 /// 162 this(Dstring labelText) 163 { 164 this(); 165 166 ttext = labelText; 167 } 168 169 /// ditto 170 this(Dstring labelText, TreeNode[] children) 171 { 172 this(); 173 174 ttext = labelText; 175 tchildren.addRange(children); 176 } 177 178 /// ditto 179 this() 180 { 181 Application.ppin(cast(void*)this); 182 183 /+ 184 bcolor = Color.empty; 185 fcolor = Color.empty; 186 +/ 187 188 tchildren = new TreeNodeCollection(tview, this); 189 } 190 191 this(Object val) // package 192 { 193 this(getObjectString(val)); 194 } 195 196 197 /+ 198 /// 199 final @property void backColor(Color c) // setter 200 { 201 bcolor = c; 202 } 203 204 /// ditto 205 final @property Color backColor() // getter 206 { 207 return bcolor; 208 } 209 +/ 210 211 212 /// 213 final @property Rect bounds() // getter 214 { 215 Rect result; 216 217 if(created) 218 { 219 RECT rect; 220 *(cast(HTREEITEM*)&rect) = hnode; 221 if(SendMessageA(tview.handle, TVM_GETITEMRECT, FALSE, cast(LPARAM)&rect)) 222 { 223 result = Rect(&rect); 224 } 225 } 226 227 return result; 228 } 229 230 231 /// 232 final @property TreeNode firstNode() // getter 233 { 234 if(tchildren.length) 235 return tchildren._nodes[0]; 236 return null; 237 } 238 239 240 /+ 241 /// 242 final @property void foreColor(Color c) // setter 243 { 244 fcolor = c; 245 } 246 247 /// ditto 248 final @property Color foreColor() // getter 249 { 250 return fcolor; 251 } 252 +/ 253 254 255 /// 256 // Path from the root to this node. 257 final @property Dstring fullPath() // getter 258 { 259 if(!tparent) 260 return ttext; 261 262 // Might want to manually loop through parents and preallocate the whole buffer. 263 assert(tview !is null); 264 dchar sep; 265 sep = tview.pathSeparator; 266 //return std.string.format("%s%s%s", tparent.fullPath, sep, ttext); 267 char[4] ssep; 268 int sseplen = 0; 269 foreach(char ch; (&sep)[0 .. 1]) 270 { 271 ssep[sseplen++] = ch; 272 } 273 //return tparent.fullPath ~ ssep[0 .. sseplen] ~ ttext; 274 return tparent.fullPath ~ cast(Dstring)ssep[0 .. sseplen] ~ ttext; // Needed in D2. 275 } 276 277 278 /// 279 final @property HTREEITEM handle() // getter 280 { 281 return hnode; 282 } 283 284 285 /// 286 // Index of this node in the parent node. 287 final @property int index() // getter 288 { 289 int result = -1; 290 if(tparent) 291 { 292 result = tparent.tchildren.indexOf(this); 293 assert(result != -1); 294 } 295 return result; 296 } 297 298 299 /+ 300 /// 301 final @property bool isEditing() // getter 302 { 303 } 304 +/ 305 306 307 /// 308 final @property bool isExpanded() // getter 309 { 310 return isState(TVIS_EXPANDED); 311 } 312 313 314 /// 315 final @property bool isSelected() // getter 316 { 317 return isState(TVIS_SELECTED); 318 } 319 320 321 /+ 322 /// 323 final @property bool isVisible() // getter 324 { 325 } 326 +/ 327 328 329 /// 330 final @property TreeNode lastNode() // getter 331 { 332 if(tchildren.length) 333 return tchildren._nodes[tchildren.length - 1]; 334 return null; 335 } 336 337 338 /// 339 // Next sibling node. 340 final @property TreeNode nextNode() // getter 341 { 342 if(tparent) 343 { 344 int i; 345 i = tparent.tchildren.indexOf(this); 346 assert(i != -1); 347 348 i++; 349 if(i != tparent.tchildren.length) 350 return tparent.tchildren._nodes[i]; 351 } 352 return null; 353 } 354 355 356 /+ 357 /// 358 final @property void nodeFont(Font f) // setter 359 { 360 tfont = f; 361 } 362 363 /// ditto 364 final @property Font nodeFont() // getter 365 { 366 return tfont; 367 } 368 +/ 369 370 371 /// 372 final @property TreeNodeCollection nodes() // getter 373 { 374 return tchildren; 375 } 376 377 378 /// 379 final @property TreeNode parent() // getter 380 { 381 return tparent; 382 } 383 384 385 /// 386 // Previous sibling node. 387 final @property TreeNode prevNode() // getter 388 { 389 if(tparent) 390 { 391 int i; 392 i = tparent.tchildren.indexOf(this); 393 assert(i != -1); 394 395 if(i) 396 { 397 i--; 398 return tparent.tchildren._nodes[i]; 399 } 400 } 401 return null; 402 } 403 404 405 /// 406 final @property void tag(Object o) // setter 407 { 408 ttag = o; 409 } 410 411 /// ditto 412 final @property Object tag() // getter 413 { 414 return ttag; 415 } 416 417 418 /// 419 final @property void text(Dstring newText) // setter 420 { 421 ttext = newText; 422 423 if(created) 424 { 425 TV_ITEMA item; 426 Message m; 427 428 item.mask = TVIF_HANDLE | TVIF_TEXT; 429 item.hItem = hnode; 430 /+ 431 item.pszText = stringToStringz(ttext); 432 //item.cchTextMax = ttext.length; // ? 433 m = Message(tview.handle, TVM_SETITEMA, 0, cast(LPARAM)&item); 434 +/ 435 if(dfl.internal.utf.useUnicode) 436 { 437 item.pszText = cast(typeof(item.pszText))dfl.internal.utf.toUnicodez(ttext); 438 m = Message(tview.handle, TVM_SETITEMW, 0, cast(LPARAM)&item); 439 } 440 else 441 { 442 item.pszText = cast(typeof(item.pszText))dfl.internal.utf.unsafeAnsiz(ttext); 443 m = Message(tview.handle, TVM_SETITEMA, 0, cast(LPARAM)&item); 444 } 445 tview.prevWndProc(m); 446 } 447 } 448 449 /// ditto 450 final @property Dstring text() // getter 451 { 452 return ttext; 453 } 454 455 456 /// 457 // Get the TreeView control this node belongs to. 458 final @property TreeView treeView() // getter 459 { 460 return tview; 461 } 462 463 464 /// 465 final void beginEdit() 466 { 467 if(created) 468 { 469 SetFocus(tview.hwnd); // Needs to have focus. 470 HWND hwEdit; 471 hwEdit = cast(HWND)SendMessageA(tview.hwnd, TVM_EDITLABELA, 0, cast(LPARAM)hnode); 472 if(!hwEdit) 473 goto err_edit; 474 } 475 else 476 { 477 err_edit: 478 throw new DflException("Unable to edit TreeNode"); 479 } 480 } 481 482 483 /+ 484 /// 485 final void endEdit(bool cancel) 486 { 487 // ? 488 } 489 +/ 490 491 492 /// 493 final void ensureVisible() 494 { 495 if(created) 496 { 497 SendMessageA(tview.hwnd, TVM_ENSUREVISIBLE, 0, cast(LPARAM)hnode); 498 } 499 } 500 501 502 /// 503 final void collapse() 504 { 505 if(created) 506 { 507 SendMessageA(tview.hwnd, TVM_EXPAND, TVE_COLLAPSE, cast(LPARAM)hnode); 508 } 509 } 510 511 512 /// 513 final void expand() 514 { 515 if(created) 516 { 517 SendMessageA(tview.hwnd, TVM_EXPAND, TVE_EXPAND, cast(LPARAM)hnode); 518 } 519 } 520 521 522 /// 523 final void expandAll() 524 { 525 if(created) 526 { 527 SendMessageA(tview.hwnd, TVM_EXPAND, TVE_EXPAND, cast(LPARAM)hnode); 528 529 foreach(TreeNode node; tchildren._nodes) 530 { 531 node.expandAll(); 532 } 533 } 534 } 535 536 537 /// 538 static TreeNode fromHandle(TreeView tree, HTREEITEM handle) 539 { 540 return tree.treeNodeFromHandle(handle); 541 } 542 543 544 /// 545 final void remove() 546 { 547 if(tparent) 548 tparent.tchildren.remove(this); 549 else if(tview) // It's a top level node. 550 tview.tchildren.remove(this); 551 } 552 553 554 /// 555 final void toggle() 556 { 557 if(created) 558 { 559 SendMessageA(tview.hwnd, TVM_EXPAND, TVE_TOGGLE, cast(LPARAM)hnode); 560 } 561 } 562 563 564 version(DFL_NO_IMAGELIST) 565 { 566 } 567 else 568 { 569 /// 570 final @property void imageIndex(int index) // setter 571 { 572 this._imgidx = index; 573 574 if(created) 575 { 576 TV_ITEMA item; 577 Message m; 578 m = Message(tview.handle, TVM_SETITEMA, 0, cast(LPARAM)&item); 579 580 item.mask = TVIF_HANDLE | TVIF_IMAGE; 581 item.hItem = hnode; 582 item.iImage = _imgidx; 583 if(tview._selimgidx < 0) 584 { 585 item.mask |= TVIF_SELECTEDIMAGE; 586 item.iSelectedImage = _imgidx; 587 } 588 tview.prevWndProc(m); 589 } 590 } 591 592 /// ditto 593 final @property int imageIndex() // getter 594 { 595 return _imgidx; 596 } 597 } 598 599 600 override Dstring toString() 601 { 602 return ttext; 603 } 604 605 606 override Dequ opEquals(Object o) 607 { 608 return 0 == stringICmp(ttext, getObjectString(o)); // ? 609 } 610 611 Dequ opEquals(TreeNode node) 612 { 613 return 0 == stringICmp(ttext, node.ttext); 614 } 615 616 Dequ opEquals(Dstring val) 617 { 618 return 0 == stringICmp(ttext, val); 619 } 620 621 622 override int opCmp(Object o) 623 { 624 return stringICmp(ttext, getObjectString(o)); // ? 625 } 626 627 int opCmp(TreeNode node) 628 { 629 return stringICmp(ttext, node.ttext); 630 } 631 632 int opCmp(Dstring val) 633 { 634 return stringICmp(text, val); 635 } 636 637 638 private: 639 Dstring ttext; 640 TreeNode tparent; 641 TreeNodeCollection tchildren; 642 Object ttag; 643 HTREEITEM hnode; 644 TreeView tview; 645 version(DFL_NO_IMAGELIST) 646 { 647 } 648 else 649 { 650 int _imgidx = -1; 651 } 652 /+ 653 Color bcolor, fcolor; 654 Font tfont; 655 +/ 656 657 658 package final @property bool created() // getter 659 { 660 if(tview && tview.created()) 661 { 662 assert(hnode); 663 return true; 664 } 665 return false; 666 } 667 668 669 bool isState(UINT state) 670 { 671 if(created) 672 { 673 TV_ITEMA ti; 674 ti.mask = TVIF_HANDLE | TVIF_STATE; 675 ti.hItem = hnode; 676 ti.stateMask = state; 677 if(SendMessageA(tview.handle, TVM_GETITEMA, 0, cast(LPARAM)&ti)) 678 { 679 if(ti.state & state) 680 return true; 681 } 682 } 683 return false; 684 } 685 686 687 void _reset() 688 { 689 hnode = null; 690 tview = null; 691 tparent = null; 692 } 693 } 694 695 696 /// 697 class TreeNodeCollection 698 { 699 void add(TreeNode node) 700 { 701 //cprintf("Adding node %p '%.*s'\n", cast(void*)node, getObjectString(node)); 702 703 int i; 704 705 if(tview && tview.sorted()) 706 { 707 // Insertion sort. 708 709 for(i = 0; i != _nodes.length; i++) 710 { 711 if(node < _nodes[i]) 712 break; 713 } 714 } 715 else 716 { 717 i = _nodes.length; 718 } 719 720 insert(i, node); 721 } 722 723 void add(Dstring text) 724 { 725 return add(new TreeNode(text)); 726 } 727 728 void add(Object val) 729 { 730 return add(new TreeNode(getObjectString(val))); // ? 731 } 732 733 734 void addRange(Object[] range) 735 { 736 foreach(Object o; range) 737 { 738 add(o); 739 } 740 } 741 742 void addRange(TreeNode[] range) 743 { 744 foreach(TreeNode node; range) 745 { 746 add(node); 747 } 748 } 749 750 void addRange(Dstring[] range) 751 { 752 foreach(Dstring s; range) 753 { 754 add(s); 755 } 756 } 757 758 759 // Like clear but doesn't bother removing stuff from the lists. 760 // Used when a parent is being removed and the children only 761 // need to be reset. 762 private void _reset() 763 { 764 foreach(TreeNode node; _nodes) 765 { 766 node._reset(); 767 } 768 } 769 770 771 // Clear node handles when the TreeView window is destroyed so 772 // that it can be reconstructed. 773 private void _resetHandles() 774 { 775 foreach(TreeNode node; _nodes) 776 { 777 node.tchildren._resetHandles(); 778 node.hnode = null; 779 } 780 } 781 782 783 private: 784 785 TreeView tview; // null if not assigned to a TreeView yet. 786 TreeNode tparent; // null if root. The parent of -_nodes-. 787 TreeNode[] _nodes; 788 789 790 void verifyNoParent(TreeNode node) 791 { 792 if(node.tparent) 793 throw new DflException("TreeNode already belongs to a TreeView"); 794 } 795 796 797 package this(TreeView treeView, TreeNode parentNode) 798 { 799 tview = treeView; 800 tparent = parentNode; 801 } 802 803 804 package final void setTreeView(TreeView treeView) 805 { 806 tview = treeView; 807 foreach(TreeNode node; _nodes) 808 { 809 node.tchildren.setTreeView(treeView); 810 } 811 } 812 813 814 package final @property bool created() // getter 815 { 816 return tview && tview.created(); 817 } 818 819 820 package void populateInsertChildNode(ref Message m, ref TV_ITEMA dest, TreeNode node) 821 { 822 with(dest) 823 { 824 mask = /+ TVIF_CHILDREN | +/ TVIF_PARAM | TVIF_TEXT; 825 version(DFL_NO_IMAGELIST) 826 { 827 } 828 else 829 { 830 mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE; 831 iImage = node._imgidx; 832 if(tview._selimgidx < 0) 833 iSelectedImage = node._imgidx; 834 else 835 iSelectedImage = tview._selimgidx; 836 } 837 /+ cChildren = I_CHILDRENCALLBACK; +/ 838 lParam = cast(LPARAM)cast(void*)node; 839 /+ 840 pszText = stringToStringz(node.text); 841 //cchTextMax = node.text.length; // ? 842 +/ 843 if(dfl.internal.utf.useUnicode) 844 { 845 pszText = cast(typeof(pszText))dfl.internal.utf.toUnicodez(node.text); 846 m.hWnd = tview.handle; 847 m.msg = TVM_INSERTITEMW; 848 } 849 else 850 { 851 pszText = cast(typeof(pszText))dfl.internal.utf.unsafeAnsiz(node.text); 852 m.hWnd = tview.handle; 853 m.msg = TVM_INSERTITEMA; 854 } 855 } 856 } 857 858 859 void doNodes() 860 in 861 { 862 assert(created); 863 } 864 body 865 { 866 TV_INSERTSTRUCTA tis; 867 Message m; 868 869 tis.hInsertAfter = TVI_LAST; 870 871 m.hWnd = tview.handle; 872 m.wParam = 0; 873 874 foreach(TreeNode node; _nodes) 875 { 876 assert(!node.handle); 877 878 tis.hParent = tparent ? tparent.handle : TVI_ROOT; 879 populateInsertChildNode(m, tis.item, node); 880 881 m.lParam = cast(LPARAM)&tis; 882 tview.prevWndProc(m); 883 assert(m.result); 884 node.hnode = cast(HTREEITEM)m.result; 885 886 node.tchildren.doNodes(); 887 } 888 } 889 890 891 void _added(size_t idx, TreeNode val) 892 { 893 verifyNoParent(val); 894 895 val.tparent = tparent; 896 val.tview = tview; 897 val.tchildren.setTreeView(tview); 898 899 if(created) 900 { 901 TV_INSERTSTRUCTA tis; 902 903 if(idx <= 0) 904 { 905 tis.hInsertAfter = TVI_FIRST; 906 } 907 else if(idx >= cast(int)_nodes.length) 908 { 909 tis.hInsertAfter = TVI_LAST; 910 } 911 else 912 { 913 tis.hInsertAfter = _nodes[idx - 1].handle; 914 } 915 916 tis.hParent = tparent ? tparent.handle : TVI_ROOT; 917 assert(tis.hInsertAfter); 918 919 Message m; 920 m.wParam = 0; 921 922 populateInsertChildNode(m, tis.item, val); 923 924 m.lParam = cast(LPARAM)&tis; 925 tview.prevWndProc(m); 926 assert(m.result); 927 val.hnode = cast(HTREEITEM)m.result; 928 929 val.tchildren.doNodes(); 930 931 if(tparent) 932 tview.invalidate(tparent.bounds); 933 } 934 } 935 936 937 void _removing(size_t idx, TreeNode val) 938 { 939 if(size_t.max == idx) // Clearing all... 940 { 941 TreeNode[] nodes = _nodes; 942 _nodes = _nodes[0 .. 0]; // Not nice to dfl.collections, but OK. 943 if(created) 944 { 945 Message m; 946 m.hWnd = tview.handle; 947 m.msg = TVM_DELETEITEM; 948 m.wParam = 0; 949 if(tparent) 950 { 951 foreach(TreeNode node; nodes) 952 { 953 assert(node.handle !is null); 954 m.lParam = cast(LPARAM)node.handle; 955 tview.prevWndProc(m); 956 957 node._reset(); 958 } 959 } 960 else 961 { 962 m.lParam = cast(LPARAM)TVI_ROOT; 963 tview.prevWndProc(m); 964 foreach(TreeNode node; nodes) 965 { 966 node._reset(); 967 } 968 } 969 } 970 } 971 else 972 { 973 } 974 } 975 976 977 void _removed(size_t idx, TreeNode val) 978 { 979 if(size_t.max == idx) // Clear all. 980 { 981 } 982 else 983 { 984 if(created) 985 { 986 assert(val.hnode); 987 Message m; 988 m = Message(tview.handle, TVM_DELETEITEM, 0, cast(LPARAM)val.hnode); 989 tview.prevWndProc(m); 990 } 991 992 // Clear children. 993 val._reset(); 994 } 995 } 996 997 998 public: 999 1000 mixin ListWrapArray!(TreeNode, _nodes, 1001 _blankListCallback!(TreeNode), _added, 1002 _removing, _removed, 1003 true, /+true+/ false, false) _wraparray; 1004 } 1005 1006 1007 /// 1008 class TreeView: ControlSuperClass // docmain 1009 { 1010 this() 1011 { 1012 _initTreeview(); 1013 1014 wstyle |= WS_TABSTOP | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_HASLINES; 1015 wexstyle |= WS_EX_CLIENTEDGE; 1016 ctrlStyle |= ControlStyles.SELECTABLE; 1017 wclassStyle = treeviewClassStyle; 1018 1019 tchildren = new TreeNodeCollection(this, null); 1020 } 1021 1022 1023 /+ 1024 ~this() 1025 { 1026 /+ 1027 if(tchildren) 1028 tchildren._dtorReset(); 1029 +/ 1030 } 1031 +/ 1032 1033 1034 static @property Color defaultBackColor() // getter 1035 { 1036 return SystemColors.window; 1037 } 1038 1039 1040 override @property Color backColor() // getter 1041 { 1042 if(Color.empty == backc) 1043 return defaultBackColor; 1044 return backc; 1045 } 1046 1047 1048 override @property void backColor(Color b) // setter 1049 { 1050 super.backColor = b; 1051 1052 if(created) 1053 { 1054 // For some reason the left edge isn't showing the new color. 1055 // This causes the entire control to be redrawn with the new color. 1056 // Sets the same font. 1057 prevwproc(WM_SETFONT, this.font ? cast(WPARAM)this.font.handle : 0, MAKELPARAM(TRUE, 0)); 1058 } 1059 } 1060 1061 1062 static @property Color defaultForeColor() //getter 1063 { 1064 return SystemColors.windowText; 1065 } 1066 1067 1068 override @property Color foreColor() // getter 1069 { 1070 if(Color.empty == forec) 1071 return defaultForeColor; 1072 return forec; 1073 } 1074 1075 alias Control.foreColor foreColor; // Overload. 1076 1077 1078 final @property void borderStyle(BorderStyle bs) // setter 1079 { 1080 final switch(bs) 1081 { 1082 case BorderStyle.FIXED_3D: 1083 _style(_style() & ~WS_BORDER); 1084 _exStyle(_exStyle() | WS_EX_CLIENTEDGE); 1085 break; 1086 1087 case BorderStyle.FIXED_SINGLE: 1088 _exStyle(_exStyle() & ~WS_EX_CLIENTEDGE); 1089 _style(_style() | WS_BORDER); 1090 break; 1091 1092 case BorderStyle.NONE: 1093 _style(_style() & ~WS_BORDER); 1094 _exStyle(_exStyle() & ~WS_EX_CLIENTEDGE); 1095 break; 1096 } 1097 1098 if(created) 1099 { 1100 redrawEntire(); 1101 } 1102 } 1103 1104 1105 final @property BorderStyle borderStyle() // getter 1106 { 1107 if(_exStyle() & WS_EX_CLIENTEDGE) 1108 return BorderStyle.FIXED_3D; 1109 else if(_style() & WS_BORDER) 1110 return BorderStyle.FIXED_SINGLE; 1111 return BorderStyle.NONE; 1112 } 1113 1114 1115 /+ 1116 /// 1117 final @property void checkBoxes(bool byes) // setter 1118 { 1119 if(byes) 1120 _style(_style() | TVS_CHECKBOXES); 1121 else 1122 _style(_style() & ~TVS_CHECKBOXES); 1123 1124 _crecreate(); 1125 } 1126 1127 /// ditto 1128 final @property bool checkBoxes() // getter 1129 { 1130 return (_style() & TVS_CHECKBOXES) != 0; 1131 } 1132 +/ 1133 1134 1135 /// 1136 final @property void fullRowSelect(bool byes) // setter 1137 { 1138 if(byes) 1139 _style(_style() | TVS_FULLROWSELECT); 1140 else 1141 _style(_style() & ~TVS_FULLROWSELECT); 1142 1143 _crecreate(); // ? 1144 } 1145 1146 /// ditto 1147 final @property bool fullRowSelect() // getter 1148 { 1149 return (_style() & TVS_FULLROWSELECT) != 0; 1150 } 1151 1152 1153 /// 1154 final @property void hideSelection(bool byes) // setter 1155 { 1156 if(byes) 1157 _style(_style() & ~TVS_SHOWSELALWAYS); 1158 else 1159 _style(_style() | TVS_SHOWSELALWAYS); 1160 } 1161 1162 /// ditto 1163 final @property bool hideSelection() // getter 1164 { 1165 return (_style() & TVS_SHOWSELALWAYS) == 0; 1166 } 1167 1168 1169 deprecated alias hoverSelection hotTracking; 1170 1171 /// 1172 final @property void hoverSelection(bool byes) // setter 1173 { 1174 if(byes) 1175 _style(_style() | TVS_TRACKSELECT); 1176 else 1177 _style(_style() & ~TVS_TRACKSELECT); 1178 } 1179 1180 /// ditto 1181 final @property bool hoverSelection() // getter 1182 { 1183 return (_style() & TVS_TRACKSELECT) != 0; 1184 } 1185 1186 1187 /// 1188 final @property void indent(int newIndent) // setter 1189 { 1190 if(newIndent < 0) 1191 newIndent = 0; 1192 else if(newIndent > 32_000) 1193 newIndent = 32_000; 1194 1195 ind = newIndent; 1196 1197 if(created) 1198 SendMessageA(hwnd, TVM_SETINDENT, ind, 0); 1199 } 1200 1201 /// ditto 1202 final @property int indent() // getter 1203 { 1204 if(created) 1205 ind = cast(int)SendMessageA(hwnd, TVM_GETINDENT, 0, 0); 1206 return ind; 1207 } 1208 1209 1210 /// 1211 final @property void itemHeight(int h) // setter 1212 { 1213 if(h < 0) 1214 h = 0; 1215 1216 iheight = h; 1217 1218 if(created) 1219 SendMessageA(hwnd, TVM_SETITEMHEIGHT, iheight, 0); 1220 } 1221 1222 /// ditto 1223 final @property int itemHeight() // getter 1224 { 1225 if(created) 1226 iheight = cast(int)SendMessageA(hwnd, TVM_GETITEMHEIGHT, 0, 0); 1227 return iheight; 1228 } 1229 1230 1231 /// 1232 final @property void labelEdit(bool byes) // setter 1233 { 1234 if(byes) 1235 _style(_style() | TVS_EDITLABELS); 1236 else 1237 _style(_style() & ~TVS_EDITLABELS); 1238 } 1239 1240 /// ditto 1241 final @property bool labelEdit() // getter 1242 { 1243 return (_style() & TVS_EDITLABELS) != 0; 1244 } 1245 1246 1247 /// 1248 final @property TreeNodeCollection nodes() // getter 1249 { 1250 return tchildren; 1251 } 1252 1253 1254 /// 1255 final @property void pathSeparator(dchar sep) // setter 1256 { 1257 pathsep = sep; 1258 } 1259 1260 /// ditto 1261 final @property dchar pathSeparator() // getter 1262 { 1263 return pathsep; 1264 } 1265 1266 1267 /// 1268 final @property void scrollable(bool byes) // setter 1269 { 1270 if(byes) 1271 _style(_style() & ~TVS_NOSCROLL); 1272 else 1273 _style(_style() | TVS_NOSCROLL); 1274 1275 if(created) 1276 redrawEntire(); 1277 } 1278 1279 /// ditto 1280 final @property bool scrollable() // getter 1281 { 1282 return (_style & TVS_NOSCROLL) == 0; 1283 } 1284 1285 1286 /// 1287 final @property void selectedNode(TreeNode node) // setter 1288 { 1289 if(created) 1290 { 1291 if(node) 1292 { 1293 SendMessageA(hwnd, TVM_SELECTITEM, TVGN_CARET, cast(LPARAM)node.handle); 1294 } 1295 else 1296 { 1297 // Should the selection be cleared if -node- is null? 1298 //SendMessageA(hwnd, TVM_SELECTITEM, TVGN_CARET, cast(LPARAM)null); 1299 } 1300 } 1301 } 1302 1303 /// ditto 1304 final @property TreeNode selectedNode() // getter 1305 { 1306 if(created) 1307 { 1308 HTREEITEM hnode; 1309 hnode = cast(HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_CARET, cast(LPARAM)null); 1310 if(hnode) 1311 return treeNodeFromHandle(hnode); 1312 } 1313 return null; 1314 } 1315 1316 1317 /// 1318 final @property void showLines(bool byes) // setter 1319 { 1320 if(byes) 1321 _style(_style() | TVS_HASLINES); 1322 else 1323 _style(_style() & ~TVS_HASLINES); 1324 1325 _crecreate(); // ? 1326 } 1327 1328 /// ditto 1329 final @property bool showLines() // getter 1330 { 1331 return (_style() & TVS_HASLINES) != 0; 1332 } 1333 1334 1335 /// 1336 final @property void showPlusMinus(bool byes) // setter 1337 { 1338 if(byes) 1339 _style(_style() | TVS_HASBUTTONS); 1340 else 1341 _style(_style() & ~TVS_HASBUTTONS); 1342 1343 _crecreate(); // ? 1344 } 1345 1346 /// ditto 1347 final @property bool showPlusMinus() // getter 1348 { 1349 return (_style() & TVS_HASBUTTONS) != 0; 1350 } 1351 1352 1353 /// 1354 // -showPlusMinus- should be false. 1355 final @property void singleExpand(bool byes) // setter 1356 { 1357 if(byes) 1358 _style(_style() | TVS_SINGLEEXPAND); 1359 else 1360 _style(_style() & ~TVS_SINGLEEXPAND); 1361 1362 _crecreate(); // ? 1363 } 1364 1365 /// ditto 1366 final @property bool singleExpand() // getter 1367 { 1368 return (_style & TVS_SINGLEEXPAND) != 0; 1369 } 1370 1371 1372 /// 1373 final @property void showRootLines(bool byes) // setter 1374 { 1375 if(byes) 1376 _style(_style() | TVS_LINESATROOT); 1377 else 1378 _style(_style() & ~TVS_LINESATROOT); 1379 1380 _crecreate(); // ? 1381 } 1382 1383 /// ditto 1384 final @property bool showRootLines() // getter 1385 { 1386 return (_style() & TVS_LINESATROOT) != 0; 1387 } 1388 1389 1390 /// 1391 final @property void sorted(bool byes) // setter 1392 { 1393 _sort = byes; 1394 } 1395 1396 /// ditto 1397 final @property bool sorted() // getter 1398 { 1399 return _sort; 1400 } 1401 1402 1403 /// 1404 // First visible node, based on the scrolled position. 1405 final @property TreeNode topNode() // getter 1406 { 1407 if(created) 1408 { 1409 HTREEITEM hnode; 1410 hnode = cast(HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, 1411 TVGN_FIRSTVISIBLE, cast(LPARAM)null); 1412 if(hnode) 1413 return treeNodeFromHandle(hnode); 1414 } 1415 return null; 1416 } 1417 1418 1419 /// 1420 // Number of visible nodes, including partially visible. 1421 final @property int visibleCount() // getter 1422 { 1423 if(!created) 1424 return 0; 1425 return cast(int)SendMessageA(hwnd, TVM_GETVISIBLECOUNT, 0, 0); 1426 } 1427 1428 1429 /// 1430 final void beginUpdate() 1431 { 1432 SendMessageA(handle, WM_SETREDRAW, false, 0); 1433 } 1434 1435 /// ditto 1436 final void endUpdate() 1437 { 1438 SendMessageA(handle, WM_SETREDRAW, true, 0); 1439 invalidate(true); // Show updates. 1440 } 1441 1442 1443 /// 1444 final void collapseAll() 1445 { 1446 if(created) 1447 { 1448 void collapsing(TreeNodeCollection tchildren) 1449 { 1450 foreach(TreeNode node; tchildren._nodes) 1451 { 1452 SendMessageA(hwnd, TVM_EXPAND, TVE_COLLAPSE, cast(LPARAM)node.hnode); 1453 collapsing(node.tchildren); 1454 } 1455 } 1456 1457 1458 collapsing(tchildren); 1459 } 1460 } 1461 1462 1463 /// 1464 final void expandAll() 1465 { 1466 if(created) 1467 { 1468 void expanding(TreeNodeCollection tchildren) 1469 { 1470 foreach(TreeNode node; tchildren._nodes) 1471 { 1472 SendMessageA(hwnd, TVM_EXPAND, TVE_EXPAND, cast(LPARAM)node.hnode); 1473 expanding(node.tchildren); 1474 } 1475 } 1476 1477 1478 expanding(tchildren); 1479 } 1480 } 1481 1482 1483 /// 1484 final TreeNode getNodeAt(int x, int y) 1485 { 1486 if(created) 1487 { 1488 TVHITTESTINFO thi; 1489 HTREEITEM hti; 1490 thi.pt.x = x; 1491 thi.pt.y = y; 1492 hti = cast(HTREEITEM)SendMessageA(hwnd, TVM_HITTEST, 0, cast(LPARAM)&thi); 1493 if(hti) 1494 { 1495 TreeNode result; 1496 result = treeNodeFromHandle(hti); 1497 if(result) 1498 { 1499 assert(result.tview is this); 1500 return result; 1501 } 1502 } 1503 } 1504 return null; 1505 } 1506 1507 /// ditto 1508 final TreeNode getNodeAt(Point pt) 1509 { 1510 return getNodeAt(pt.x, pt.y); 1511 } 1512 1513 1514 /+ 1515 /// 1516 // TODO: finish. 1517 final int getNodeCount(bool includeSubNodes) 1518 { 1519 int result; 1520 result = tchildren.length(); 1521 1522 if(includeSubNodes) 1523 { 1524 // ... 1525 } 1526 1527 return result; 1528 } 1529 +/ 1530 1531 1532 version(DFL_NO_IMAGELIST) 1533 { 1534 } 1535 else 1536 { 1537 /// 1538 final @property void imageList(ImageList imglist) // setter 1539 { 1540 if(isHandleCreated) 1541 { 1542 prevwproc(TVM_SETIMAGELIST, TVSIL_NORMAL, 1543 cast(LPARAM)(imglist ? imglist.handle : cast(HIMAGELIST)null)); 1544 } 1545 1546 _imglist = imglist; 1547 } 1548 1549 /// ditto 1550 final @property ImageList imageList() // getter 1551 { 1552 return _imglist; 1553 } 1554 1555 1556 /+ 1557 /// 1558 // Default image index (if -1 use this). 1559 final @property void imageIndex(int index) // setter 1560 { 1561 _defimgidx = index; 1562 } 1563 1564 /// ditto 1565 final @property int imageIndex() // getter 1566 { 1567 return _defimgidx; 1568 } 1569 +/ 1570 1571 1572 /// 1573 final @property void selectedImageIndex(int index) // setter 1574 { 1575 //assert(index >= 0); 1576 assert(index >= -1); 1577 _selimgidx = index; 1578 1579 if(isHandleCreated) 1580 { 1581 TreeNode curnode = selectedNode; 1582 _crecreate(); 1583 if(curnode) 1584 curnode.ensureVisible(); 1585 } 1586 } 1587 1588 /// ditto 1589 final @property int selectedImageIndex() // getter 1590 { 1591 return _selimgidx; 1592 } 1593 } 1594 1595 1596 protected override @property Size defaultSize() // getter 1597 { 1598 return Size(120, 100); 1599 } 1600 1601 1602 /+ 1603 override void createHandle() 1604 { 1605 if(isHandleCreated) 1606 return; 1607 1608 createClassHandle(TREEVIEW_CLASSNAME); 1609 1610 onHandleCreated(EventArgs.empty); 1611 } 1612 +/ 1613 1614 1615 protected override void createParams(ref CreateParams cp) 1616 { 1617 super.createParams(cp); 1618 1619 cp.className = TREEVIEW_CLASSNAME; 1620 } 1621 1622 1623 protected override void onHandleCreated(EventArgs ea) 1624 { 1625 super.onHandleCreated(ea); 1626 1627 prevwproc(CCM_SETVERSION, 5, 0); // Fixes font size issue. 1628 1629 prevwproc(TVM_SETINDENT, ind, 0); 1630 1631 prevwproc(TVM_SETITEMHEIGHT, iheight, 0); 1632 1633 version(DFL_NO_IMAGELIST) 1634 { 1635 } 1636 else 1637 { 1638 if(_imglist) 1639 prevwproc(TVM_SETIMAGELIST, TVSIL_NORMAL, cast(LPARAM)_imglist.handle); 1640 } 1641 1642 tchildren.doNodes(); 1643 } 1644 1645 1646 protected override void onHandleDestroyed(EventArgs ea) 1647 { 1648 tchildren._resetHandles(); 1649 1650 super.onHandleDestroyed(ea); 1651 } 1652 1653 1654 protected override void wndProc(ref Message m) 1655 { 1656 // TODO: support these messages. 1657 switch(m.msg) 1658 { 1659 case TVM_INSERTITEMA: 1660 case TVM_INSERTITEMW: 1661 m.result = cast(LRESULT)null; 1662 return; 1663 1664 case TVM_SETITEMA: 1665 case TVM_SETITEMW: 1666 m.result = cast(LRESULT)-1; 1667 return; 1668 1669 case TVM_DELETEITEM: 1670 m.result = FALSE; 1671 return; 1672 1673 case TVM_SETIMAGELIST: 1674 m.result = cast(LRESULT)null; 1675 return; 1676 1677 default: 1678 } 1679 1680 super.wndProc(m); 1681 } 1682 1683 1684 protected override void prevWndProc(ref Message msg) 1685 { 1686 //msg.result = CallWindowProcA(treeviewPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam); 1687 msg.result = dfl.internal.utf.callWindowProc(treeviewPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam); 1688 } 1689 1690 1691 //TreeViewEventHandler afterCollapse; 1692 Event!(TreeView, TreeViewEventArgs) afterCollapse; /// 1693 //TreeViewEventHandler afterExpand; 1694 Event!(TreeView, TreeViewEventArgs) afterExpand; /// 1695 //TreeViewEventHandler afterSelect; 1696 Event!(TreeView, TreeViewEventArgs) afterSelect; /// 1697 //NodeLabelEditEventHandler afterLabelEdit; 1698 Event!(TreeView, NodeLabelEditEventArgs) afterLabelEdit; /// 1699 //TreeViewCancelEventHandler beforeCollapse; 1700 Event!(TreeView, TreeViewCancelEventArgs) beforeCollapse; /// 1701 //TreeViewCancelEventHandler beforeExpand; 1702 Event!(TreeView, TreeViewCancelEventArgs) beforeExpand; /// 1703 //TreeViewCancelEventHandler beforeSelect; 1704 Event!(TreeView, TreeViewCancelEventArgs) beforeSelect; /// 1705 //NodeLabelEditEventHandler beforeLabelEdit; 1706 Event!(TreeView, NodeLabelEditEventArgs) beforeLabelEdit; /// 1707 1708 1709 /// 1710 protected void onAfterCollapse(TreeViewEventArgs ea) 1711 { 1712 afterCollapse(this, ea); 1713 } 1714 1715 1716 /// 1717 protected void onAfterExpand(TreeViewEventArgs ea) 1718 { 1719 afterExpand(this, ea); 1720 } 1721 1722 1723 /// 1724 protected void onAfterSelect(TreeViewEventArgs ea) 1725 { 1726 afterSelect(this, ea); 1727 } 1728 1729 1730 /// 1731 protected void onAfterLabelEdit(NodeLabelEditEventArgs ea) 1732 { 1733 afterLabelEdit(this, ea); 1734 } 1735 1736 1737 /// 1738 protected void onBeforeCollapse(TreeViewCancelEventArgs ea) 1739 { 1740 beforeCollapse(this, ea); 1741 } 1742 1743 1744 /// 1745 protected void onBeforeExpand(TreeViewCancelEventArgs ea) 1746 { 1747 beforeExpand(this, ea); 1748 } 1749 1750 1751 /// 1752 protected void onBeforeSelect(TreeViewCancelEventArgs ea) 1753 { 1754 beforeSelect(this, ea); 1755 } 1756 1757 1758 /// 1759 protected void onBeforeLabelEdit(NodeLabelEditEventArgs ea) 1760 { 1761 beforeLabelEdit(this, ea); 1762 } 1763 1764 1765 protected override void onReflectedMessage(ref Message m) // package 1766 { 1767 super.onReflectedMessage(m); 1768 1769 switch(m.msg) 1770 { 1771 case WM_NOTIFY: 1772 { 1773 NMHDR* nmh; 1774 NM_TREEVIEW* nmtv; 1775 TreeViewCancelEventArgs cea; 1776 1777 nmh = cast(NMHDR*)m.lParam; 1778 assert(nmh.hwndFrom == hwnd); 1779 1780 switch(nmh.code) 1781 { 1782 case NM_CUSTOMDRAW: 1783 { 1784 NMTVCUSTOMDRAW* tvcd; 1785 tvcd = cast(NMTVCUSTOMDRAW*)nmh; 1786 //if(tvcd.nmcd.dwDrawStage & CDDS_ITEM) 1787 { 1788 //if(tvcd.nmcd.uItemState & CDIS_SELECTED) 1789 if((tvcd.nmcd.dwDrawStage & CDDS_ITEM) 1790 && (tvcd.nmcd.uItemState & CDIS_SELECTED)) 1791 { 1792 // Note: might not look good with custom colors. 1793 tvcd.clrText = SystemColors.highlightText.toRgb(); 1794 tvcd.clrTextBk = SystemColors.highlight.toRgb(); 1795 } 1796 else 1797 { 1798 //tvcd.clrText = foreColor.toRgb(); 1799 tvcd.clrText = foreColor.solidColor(backColor).toRgb(); 1800 tvcd.clrTextBk = backColor.toRgb(); 1801 } 1802 } 1803 m.result |= CDRF_NOTIFYITEMDRAW; // | CDRF_NOTIFYITEMERASE; 1804 1805 // This doesn't seem to be doing anything. 1806 Font fon; 1807 fon = this.font; 1808 if(fon) 1809 { 1810 SelectObject(tvcd.nmcd.hdc, fon.handle); 1811 m.result |= CDRF_NEWFONT; 1812 } 1813 } 1814 break; 1815 1816 /+ 1817 case TVN_GETDISPINFOA: 1818 1819 break; 1820 +/ 1821 1822 case TVN_SELCHANGINGW: 1823 goto sel_changing; 1824 1825 case TVN_SELCHANGINGA: 1826 if(dfl.internal.utf.useUnicode) 1827 break; 1828 sel_changing: 1829 1830 nmtv = cast(NM_TREEVIEW*)nmh; 1831 switch(nmtv.action) 1832 { 1833 case TVC_BYMOUSE: 1834 cea = new TreeViewCancelEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1835 false, TreeViewAction.BY_MOUSE); 1836 onBeforeSelect(cea); 1837 m.result = cea.cancel; 1838 break; 1839 1840 case TVC_BYKEYBOARD: 1841 cea = new TreeViewCancelEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1842 false, TreeViewAction.BY_KEYBOARD); 1843 onBeforeSelect(cea); 1844 m.result = cea.cancel; 1845 break; 1846 1847 //case TVC_UNKNOWN: 1848 default: 1849 cea = new TreeViewCancelEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1850 false, TreeViewAction.UNKNOWN); 1851 onBeforeSelect(cea); 1852 m.result = cea.cancel; 1853 } 1854 break; 1855 1856 case TVN_SELCHANGEDW: 1857 goto sel_changed; 1858 1859 case TVN_SELCHANGEDA: 1860 if(dfl.internal.utf.useUnicode) 1861 break; 1862 sel_changed: 1863 1864 nmtv = cast(NM_TREEVIEW*)nmh; 1865 switch(nmtv.action) 1866 { 1867 case TVC_BYMOUSE: 1868 onAfterSelect(new TreeViewEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1869 TreeViewAction.BY_MOUSE)); 1870 break; 1871 1872 case TVC_BYKEYBOARD: 1873 onAfterSelect(new TreeViewEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1874 TreeViewAction.BY_KEYBOARD)); 1875 break; 1876 1877 //case TVC_UNKNOWN: 1878 default: 1879 onAfterSelect(new TreeViewEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1880 TreeViewAction.UNKNOWN)); 1881 } 1882 break; 1883 1884 case TVN_ITEMEXPANDINGW: 1885 goto item_expanding; 1886 1887 case TVN_ITEMEXPANDINGA: 1888 if(dfl.internal.utf.useUnicode) 1889 break; 1890 item_expanding: 1891 1892 nmtv = cast(NM_TREEVIEW*)nmh; 1893 switch(nmtv.action) 1894 { 1895 case TVE_COLLAPSE: 1896 cea = new TreeViewCancelEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1897 false, TreeViewAction.COLLAPSE); 1898 onBeforeCollapse(cea); 1899 m.result = cea.cancel; 1900 break; 1901 1902 case TVE_EXPAND: 1903 cea = new TreeViewCancelEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1904 false, TreeViewAction.EXPAND); 1905 onBeforeExpand(cea); 1906 m.result = cea.cancel; 1907 break; 1908 1909 default: 1910 } 1911 break; 1912 1913 case TVN_ITEMEXPANDEDW: 1914 goto item_expanded; 1915 1916 case TVN_ITEMEXPANDEDA: 1917 if(dfl.internal.utf.useUnicode) 1918 break; 1919 item_expanded: 1920 1921 nmtv = cast(NM_TREEVIEW*)nmh; 1922 switch(nmtv.action) 1923 { 1924 case TVE_COLLAPSE: 1925 { 1926 scope TreeViewEventArgs tvea = new TreeViewEventArgs( 1927 cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1928 TreeViewAction.COLLAPSE); 1929 onAfterCollapse(tvea); 1930 } 1931 break; 1932 1933 case TVE_EXPAND: 1934 { 1935 scope TreeViewEventArgs tvea = new TreeViewEventArgs( 1936 cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1937 TreeViewAction.EXPAND); 1938 onAfterExpand(tvea); 1939 } 1940 break; 1941 1942 default: 1943 } 1944 break; 1945 1946 case TVN_BEGINLABELEDITW: 1947 goto begin_label_edit; 1948 1949 case TVN_BEGINLABELEDITA: 1950 if(dfl.internal.utf.useUnicode) 1951 break; 1952 begin_label_edit: 1953 1954 { 1955 TV_DISPINFOA* nmdi; 1956 nmdi = cast(TV_DISPINFOA*)nmh; 1957 TreeNode node; 1958 node = cast(TreeNode)cast(void*)nmdi.item.lParam; 1959 scope NodeLabelEditEventArgs nleea = new NodeLabelEditEventArgs(node); 1960 onBeforeLabelEdit(nleea); 1961 m.result = nleea.cancelEdit; 1962 } 1963 break; 1964 1965 case TVN_ENDLABELEDITW: 1966 { 1967 Dstring label; 1968 TV_DISPINFOW* nmdi; 1969 nmdi = cast(TV_DISPINFOW*)nmh; 1970 if(nmdi.item.pszText) 1971 { 1972 TreeNode node; 1973 node = cast(TreeNode)cast(void*)nmdi.item.lParam; 1974 label = fromUnicodez(nmdi.item.pszText); 1975 scope NodeLabelEditEventArgs nleea = new NodeLabelEditEventArgs(node, label); 1976 onAfterLabelEdit(nleea); 1977 if(nleea.cancelEdit) 1978 { 1979 m.result = FALSE; 1980 } 1981 else 1982 { 1983 // TODO: check if correct implementation. 1984 // Update the node's cached text.. 1985 node.ttext = label; 1986 1987 m.result = TRUE; 1988 } 1989 } 1990 } 1991 break; 1992 1993 case TVN_ENDLABELEDITA: 1994 if(dfl.internal.utf.useUnicode) 1995 { 1996 break; 1997 } 1998 else 1999 { 2000 Dstring label; 2001 TV_DISPINFOA* nmdi; 2002 nmdi = cast(TV_DISPINFOA*)nmh; 2003 if(nmdi.item.pszText) 2004 { 2005 TreeNode node; 2006 node = cast(TreeNode)cast(void*)nmdi.item.lParam; 2007 label = fromAnsiz(nmdi.item.pszText); 2008 scope NodeLabelEditEventArgs nleea = new NodeLabelEditEventArgs(node, label); 2009 onAfterLabelEdit(nleea); 2010 if(nleea.cancelEdit) 2011 { 2012 m.result = FALSE; 2013 } 2014 else 2015 { 2016 // TODO: check if correct implementation. 2017 // Update the node's cached text.. 2018 node.ttext = label; 2019 2020 m.result = TRUE; 2021 } 2022 } 2023 break; 2024 } 2025 2026 default: 2027 } 2028 } 2029 break; 2030 2031 default: 2032 } 2033 } 2034 2035 2036 private: 2037 TreeNodeCollection tchildren; 2038 int ind = 19; // Indent. 2039 dchar pathsep = '\\'; 2040 bool _sort = false; 2041 int iheight = 16; 2042 version(DFL_NO_IMAGELIST) 2043 { 2044 } 2045 else 2046 { 2047 ImageList _imglist; 2048 int _selimgidx = -1; //0; 2049 } 2050 2051 2052 TreeNode treeNodeFromHandle(HTREEITEM hnode) 2053 { 2054 TV_ITEMA ti; 2055 ti.mask = TVIF_HANDLE | TVIF_PARAM; 2056 ti.hItem = hnode; 2057 if(SendMessageA(hwnd, TVM_GETITEMA, 0, cast(LPARAM)&ti)) 2058 { 2059 return cast(TreeNode)cast(void*)ti.lParam; 2060 } 2061 return null; 2062 } 2063 2064 package: 2065 final: 2066 LRESULT prevwproc(UINT msg, WPARAM wparam, LPARAM lparam) 2067 { 2068 //return CallWindowProcA(treeviewPrevWndProc, hwnd, msg, wparam, lparam); 2069 return dfl.internal.utf.callWindowProc(treeviewPrevWndProc, hwnd, msg, wparam, lparam); 2070 } 2071 } 2072