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 /* 690 if(hnode !is null) 691 hnode = null; 692 if(tview !is null) 693 tview = null; 694 if(tparent!is null) 695 tparent = null; 696 */ 697 } 698 } 699 700 701 /// 702 class TreeNodeCollection 703 { 704 void add(TreeNode node) 705 { 706 //cprintf("Adding node %p '%.*s'\n", cast(void*)node, getObjectString(node)); 707 708 int i; 709 710 if(tview && tview.sorted()) 711 { 712 // Insertion sort. 713 714 for(i = 0; i != _nodes.length; i++) 715 { 716 if(node < _nodes[i]) 717 break; 718 } 719 } 720 else 721 { 722 i = cast(int)_nodes.length; 723 } 724 725 insert(i, node); 726 } 727 728 void add(Dstring text) 729 { 730 return add(new TreeNode(text)); 731 } 732 733 void add(Object val) 734 { 735 return add(new TreeNode(getObjectString(val))); // ? 736 } 737 738 739 void addRange(Object[] range) 740 { 741 foreach(Object o; range) 742 { 743 add(o); 744 } 745 } 746 747 void addRange(TreeNode[] range) 748 { 749 foreach(TreeNode node; range) 750 { 751 add(node); 752 } 753 } 754 755 void addRange(Dstring[] range) 756 { 757 foreach(Dstring s; range) 758 { 759 add(s); 760 } 761 } 762 763 764 // Like clear but doesn't bother removing stuff from the lists. 765 // Used when a parent is being removed and the children only 766 // need to be reset. 767 private void _reset() 768 { 769 foreach(TreeNode node; _nodes) 770 { 771 node._reset(); 772 } 773 } 774 775 776 // Clear node handles when the TreeView window is destroyed so 777 // that it can be reconstructed. 778 private void _resetHandles() 779 { 780 foreach(TreeNode node; _nodes) 781 { 782 node.tchildren._resetHandles(); 783 node.hnode = null; 784 } 785 } 786 787 788 private: 789 790 TreeView tview; // null if not assigned to a TreeView yet. 791 TreeNode tparent; // null if root. The parent of -_nodes-. 792 TreeNode[] _nodes; 793 794 795 void verifyNoParent(TreeNode node) 796 { 797 if(node.tparent) 798 throw new DflException("TreeNode already belongs to a TreeView"); 799 } 800 801 802 package this(TreeView treeView, TreeNode parentNode) 803 { 804 tview = treeView; 805 tparent = parentNode; 806 } 807 808 809 package final void setTreeView(TreeView treeView) 810 { 811 tview = treeView; 812 foreach(TreeNode node; _nodes) 813 { 814 node.tchildren.setTreeView(treeView); 815 } 816 } 817 818 819 package final @property bool created() // getter 820 { 821 return tview && tview.created(); 822 } 823 824 825 package void populateInsertChildNode(ref Message m, ref TV_ITEMA dest, TreeNode node) 826 { 827 with(dest) 828 { 829 mask = /+ TVIF_CHILDREN | +/ TVIF_PARAM | TVIF_TEXT; 830 version(DFL_NO_IMAGELIST) 831 { 832 } 833 else 834 { 835 mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE; 836 iImage = node._imgidx; 837 if(tview._selimgidx < 0) 838 iSelectedImage = node._imgidx; 839 else 840 iSelectedImage = tview._selimgidx; 841 } 842 /+ cChildren = I_CHILDRENCALLBACK; +/ 843 lParam = cast(LPARAM)cast(void*)node; 844 /+ 845 pszText = stringToStringz(node.text); 846 //cchTextMax = node.text.length; // ? 847 +/ 848 if(dfl.internal.utf.useUnicode) 849 { 850 pszText = cast(typeof(pszText))dfl.internal.utf.toUnicodez(node.text); 851 m.hWnd = tview.handle; 852 m.msg = TVM_INSERTITEMW; 853 } 854 else 855 { 856 pszText = cast(typeof(pszText))dfl.internal.utf.unsafeAnsiz(node.text); 857 m.hWnd = tview.handle; 858 m.msg = TVM_INSERTITEMA; 859 } 860 } 861 } 862 863 864 void doNodes() 865 in 866 { 867 assert(created); 868 } 869 body 870 { 871 TV_INSERTSTRUCTA tis; 872 Message m; 873 874 tis.hInsertAfter = TVI_LAST; 875 876 m.hWnd = tview.handle; 877 m.wParam = 0; 878 879 foreach(TreeNode node; _nodes) 880 { 881 assert(!node.handle); 882 883 tis.hParent = tparent ? tparent.handle : TVI_ROOT; 884 populateInsertChildNode(m, tis.item, node); 885 886 m.lParam = cast(LPARAM)&tis; 887 tview.prevWndProc(m); 888 assert(m.result); 889 node.hnode = cast(HTREEITEM)m.result; 890 891 node.tchildren.doNodes(); 892 } 893 } 894 895 896 void _added(size_t idx, TreeNode val) 897 { 898 verifyNoParent(val); 899 900 val.tparent = tparent; 901 val.tview = tview; 902 val.tchildren.setTreeView(tview); 903 904 if(created) 905 { 906 TV_INSERTSTRUCTA tis; 907 908 if(idx <= 0) 909 { 910 tis.hInsertAfter = TVI_FIRST; 911 } 912 else if(idx >= cast(int)_nodes.length) 913 { 914 tis.hInsertAfter = TVI_LAST; 915 } 916 else 917 { 918 tis.hInsertAfter = _nodes[idx - 1].handle; 919 } 920 921 tis.hParent = tparent ? tparent.handle : TVI_ROOT; 922 assert(tis.hInsertAfter); 923 924 Message m; 925 m.wParam = 0; 926 927 populateInsertChildNode(m, tis.item, val); 928 929 m.lParam = cast(LPARAM)&tis; 930 tview.prevWndProc(m); 931 assert(m.result); 932 val.hnode = cast(HTREEITEM)m.result; 933 934 val.tchildren.doNodes(); 935 936 if(tparent) 937 tview.invalidate(tparent.bounds); 938 } 939 } 940 941 942 void _removing(size_t idx, TreeNode val) 943 { 944 if(size_t.max == idx) // Clearing all... 945 { 946 TreeNode[] nodes = _nodes; 947 _nodes = _nodes[0 .. 0]; // Not nice to dfl.collections, but OK. 948 if(created) 949 { 950 Message m; 951 m.hWnd = tview.handle; 952 m.msg = TVM_DELETEITEM; 953 m.wParam = 0; 954 if(tparent) 955 { 956 foreach(TreeNode node; nodes) 957 { 958 assert(node.handle !is null); 959 m.lParam = cast(LPARAM)node.handle; 960 tview.prevWndProc(m); 961 962 node._reset(); 963 } 964 } 965 else 966 { 967 m.lParam =cast(LPARAM)TVI_ROOT; 968 tview.prevWndProc(m); 969 foreach(TreeNode node; nodes) 970 { 971 node._reset(); 972 } 973 } 974 } 975 } 976 else 977 { 978 } 979 } 980 981 982 void _removed(size_t idx, TreeNode val) 983 { 984 if(size_t.max == idx) // Clear all. 985 { 986 } 987 else 988 { 989 if(created) 990 { 991 assert(val.hnode); 992 Message m; 993 m = Message(tview.handle, TVM_DELETEITEM, 0, cast(LPARAM)&val.hnode);// 994 tview.prevWndProc(m); 995 } 996 997 // Clear children. 998 val._reset(); 999 } 1000 } 1001 1002 1003 public: 1004 1005 mixin ListWrapArray!(TreeNode, _nodes, 1006 _blankListCallback!(TreeNode), _added, 1007 _removing, _removed, 1008 true, /+true+/ false, false) _wraparray; 1009 } 1010 1011 1012 /// 1013 class TreeView: ControlSuperClass // docmain 1014 { 1015 this() 1016 { 1017 _initTreeview(); 1018 1019 wstyle |= WS_TABSTOP | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_HASLINES; 1020 wexstyle |= WS_EX_CLIENTEDGE; 1021 ctrlStyle |= ControlStyles.SELECTABLE; 1022 wclassStyle = treeviewClassStyle; 1023 1024 tchildren = new TreeNodeCollection(this, null); 1025 } 1026 1027 1028 /+ 1029 ~this() 1030 { 1031 /+ 1032 if(tchildren) 1033 tchildren._dtorReset(); 1034 +/ 1035 } 1036 +/ 1037 1038 1039 static @property Color defaultBackColor() // getter 1040 { 1041 return SystemColors.window; 1042 } 1043 1044 1045 override @property Color backColor() // getter 1046 { 1047 if(Color.empty == backc) 1048 return defaultBackColor; 1049 return backc; 1050 } 1051 1052 1053 override @property void backColor(Color b) // setter 1054 { 1055 super.backColor = b; 1056 1057 if(created) 1058 { 1059 // For some reason the left edge isn't showing the new color. 1060 // This causes the entire control to be redrawn with the new color. 1061 // Sets the same font. 1062 prevwproc(WM_SETFONT, this.font ? cast(WPARAM)this.font.handle : 0, MAKELPARAM(TRUE, 0)); 1063 } 1064 } 1065 1066 1067 static @property Color defaultForeColor() //getter 1068 { 1069 return SystemColors.windowText; 1070 } 1071 1072 1073 override @property Color foreColor() // getter 1074 { 1075 if(Color.empty == forec) 1076 return defaultForeColor; 1077 return forec; 1078 } 1079 1080 alias Control.foreColor foreColor; // Overload. 1081 1082 1083 final @property void borderStyle(BorderStyle bs) // setter 1084 { 1085 final switch(bs) 1086 { 1087 case BorderStyle.FIXED_3D: 1088 _style(_style() & ~WS_BORDER); 1089 _exStyle(_exStyle() | WS_EX_CLIENTEDGE); 1090 break; 1091 1092 case BorderStyle.FIXED_SINGLE: 1093 _exStyle(_exStyle() & ~WS_EX_CLIENTEDGE); 1094 _style(_style() | WS_BORDER); 1095 break; 1096 1097 case BorderStyle.NONE: 1098 _style(_style() & ~WS_BORDER); 1099 _exStyle(_exStyle() & ~WS_EX_CLIENTEDGE); 1100 break; 1101 } 1102 1103 if(created) 1104 { 1105 redrawEntire(); 1106 } 1107 } 1108 1109 1110 final @property BorderStyle borderStyle() // getter 1111 { 1112 if(_exStyle() & WS_EX_CLIENTEDGE) 1113 return BorderStyle.FIXED_3D; 1114 else if(_style() & WS_BORDER) 1115 return BorderStyle.FIXED_SINGLE; 1116 return BorderStyle.NONE; 1117 } 1118 1119 1120 /+ 1121 /// 1122 final @property void checkBoxes(bool byes) // setter 1123 { 1124 if(byes) 1125 _style(_style() | TVS_CHECKBOXES); 1126 else 1127 _style(_style() & ~TVS_CHECKBOXES); 1128 1129 _crecreate(); 1130 } 1131 1132 /// ditto 1133 final @property bool checkBoxes() // getter 1134 { 1135 return (_style() & TVS_CHECKBOXES) != 0; 1136 } 1137 +/ 1138 1139 1140 /// 1141 final @property void fullRowSelect(bool byes) // setter 1142 { 1143 if(byes) 1144 _style(_style() | TVS_FULLROWSELECT); 1145 else 1146 _style(_style() & ~TVS_FULLROWSELECT); 1147 1148 _crecreate(); // ? 1149 } 1150 1151 /// ditto 1152 final @property bool fullRowSelect() // getter 1153 { 1154 return (_style() & TVS_FULLROWSELECT) != 0; 1155 } 1156 1157 1158 /// 1159 final @property void hideSelection(bool byes) // setter 1160 { 1161 if(byes) 1162 _style(_style() & ~TVS_SHOWSELALWAYS); 1163 else 1164 _style(_style() | TVS_SHOWSELALWAYS); 1165 } 1166 1167 /// ditto 1168 final @property bool hideSelection() // getter 1169 { 1170 return (_style() & TVS_SHOWSELALWAYS) == 0; 1171 } 1172 1173 1174 deprecated alias hoverSelection hotTracking; 1175 1176 /// 1177 final @property void hoverSelection(bool byes) // setter 1178 { 1179 if(byes) 1180 _style(_style() | TVS_TRACKSELECT); 1181 else 1182 _style(_style() & ~TVS_TRACKSELECT); 1183 } 1184 1185 /// ditto 1186 final @property bool hoverSelection() // getter 1187 { 1188 return (_style() & TVS_TRACKSELECT) != 0; 1189 } 1190 1191 1192 /// 1193 final @property void indent(int newIndent) // setter 1194 { 1195 if(newIndent < 0) 1196 newIndent = 0; 1197 else if(newIndent > 32_000) 1198 newIndent = 32_000; 1199 1200 ind = newIndent; 1201 1202 if(created) 1203 SendMessageA(hwnd, TVM_SETINDENT, ind, 0); 1204 } 1205 1206 /// ditto 1207 final @property int indent() // getter 1208 { 1209 if(created) 1210 ind = cast(int)SendMessageA(hwnd, TVM_GETINDENT, 0, 0); 1211 return ind; 1212 } 1213 1214 1215 /// 1216 final @property void itemHeight(int h) // setter 1217 { 1218 if(h < 0) 1219 h = 0; 1220 1221 iheight = h; 1222 1223 if(created) 1224 SendMessageA(hwnd, TVM_SETITEMHEIGHT, iheight, 0); 1225 } 1226 1227 /// ditto 1228 final @property int itemHeight() // getter 1229 { 1230 if(created) 1231 iheight = cast(int)SendMessageA(hwnd, TVM_GETITEMHEIGHT, 0, 0); 1232 return iheight; 1233 } 1234 1235 1236 /// 1237 final @property void labelEdit(bool byes) // setter 1238 { 1239 if(byes) 1240 _style(_style() | TVS_EDITLABELS); 1241 else 1242 _style(_style() & ~TVS_EDITLABELS); 1243 } 1244 1245 /// ditto 1246 final @property bool labelEdit() // getter 1247 { 1248 return (_style() & TVS_EDITLABELS) != 0; 1249 } 1250 1251 1252 /// 1253 final @property TreeNodeCollection nodes() // getter 1254 { 1255 return tchildren; 1256 } 1257 1258 1259 /// 1260 final @property void pathSeparator(dchar sep) // setter 1261 { 1262 pathsep = sep; 1263 } 1264 1265 /// ditto 1266 final @property dchar pathSeparator() // getter 1267 { 1268 return pathsep; 1269 } 1270 1271 1272 /// 1273 final @property void scrollable(bool byes) // setter 1274 { 1275 if(byes) 1276 _style(_style() & ~TVS_NOSCROLL); 1277 else 1278 _style(_style() | TVS_NOSCROLL); 1279 1280 if(created) 1281 redrawEntire(); 1282 } 1283 1284 /// ditto 1285 final @property bool scrollable() // getter 1286 { 1287 return (_style & TVS_NOSCROLL) == 0; 1288 } 1289 1290 1291 /// 1292 final @property void selectedNode(TreeNode node) // setter 1293 { 1294 if(created) 1295 { 1296 if(node) 1297 { 1298 SendMessageA(hwnd, TVM_SELECTITEM, TVGN_CARET, cast(LPARAM)node.handle); 1299 } 1300 else 1301 { 1302 // Should the selection be cleared if -node- is null? 1303 //SendMessageA(hwnd, TVM_SELECTITEM, TVGN_CARET, cast(LPARAM)null); 1304 } 1305 } 1306 } 1307 1308 /// ditto 1309 final @property TreeNode selectedNode() // getter 1310 { 1311 if(created) 1312 { 1313 HTREEITEM hnode; 1314 hnode = cast(HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_CARET, cast(LPARAM)null); 1315 if(hnode) 1316 return treeNodeFromHandle(hnode); 1317 } 1318 return null; 1319 } 1320 1321 1322 /// 1323 final @property void showLines(bool byes) // setter 1324 { 1325 if(byes) 1326 _style(_style() | TVS_HASLINES); 1327 else 1328 _style(_style() & ~TVS_HASLINES); 1329 1330 _crecreate(); // ? 1331 } 1332 1333 /// ditto 1334 final @property bool showLines() // getter 1335 { 1336 return (_style() & TVS_HASLINES) != 0; 1337 } 1338 1339 1340 /// 1341 final @property void showPlusMinus(bool byes) // setter 1342 { 1343 if(byes) 1344 _style(_style() | TVS_HASBUTTONS); 1345 else 1346 _style(_style() & ~TVS_HASBUTTONS); 1347 1348 _crecreate(); // ? 1349 } 1350 1351 /// ditto 1352 final @property bool showPlusMinus() // getter 1353 { 1354 return (_style() & TVS_HASBUTTONS) != 0; 1355 } 1356 1357 1358 /// 1359 // -showPlusMinus- should be false. 1360 final @property void singleExpand(bool byes) // setter 1361 { 1362 if(byes) 1363 _style(_style() | TVS_SINGLEEXPAND); 1364 else 1365 _style(_style() & ~TVS_SINGLEEXPAND); 1366 1367 _crecreate(); // ? 1368 } 1369 1370 /// ditto 1371 final @property bool singleExpand() // getter 1372 { 1373 return (_style & TVS_SINGLEEXPAND) != 0; 1374 } 1375 1376 1377 /// 1378 final @property void showRootLines(bool byes) // setter 1379 { 1380 if(byes) 1381 _style(_style() | TVS_LINESATROOT); 1382 else 1383 _style(_style() & ~TVS_LINESATROOT); 1384 1385 _crecreate(); // ? 1386 } 1387 1388 /// ditto 1389 final @property bool showRootLines() // getter 1390 { 1391 return (_style() & TVS_LINESATROOT) != 0; 1392 } 1393 1394 1395 /// 1396 final @property void sorted(bool byes) // setter 1397 { 1398 _sort = byes; 1399 } 1400 1401 /// ditto 1402 final @property bool sorted() // getter 1403 { 1404 return _sort; 1405 } 1406 1407 1408 /// 1409 // First visible node, based on the scrolled position. 1410 final @property TreeNode topNode() // getter 1411 { 1412 if(created) 1413 { 1414 HTREEITEM hnode; 1415 hnode = cast(HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, 1416 TVGN_FIRSTVISIBLE, cast(LPARAM)null); 1417 if(hnode) 1418 return treeNodeFromHandle(hnode); 1419 } 1420 return null; 1421 } 1422 1423 1424 /// 1425 // Number of visible nodes, including partially visible. 1426 final @property int visibleCount() // getter 1427 { 1428 if(!created) 1429 return 0; 1430 return cast(int)SendMessageA(hwnd, TVM_GETVISIBLECOUNT, 0, 0); 1431 } 1432 1433 1434 /// 1435 final void beginUpdate() 1436 { 1437 SendMessageA(handle, WM_SETREDRAW, false, 0); 1438 } 1439 1440 /// ditto 1441 final void endUpdate() 1442 { 1443 SendMessageA(handle, WM_SETREDRAW, true, 0); 1444 invalidate(true); // Show updates. 1445 } 1446 1447 1448 /// 1449 final void collapseAll() 1450 { 1451 if(created) 1452 { 1453 void collapsing(TreeNodeCollection tchildren) 1454 { 1455 foreach(TreeNode node; tchildren._nodes) 1456 { 1457 SendMessageA(hwnd, TVM_EXPAND, TVE_COLLAPSE, cast(LPARAM)node.hnode); 1458 collapsing(node.tchildren); 1459 } 1460 } 1461 1462 1463 collapsing(tchildren); 1464 } 1465 } 1466 1467 1468 /// 1469 final void expandAll() 1470 { 1471 if(created) 1472 { 1473 void expanding(TreeNodeCollection tchildren) 1474 { 1475 foreach(TreeNode node; tchildren._nodes) 1476 { 1477 SendMessageA(hwnd, TVM_EXPAND, TVE_EXPAND, cast(LPARAM)node.hnode); 1478 expanding(node.tchildren); 1479 } 1480 } 1481 1482 1483 expanding(tchildren); 1484 } 1485 } 1486 1487 1488 /// 1489 final TreeNode getNodeAt(int x, int y) 1490 { 1491 if(created) 1492 { 1493 TVHITTESTINFO thi; 1494 HTREEITEM hti; 1495 thi.pt.x = x; 1496 thi.pt.y = y; 1497 hti = cast(HTREEITEM)SendMessageA(hwnd, TVM_HITTEST, 0, cast(LPARAM)&thi); 1498 if(hti) 1499 { 1500 TreeNode result; 1501 result = treeNodeFromHandle(hti); 1502 if(result) 1503 { 1504 assert(result.tview is this); 1505 return result; 1506 } 1507 } 1508 } 1509 return null; 1510 } 1511 1512 /// ditto 1513 final TreeNode getNodeAt(Point pt) 1514 { 1515 return getNodeAt(pt.x, pt.y); 1516 } 1517 1518 1519 /+ 1520 /// 1521 // TODO: finish. 1522 final int getNodeCount(bool includeSubNodes) 1523 { 1524 int result; 1525 result = tchildren.length(); 1526 1527 if(includeSubNodes) 1528 { 1529 // ... 1530 } 1531 1532 return result; 1533 } 1534 +/ 1535 1536 1537 version(DFL_NO_IMAGELIST) 1538 { 1539 } 1540 else 1541 { 1542 /// 1543 final @property void imageList(ImageList imglist) // setter 1544 { 1545 if(isHandleCreated) 1546 { 1547 prevwproc(TVM_SETIMAGELIST, TVSIL_NORMAL, 1548 cast(LPARAM)(imglist ? imglist.handle : cast(HIMAGELIST)null)); 1549 } 1550 1551 _imglist = imglist; 1552 } 1553 1554 /// ditto 1555 final @property ImageList imageList() // getter 1556 { 1557 return _imglist; 1558 } 1559 1560 1561 /+ 1562 /// 1563 // Default image index (if -1 use this). 1564 final @property void imageIndex(int index) // setter 1565 { 1566 _defimgidx = index; 1567 } 1568 1569 /// ditto 1570 final @property int imageIndex() // getter 1571 { 1572 return _defimgidx; 1573 } 1574 +/ 1575 1576 1577 /// 1578 final @property void selectedImageIndex(int index) // setter 1579 { 1580 //assert(index >= 0); 1581 assert(index >= -1); 1582 _selimgidx = index; 1583 1584 if(isHandleCreated) 1585 { 1586 TreeNode curnode = selectedNode; 1587 _crecreate(); 1588 if(curnode) 1589 curnode.ensureVisible(); 1590 } 1591 } 1592 1593 /// ditto 1594 final @property int selectedImageIndex() // getter 1595 { 1596 return _selimgidx; 1597 } 1598 } 1599 1600 1601 protected override @property Size defaultSize() // getter 1602 { 1603 return Size(120, 100); 1604 } 1605 1606 1607 /+ 1608 override void createHandle() 1609 { 1610 if(isHandleCreated) 1611 return; 1612 1613 createClassHandle(TREEVIEW_CLASSNAME); 1614 1615 onHandleCreated(EventArgs.empty); 1616 } 1617 +/ 1618 1619 1620 protected override void createParams(ref CreateParams cp) 1621 { 1622 super.createParams(cp); 1623 1624 cp.className = TREEVIEW_CLASSNAME; 1625 } 1626 1627 1628 protected override void onHandleCreated(EventArgs ea) 1629 { 1630 super.onHandleCreated(ea); 1631 1632 prevwproc(CCM_SETVERSION, 5, 0); // Fixes font size issue. 1633 1634 prevwproc(TVM_SETINDENT, ind, 0); 1635 1636 prevwproc(TVM_SETITEMHEIGHT, iheight, 0); 1637 1638 version(DFL_NO_IMAGELIST) 1639 { 1640 } 1641 else 1642 { 1643 if(_imglist) 1644 prevwproc(TVM_SETIMAGELIST, TVSIL_NORMAL, cast(LPARAM)_imglist.handle); 1645 } 1646 1647 tchildren.doNodes(); 1648 } 1649 1650 1651 protected override void onHandleDestroyed(EventArgs ea) 1652 { 1653 tchildren._resetHandles(); 1654 1655 super.onHandleDestroyed(ea); 1656 } 1657 1658 1659 protected override void wndProc(ref Message m) 1660 { 1661 // TODO: support these messages. 1662 switch(m.msg) 1663 { 1664 case TVM_INSERTITEMA: 1665 case TVM_INSERTITEMW: 1666 m.result = cast(LRESULT)null; 1667 return; 1668 1669 case TVM_SETITEMA: 1670 case TVM_SETITEMW: 1671 m.result = cast(LRESULT)-1; 1672 return; 1673 1674 case TVM_DELETEITEM: 1675 m.result = FALSE; 1676 return; 1677 1678 case TVM_SETIMAGELIST: 1679 m.result = cast(LRESULT)null; 1680 return; 1681 1682 default: 1683 } 1684 1685 super.wndProc(m); 1686 } 1687 1688 1689 protected override void prevWndProc(ref Message msg) 1690 { 1691 //msg.result = CallWindowProcA(treeviewPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam); 1692 msg.result = dfl.internal.utf.callWindowProc(treeviewPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam); 1693 } 1694 1695 1696 //TreeViewEventHandler afterCollapse; 1697 Event!(TreeView, TreeViewEventArgs) afterCollapse; /// 1698 //TreeViewEventHandler afterExpand; 1699 Event!(TreeView, TreeViewEventArgs) afterExpand; /// 1700 //TreeViewEventHandler afterSelect; 1701 Event!(TreeView, TreeViewEventArgs) afterSelect; /// 1702 //NodeLabelEditEventHandler afterLabelEdit; 1703 Event!(TreeView, NodeLabelEditEventArgs) afterLabelEdit; /// 1704 //TreeViewCancelEventHandler beforeCollapse; 1705 Event!(TreeView, TreeViewCancelEventArgs) beforeCollapse; /// 1706 //TreeViewCancelEventHandler beforeExpand; 1707 Event!(TreeView, TreeViewCancelEventArgs) beforeExpand; /// 1708 //TreeViewCancelEventHandler beforeSelect; 1709 Event!(TreeView, TreeViewCancelEventArgs) beforeSelect; /// 1710 //NodeLabelEditEventHandler beforeLabelEdit; 1711 Event!(TreeView, NodeLabelEditEventArgs) beforeLabelEdit; /// 1712 1713 1714 /// 1715 protected void onAfterCollapse(TreeViewEventArgs ea) 1716 { 1717 afterCollapse(this, ea); 1718 } 1719 1720 1721 /// 1722 protected void onAfterExpand(TreeViewEventArgs ea) 1723 { 1724 afterExpand(this, ea); 1725 } 1726 1727 1728 /// 1729 protected void onAfterSelect(TreeViewEventArgs ea) 1730 { 1731 afterSelect(this, ea); 1732 } 1733 1734 1735 /// 1736 protected void onAfterLabelEdit(NodeLabelEditEventArgs ea) 1737 { 1738 afterLabelEdit(this, ea); 1739 } 1740 1741 1742 /// 1743 protected void onBeforeCollapse(TreeViewCancelEventArgs ea) 1744 { 1745 beforeCollapse(this, ea); 1746 } 1747 1748 1749 /// 1750 protected void onBeforeExpand(TreeViewCancelEventArgs ea) 1751 { 1752 beforeExpand(this, ea); 1753 } 1754 1755 1756 /// 1757 protected void onBeforeSelect(TreeViewCancelEventArgs ea) 1758 { 1759 beforeSelect(this, ea); 1760 } 1761 1762 1763 /// 1764 protected void onBeforeLabelEdit(NodeLabelEditEventArgs ea) 1765 { 1766 beforeLabelEdit(this, ea); 1767 } 1768 1769 1770 protected override void onReflectedMessage(ref Message m) // package 1771 { 1772 super.onReflectedMessage(m); 1773 1774 switch(m.msg) 1775 { 1776 case WM_NOTIFY: 1777 { 1778 NMHDR* nmh; 1779 NM_TREEVIEW* nmtv; 1780 TreeViewCancelEventArgs cea; 1781 1782 nmh = cast(NMHDR*)m.lParam; 1783 assert(nmh.hwndFrom == hwnd); 1784 1785 switch(nmh.code) 1786 { 1787 case NM_CUSTOMDRAW: 1788 { 1789 NMTVCUSTOMDRAW* tvcd; 1790 tvcd = cast(NMTVCUSTOMDRAW*)nmh; 1791 //if(tvcd.nmcd.dwDrawStage & CDDS_ITEM) 1792 { 1793 //if(tvcd.nmcd.uItemState & CDIS_SELECTED) 1794 if((tvcd.nmcd.dwDrawStage & CDDS_ITEM) 1795 && (tvcd.nmcd.uItemState & CDIS_SELECTED)) 1796 { 1797 // Note: might not look good with custom colors. 1798 tvcd.clrText = SystemColors.highlightText.toRgb(); 1799 tvcd.clrTextBk = SystemColors.highlight.toRgb(); 1800 } 1801 else 1802 { 1803 //tvcd.clrText = foreColor.toRgb(); 1804 tvcd.clrText = foreColor.solidColor(backColor).toRgb(); 1805 tvcd.clrTextBk = backColor.toRgb(); 1806 } 1807 } 1808 m.result |= CDRF_NOTIFYITEMDRAW; // | CDRF_NOTIFYITEMERASE; 1809 1810 // This doesn't seem to be doing anything. 1811 Font fon; 1812 fon = this.font; 1813 if(fon) 1814 { 1815 SelectObject(tvcd.nmcd.hdc, fon.handle); 1816 m.result |= CDRF_NEWFONT; 1817 } 1818 } 1819 break; 1820 1821 /+ 1822 case TVN_GETDISPINFOA: 1823 1824 break; 1825 +/ 1826 1827 case TVN_SELCHANGINGW: 1828 goto sel_changing; 1829 1830 case TVN_SELCHANGINGA: 1831 if(dfl.internal.utf.useUnicode) 1832 break; 1833 sel_changing: 1834 1835 nmtv = cast(NM_TREEVIEW*)nmh; 1836 switch(nmtv.action) 1837 { 1838 case TVC_BYMOUSE: 1839 cea = new TreeViewCancelEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1840 false, TreeViewAction.BY_MOUSE); 1841 onBeforeSelect(cea); 1842 m.result = cea.cancel; 1843 break; 1844 1845 case TVC_BYKEYBOARD: 1846 cea = new TreeViewCancelEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1847 false, TreeViewAction.BY_KEYBOARD); 1848 onBeforeSelect(cea); 1849 m.result = cea.cancel; 1850 break; 1851 1852 //case TVC_UNKNOWN: 1853 default: 1854 cea = new TreeViewCancelEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1855 false, TreeViewAction.UNKNOWN); 1856 onBeforeSelect(cea); 1857 m.result = cea.cancel; 1858 } 1859 break; 1860 1861 case TVN_SELCHANGEDW: 1862 goto sel_changed; 1863 1864 case TVN_SELCHANGEDA: 1865 if(dfl.internal.utf.useUnicode) 1866 break; 1867 sel_changed: 1868 1869 nmtv = cast(NM_TREEVIEW*)nmh; 1870 switch(nmtv.action) 1871 { 1872 case TVC_BYMOUSE: 1873 onAfterSelect(new TreeViewEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1874 TreeViewAction.BY_MOUSE)); 1875 break; 1876 1877 case TVC_BYKEYBOARD: 1878 onAfterSelect(new TreeViewEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1879 TreeViewAction.BY_KEYBOARD)); 1880 break; 1881 1882 //case TVC_UNKNOWN: 1883 default: 1884 onAfterSelect(new TreeViewEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1885 TreeViewAction.UNKNOWN)); 1886 } 1887 break; 1888 1889 case TVN_ITEMEXPANDINGW: 1890 goto item_expanding; 1891 1892 case TVN_ITEMEXPANDINGA: 1893 if(dfl.internal.utf.useUnicode) 1894 break; 1895 item_expanding: 1896 1897 nmtv = cast(NM_TREEVIEW*)nmh; 1898 switch(nmtv.action) 1899 { 1900 case TVE_COLLAPSE: 1901 cea = new TreeViewCancelEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1902 false, TreeViewAction.COLLAPSE); 1903 onBeforeCollapse(cea); 1904 m.result = cea.cancel; 1905 break; 1906 1907 case TVE_EXPAND: 1908 cea = new TreeViewCancelEventArgs(cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1909 false, TreeViewAction.EXPAND); 1910 onBeforeExpand(cea); 1911 m.result = cea.cancel; 1912 break; 1913 1914 default: 1915 } 1916 break; 1917 1918 case TVN_ITEMEXPANDEDW: 1919 goto item_expanded; 1920 1921 case TVN_ITEMEXPANDEDA: 1922 if(dfl.internal.utf.useUnicode) 1923 break; 1924 item_expanded: 1925 1926 nmtv = cast(NM_TREEVIEW*)nmh; 1927 switch(nmtv.action) 1928 { 1929 case TVE_COLLAPSE: 1930 { 1931 scope TreeViewEventArgs tvea = new TreeViewEventArgs( 1932 cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1933 TreeViewAction.COLLAPSE); 1934 onAfterCollapse(tvea); 1935 } 1936 break; 1937 1938 case TVE_EXPAND: 1939 { 1940 scope TreeViewEventArgs tvea = new TreeViewEventArgs( 1941 cast(TreeNode)cast(void*)nmtv.itemNew.lParam, 1942 TreeViewAction.EXPAND); 1943 onAfterExpand(tvea); 1944 } 1945 break; 1946 1947 default: 1948 } 1949 break; 1950 1951 case TVN_BEGINLABELEDITW: 1952 goto begin_label_edit; 1953 1954 case TVN_BEGINLABELEDITA: 1955 if(dfl.internal.utf.useUnicode) 1956 break; 1957 begin_label_edit: 1958 1959 { 1960 TV_DISPINFOA* nmdi; 1961 nmdi = cast(TV_DISPINFOA*)nmh; 1962 TreeNode node; 1963 node = cast(TreeNode)cast(void*)nmdi.item.lParam; 1964 scope NodeLabelEditEventArgs nleea = new NodeLabelEditEventArgs(node); 1965 onBeforeLabelEdit(nleea); 1966 m.result = nleea.cancelEdit; 1967 } 1968 break; 1969 1970 case TVN_ENDLABELEDITW: 1971 { 1972 Dstring label; 1973 TV_DISPINFOW* nmdi; 1974 nmdi = cast(TV_DISPINFOW*)nmh; 1975 if(nmdi.item.pszText) 1976 { 1977 TreeNode node; 1978 node = cast(TreeNode)cast(void*)nmdi.item.lParam; 1979 label = fromUnicodez(nmdi.item.pszText); 1980 scope NodeLabelEditEventArgs nleea = new NodeLabelEditEventArgs(node, label); 1981 onAfterLabelEdit(nleea); 1982 if(nleea.cancelEdit) 1983 { 1984 m.result = FALSE; 1985 } 1986 else 1987 { 1988 // TODO: check if correct implementation. 1989 // Update the node's cached text.. 1990 node.ttext = label; 1991 1992 m.result = TRUE; 1993 } 1994 } 1995 } 1996 break; 1997 1998 case TVN_ENDLABELEDITA: 1999 if(dfl.internal.utf.useUnicode) 2000 { 2001 break; 2002 } 2003 else 2004 { 2005 Dstring label; 2006 TV_DISPINFOA* nmdi; 2007 nmdi = cast(TV_DISPINFOA*)nmh; 2008 if(nmdi.item.pszText) 2009 { 2010 TreeNode node; 2011 node = cast(TreeNode)cast(void*)nmdi.item.lParam; 2012 label = fromAnsiz(nmdi.item.pszText); 2013 scope NodeLabelEditEventArgs nleea = new NodeLabelEditEventArgs(node, label); 2014 onAfterLabelEdit(nleea); 2015 if(nleea.cancelEdit) 2016 { 2017 m.result = FALSE; 2018 } 2019 else 2020 { 2021 // TODO: check if correct implementation. 2022 // Update the node's cached text.. 2023 node.ttext = label; 2024 2025 m.result = TRUE; 2026 } 2027 } 2028 break; 2029 } 2030 2031 default: 2032 } 2033 } 2034 break; 2035 2036 default: 2037 } 2038 } 2039 2040 2041 private: 2042 TreeNodeCollection tchildren; 2043 int ind = 19; // Indent. 2044 dchar pathsep = '\\'; 2045 bool _sort = false; 2046 int iheight = 16; 2047 version(DFL_NO_IMAGELIST) 2048 { 2049 } 2050 else 2051 { 2052 ImageList _imglist; 2053 int _selimgidx = -1; //0; 2054 } 2055 2056 2057 TreeNode treeNodeFromHandle(HTREEITEM hnode) 2058 { 2059 TV_ITEMA ti; 2060 ti.mask = TVIF_HANDLE | TVIF_PARAM; 2061 ti.hItem = hnode; 2062 if(SendMessageA(hwnd, TVM_GETITEMA, 0, cast(LPARAM)&ti)) 2063 { 2064 return cast(TreeNode)cast(void*)ti.lParam; 2065 } 2066 return null; 2067 } 2068 2069 package: 2070 final: 2071 LRESULT prevwproc(UINT msg, WPARAM wparam, LPARAM lparam) 2072 { 2073 //return CallWindowProcA(treeviewPrevWndProc, hwnd, msg, wparam, lparam); 2074 return dfl.internal.utf.callWindowProc(treeviewPrevWndProc, hwnd, msg, wparam, lparam); 2075 } 2076 } 2077