1 // Written by Christopher E. Miller 2 // See the included license.txt for copyright and license details. 3 4 5 /// 6 module dfl.combobox; 7 8 private import dfl.internal.dlib; 9 10 private import dfl.listbox, dfl.application, dfl.base, dfl.internal.winapi; 11 private import dfl.event, dfl.drawing, dfl.collections, dfl.control, 12 dfl.internal.utf; 13 14 15 private extern(Windows) void _initCombobox(); 16 17 18 /// 19 enum ComboBoxStyle: ubyte 20 { 21 DROP_DOWN, /// 22 DROP_DOWN_LIST, /// ditto 23 SIMPLE, /// ditto 24 } 25 26 27 /// 28 class ComboBox: ListControl // docmain 29 { 30 this() 31 { 32 _initCombobox(); 33 34 wstyle |= WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_HASSTRINGS; 35 wexstyle |= WS_EX_CLIENTEDGE; 36 ctrlStyle |= ControlStyles.SELECTABLE; 37 wclassStyle = comboboxClassStyle; 38 39 icollection = createItemCollection(); 40 } 41 42 43 /// 44 final @property void dropDownStyle(ComboBoxStyle ddstyle) // setter 45 { 46 LONG st; 47 st = _style() & ~(CBS_DROPDOWN | CBS_DROPDOWNLIST | CBS_SIMPLE); 48 49 final switch(ddstyle) 50 { 51 case ComboBoxStyle.DROP_DOWN: 52 _style(st | CBS_DROPDOWN); 53 break; 54 55 case ComboBoxStyle.DROP_DOWN_LIST: 56 _style(st | CBS_DROPDOWNLIST); 57 break; 58 59 case ComboBoxStyle.SIMPLE: 60 _style(st | CBS_SIMPLE); 61 break; 62 } 63 64 _crecreate(); 65 } 66 67 /// ditto 68 final @property ComboBoxStyle dropDownStyle() // getter 69 { 70 LONG st; 71 st = _style() & (CBS_DROPDOWN | CBS_DROPDOWNLIST | CBS_SIMPLE); 72 73 switch(st) 74 { 75 case CBS_DROPDOWN: 76 return ComboBoxStyle.DROP_DOWN; 77 78 case CBS_DROPDOWNLIST: 79 return ComboBoxStyle.DROP_DOWN_LIST; 80 81 case CBS_SIMPLE: 82 return ComboBoxStyle.SIMPLE; 83 default: 84 assert(0); 85 } 86 } 87 88 89 /// 90 final @property void integralHeight(bool byes) //setter 91 { 92 if(byes) 93 _style(_style() & ~CBS_NOINTEGRALHEIGHT); 94 else 95 _style(_style() | CBS_NOINTEGRALHEIGHT); 96 97 _crecreate(); 98 } 99 100 /// ditto 101 final @property bool integralHeight() // getter 102 { 103 return (_style() & CBS_NOINTEGRALHEIGHT) == 0; 104 } 105 106 107 /// 108 // This function has no effect if the drawMode is OWNER_DRAW_VARIABLE. 109 @property void itemHeight(int h) // setter 110 { 111 if(drawMode == DrawMode.OWNER_DRAW_VARIABLE) 112 return; 113 114 iheight = h; 115 116 if(isHandleCreated) 117 prevwproc(CB_SETITEMHEIGHT, 0, h); 118 } 119 120 /// ditto 121 // Return value is meaningless when drawMode is OWNER_DRAW_VARIABLE. 122 @property int itemHeight() // getter 123 { 124 /+ 125 if(drawMode == DrawMode.OWNER_DRAW_VARIABLE || !isHandleCreated) 126 return iheight; 127 128 int result = prevwproc(CB_GETITEMHEIGHT, 0, 0); 129 if(result == CB_ERR) 130 result = iheight; // ? 131 else 132 iheight = result; 133 134 return result; 135 +/ 136 return iheight; 137 } 138 139 140 /// 141 override @property void selectedIndex(int idx) // setter 142 { 143 if(isHandleCreated) 144 { 145 prevwproc(CB_SETCURSEL, cast(WPARAM)idx, 0); 146 } 147 } 148 149 /// ditto 150 override @property int selectedIndex() //getter 151 { 152 if(isHandleCreated) 153 { 154 LRESULT result; 155 result = prevwproc(CB_GETCURSEL, 0, 0); 156 if(CB_ERR != result) // Redundant. 157 return cast(int)result; 158 } 159 return -1; 160 } 161 162 163 /// 164 final @property void selectedItem(Object o) // setter 165 { 166 int i; 167 i = items.indexOf(o); 168 if(i != -1) 169 selectedIndex = i; 170 } 171 172 /// ditto 173 final @property void selectedItem(Dstring str) // setter 174 { 175 int i; 176 i = items.indexOf(str); 177 if(i != -1) 178 selectedIndex = i; 179 } 180 181 /// ditto 182 final @property Object selectedItem() // getter 183 { 184 int idx; 185 idx = selectedIndex; 186 if(idx == -1) 187 return null; 188 return items[idx]; 189 } 190 191 192 /// 193 override @property void selectedValue(Object val) // setter 194 { 195 selectedItem = val; 196 } 197 198 /// ditto 199 override @property void selectedValue(Dstring str) // setter 200 { 201 selectedItem = str; 202 } 203 204 /// ditto 205 override @property Object selectedValue() // getter 206 { 207 return selectedItem; 208 } 209 210 211 /// 212 final @property void sorted(bool byes) // setter 213 { 214 /+ 215 if(byes) 216 _style(_style() | CBS_SORT); 217 else 218 _style(_style() & ~CBS_SORT); 219 +/ 220 _sorting = byes; 221 } 222 223 /// ditto 224 final @property bool sorted() // getter 225 { 226 //return (_style() & CBS_SORT) != 0; 227 return _sorting; 228 } 229 230 231 /// 232 final void beginUpdate() 233 { 234 prevwproc(WM_SETREDRAW, false, 0); 235 } 236 237 /// ditto 238 final void endUpdate() 239 { 240 prevwproc(WM_SETREDRAW, true, 0); 241 invalidate(true); // Show updates. 242 } 243 244 245 /// 246 final int findString(Dstring str, int startIndex) 247 { 248 // TODO: find string if control not created ? 249 250 int result = NO_MATCHES; 251 252 if(isHandleCreated) 253 { 254 if(dfl.internal.utf.useUnicode) 255 result = prevwproc(CB_FINDSTRING, startIndex, cast(LPARAM)dfl.internal.utf.toUnicodez(str)); 256 else 257 result = prevwproc(CB_FINDSTRING, startIndex, cast(LPARAM)dfl.internal.utf.unsafeAnsiz(str)); 258 if(result == CB_ERR) // Redundant. 259 result = NO_MATCHES; 260 } 261 262 return result; 263 } 264 265 /// ditto 266 final int findString(Dstring str) 267 { 268 return findString(str, -1); // Start at beginning. 269 } 270 271 272 /// 273 final int findStringExact(Dstring str, int startIndex) 274 { 275 // TODO: find string if control not created ? 276 277 int result = NO_MATCHES; 278 279 if(isHandleCreated) 280 { 281 if(dfl.internal.utf.useUnicode) 282 result = prevwproc(CB_FINDSTRINGEXACT, startIndex, cast(LPARAM)dfl.internal.utf.toUnicodez(str)); 283 else 284 result = prevwproc(CB_FINDSTRINGEXACT, startIndex, cast(LPARAM)dfl.internal.utf.unsafeAnsiz(str)); 285 if(result == CB_ERR) // Redundant. 286 result = NO_MATCHES; 287 } 288 289 return result; 290 } 291 292 /// ditto 293 final int findStringExact(Dstring str) 294 { 295 return findStringExact(str, -1); // Start at beginning. 296 } 297 298 299 /// 300 final int getItemHeight(int idx) 301 { 302 int result = prevwproc(CB_GETITEMHEIGHT, idx, 0); 303 if(CB_ERR == result) 304 throw new DflException("Unable to obtain item height"); 305 return result; 306 } 307 308 309 /// 310 final @property void drawMode(DrawMode dm) // setter 311 { 312 LONG wl = _style() & ~(CBS_OWNERDRAWVARIABLE | CBS_OWNERDRAWFIXED); 313 314 final switch(dm) 315 { 316 case DrawMode.OWNER_DRAW_VARIABLE: 317 wl |= CBS_OWNERDRAWVARIABLE; 318 break; 319 320 case DrawMode.OWNER_DRAW_FIXED: 321 wl |= CBS_OWNERDRAWFIXED; 322 break; 323 324 case DrawMode.NORMAL: 325 break; 326 } 327 328 _style(wl); 329 330 _crecreate(); 331 } 332 333 /// ditto 334 final @property DrawMode drawMode() // getter 335 { 336 LONG wl = _style(); 337 338 if(wl & CBS_OWNERDRAWVARIABLE) 339 return DrawMode.OWNER_DRAW_VARIABLE; 340 if(wl & CBS_OWNERDRAWFIXED) 341 return DrawMode.OWNER_DRAW_FIXED; 342 return DrawMode.NORMAL; 343 } 344 345 346 /// 347 final void selectAll() 348 { 349 if(isHandleCreated) 350 prevwproc(CB_SETEDITSEL, 0, MAKELPARAM(0, cast(ushort)-1)); 351 } 352 353 354 /// 355 final @property void maxLength(uint len) // setter 356 { 357 if(!len) 358 lim = 0x7FFFFFFE; 359 else 360 lim = len; 361 362 if(isHandleCreated) 363 { 364 Message m; 365 m = Message(handle, CB_LIMITTEXT, cast(WPARAM)lim, 0); 366 prevWndProc(m); 367 } 368 } 369 370 /// ditto 371 final @property uint maxLength() // getter 372 { 373 return lim; 374 } 375 376 377 /// 378 final @property void selectionLength(uint len) // setter 379 { 380 if(isHandleCreated) 381 { 382 uint v1, v2; 383 prevwproc(CB_GETEDITSEL, cast(WPARAM)&v1, cast(LPARAM)&v2); 384 v2 = v1 + len; 385 prevwproc(CB_SETEDITSEL, 0, MAKELPARAM(v1, v2)); 386 } 387 } 388 389 /// ditto 390 final @property uint selectionLength() // getter 391 { 392 if(isHandleCreated) 393 { 394 uint v1, v2; 395 prevwproc(CB_GETEDITSEL, cast(WPARAM)&v1, cast(LPARAM)&v2); 396 assert(v2 >= v1); 397 return v2 - v1; 398 } 399 return 0; 400 } 401 402 403 /// 404 final @property void selectionStart(uint pos) // setter 405 { 406 if(isHandleCreated) 407 { 408 uint v1, v2; 409 prevwproc(CB_GETEDITSEL, cast(WPARAM)&v1, cast(LPARAM)&v2); 410 assert(v2 >= v1); 411 v2 = pos + (v2 - v1); 412 prevwproc(CB_SETEDITSEL, 0, MAKELPARAM(pos, v2)); 413 } 414 } 415 416 /// ditto 417 final @property uint selectionStart() // getter 418 { 419 if(isHandleCreated) 420 { 421 uint v1, v2; 422 prevwproc(CB_GETEDITSEL, cast(WPARAM)&v1, cast(LPARAM)&v2); 423 return v1; 424 } 425 return 0; 426 } 427 428 429 /// 430 // Number of characters in the textbox. 431 // This does not necessarily correspond to the number of chars; some characters use multiple chars. 432 // Return may be larger than the amount of characters. 433 // This is a lot faster than retrieving the text, but retrieving the text is completely accurate. 434 @property uint textLength() // getter 435 { 436 if(!(ctrlStyle & ControlStyles.CACHE_TEXT) && isHandleCreated) 437 //return cast(uint)SendMessageA(handle, WM_GETTEXTLENGTH, 0, 0); 438 return cast(uint)dfl.internal.utf.sendMessage(handle, WM_GETTEXTLENGTH, 0, 0); 439 return wtext.length; 440 } 441 442 443 /// 444 final @property void droppedDown(bool byes) // setter 445 { 446 if(isHandleCreated) 447 prevwproc(CB_SHOWDROPDOWN, cast(WPARAM)byes, 0); 448 } 449 450 /// ditto 451 final @property bool droppedDown() // getter 452 { 453 if(isHandleCreated) 454 return prevwproc(CB_GETDROPPEDSTATE, 0, 0) != FALSE; 455 return false; 456 } 457 458 459 /// 460 final @property void dropDownWidth(int w) // setter 461 { 462 if(dropw == w) 463 return; 464 465 if(w < 0) 466 w = 0; 467 dropw = w; 468 469 if(isHandleCreated) 470 { 471 if(dropw < width) 472 prevwproc(CB_SETDROPPEDWIDTH, width, 0); 473 else 474 prevwproc(CB_SETDROPPEDWIDTH, dropw, 0); 475 } 476 } 477 478 /// ditto 479 final @property int dropDownWidth() // getter 480 { 481 if(isHandleCreated) 482 { 483 int w; 484 w = cast(int)prevwproc(CB_GETDROPPEDWIDTH, 0, 0); 485 if(dropw != -1) 486 dropw = w; 487 return w; 488 } 489 else 490 { 491 if(dropw < width) 492 return width; 493 return dropw; 494 } 495 } 496 497 498 /// 499 final @property ObjectCollection items() // getter 500 { 501 return icollection; 502 } 503 504 505 enum DEFAULT_ITEM_HEIGHT = 13; 506 enum NO_MATCHES = CB_ERR; 507 508 509 /// 510 static class ObjectCollection 511 { 512 protected this(ComboBox lbox) 513 { 514 this.lbox = lbox; 515 } 516 517 518 protected this(ComboBox lbox, Object[] range) 519 { 520 this.lbox = lbox; 521 addRange(range); 522 } 523 524 525 protected this(ComboBox lbox, Dstring[] range) 526 { 527 this.lbox = lbox; 528 addRange(range); 529 } 530 531 532 /+ 533 protected this(ComboBox lbox, ObjectCollection range) 534 { 535 this.lbox = lbox; 536 addRange(range); 537 } 538 +/ 539 540 541 void add(Object value) 542 { 543 add2(value); 544 } 545 546 void add(Dstring value) 547 { 548 add(new ListString(value)); 549 } 550 551 552 void addRange(Object[] range) 553 { 554 if(lbox.sorted) 555 { 556 foreach(Object value; range) 557 { 558 add(value); 559 } 560 } 561 else 562 { 563 _wraparray.addRange(range); 564 } 565 } 566 567 void addRange(Dstring[] range) 568 { 569 foreach(Dstring s; range) 570 { 571 add(s); 572 } 573 } 574 575 576 private: 577 578 ComboBox lbox; 579 Object[] _items; 580 581 582 this() 583 { 584 } 585 586 587 LRESULT insert2(WPARAM idx, Dstring val) 588 { 589 insert(idx, val); 590 return idx; 591 } 592 593 594 LRESULT add2(Object val) 595 { 596 int i; 597 if(lbox.sorted) 598 { 599 for(i = 0; i != _items.length; i++) 600 { 601 if(val < _items[i]) 602 break; 603 } 604 } 605 else 606 { 607 i = _items.length; 608 } 609 610 insert(i, val); 611 612 return i; 613 } 614 615 616 LRESULT add2(Dstring val) 617 { 618 return add2(new ListString(val)); 619 } 620 621 622 void _added(size_t idx, Object val) 623 { 624 if(lbox.isHandleCreated) 625 { 626 if(dfl.internal.utf.useUnicode) 627 lbox.prevwproc(CB_INSERTSTRING, idx, cast(LPARAM)dfl.internal.utf.toUnicodez(getObjectString(val))); 628 else 629 lbox.prevwproc(CB_INSERTSTRING, idx, cast(LPARAM)dfl.internal.utf.toAnsiz(getObjectString(val))); // Can this be unsafeAnsiz()? 630 } 631 } 632 633 634 void _removed(size_t idx, Object val) 635 { 636 if(size_t.max == idx) // Clear all. 637 { 638 if(lbox.isHandleCreated) 639 { 640 lbox.prevwproc(CB_RESETCONTENT, 0, 0); 641 } 642 } 643 else 644 { 645 if(lbox.isHandleCreated) 646 { 647 lbox.prevwproc(CB_DELETESTRING, cast(WPARAM)idx, 0); 648 } 649 } 650 } 651 652 653 public: 654 655 mixin ListWrapArray!(Object, _items, 656 _blankListCallback!(Object), _added, 657 _blankListCallback!(Object), _removed, 658 true, false, false) _wraparray; 659 } 660 661 662 /// 663 protected ObjectCollection createItemCollection() 664 { 665 return new ObjectCollection(this); 666 } 667 668 669 protected override void onHandleCreated(EventArgs ea) 670 { 671 super.onHandleCreated(ea); 672 673 // Set the Ctrl ID to the HWND so that it is unique 674 // and WM_MEASUREITEM will work properly. 675 SetWindowLongA(hwnd, GWL_ID, cast(LONG)hwnd); 676 677 //prevwproc(EM_SETLIMITTEXT, cast(WPARAM)lim, 0); 678 maxLength = lim; // Call virtual function. 679 680 if(dropw < width) 681 prevwproc(CB_SETDROPPEDWIDTH, width, 0); 682 else 683 prevwproc(CB_SETDROPPEDWIDTH, dropw, 0); 684 685 if(iheight != DEFAULT_ITEM_HEIGHT) 686 prevwproc(CB_SETITEMHEIGHT, 0, iheight); 687 688 Message m; 689 m.hWnd = hwnd; 690 m.msg = CB_INSERTSTRING; 691 // Note: duplicate code. 692 if(dfl.internal.utf.useUnicode) 693 { 694 foreach(int i, Object obj; icollection._items) 695 { 696 m.wParam = i; 697 m.lParam = cast(LPARAM)dfl.internal.utf.toUnicodez(getObjectString(obj)); // <-- 698 699 prevWndProc(m); 700 //if(CB_ERR == m.result || CB_ERRSPACE == m.result) 701 if(m.result < 0) 702 throw new DflException("Unable to add combo box item"); 703 704 //prevwproc(CB_SETITEMDATA, m.result, cast(LPARAM)cast(void*)obj); 705 } 706 } 707 else 708 { 709 foreach(int i, Object obj; icollection._items) 710 { 711 m.wParam = i; 712 m.lParam = cast(LPARAM)dfl.internal.utf.toAnsiz(getObjectString(obj)); // Can this be unsafeAnsiz()? // <-- 713 714 prevWndProc(m); 715 //if(CB_ERR == m.result || CB_ERRSPACE == m.result) 716 if(m.result < 0) 717 throw new DflException("Unable to add combo box item"); 718 719 //prevwproc(CB_SETITEMDATA, m.result, cast(LPARAM)cast(void*)obj); 720 } 721 } 722 723 //redrawEntire(); 724 } 725 726 727 package final @property bool hasDropList() // getter 728 { 729 return dropDownStyle != ComboBoxStyle.SIMPLE; 730 } 731 732 733 // This is needed for the SIMPLE style. 734 protected override void onPaintBackground(PaintEventArgs pea) 735 { 736 RECT rect; 737 pea.clipRectangle.getRect(&rect); 738 FillRect(pea.graphics.handle, &rect, parent.hbrBg); // Hack. 739 } 740 741 742 override void createHandle() 743 { 744 if(isHandleCreated) 745 return; 746 747 // TODO: check if correct implementation. 748 if(hasDropList) 749 wrect.height = DEFAULT_ITEM_HEIGHT * 8; 750 751 Dstring ft; 752 ft = wtext; 753 754 super.createHandle(); 755 756 // Fix the cached window rect. 757 // This is getting screen coords, not parent coords. Why was it here, anyway? 758 //RECT rect; 759 //GetWindowRect(hwnd, &rect); 760 //wrect = Rect(&rect); 761 762 // Fix the combo box's text since the initial window 763 // text isn't put in the edit box for some reason. 764 Message m; 765 if(dfl.internal.utf.useUnicode) 766 m = Message(hwnd, WM_SETTEXT, 0, cast(LPARAM)dfl.internal.utf.toUnicodez(ft)); 767 else 768 m = Message(hwnd, WM_SETTEXT, 0, cast(LPARAM)dfl.internal.utf.toAnsiz(ft)); // Can this be unsafeAnsiz()? 769 prevWndProc(m); 770 } 771 772 773 protected override void createParams(ref CreateParams cp) 774 { 775 super.createParams(cp); 776 777 cp.className = COMBOBOX_CLASSNAME; 778 } 779 780 781 //DrawItemEventHandler drawItem; 782 Event!(ComboBox, DrawItemEventArgs) drawItem; 783 //MeasureItemEventHandler measureItem; 784 Event!(ComboBox, MeasureItemEventArgs) measureItem; 785 786 787 protected: 788 override @property Size defaultSize() // getter 789 { 790 return Size(120, 23); // ? 791 } 792 793 794 void onDrawItem(DrawItemEventArgs dieh) 795 { 796 drawItem(this, dieh); 797 } 798 799 800 void onMeasureItem(MeasureItemEventArgs miea) 801 { 802 measureItem(this, miea); 803 } 804 805 806 package final void _WmDrawItem(DRAWITEMSTRUCT* dis) 807 in 808 { 809 assert(dis.hwndItem == handle); 810 assert(dis.CtlType == ODT_COMBOBOX); 811 } 812 body 813 { 814 DrawItemState state; 815 state = cast(DrawItemState)dis.itemState; 816 817 if(dis.itemID == -1) 818 { 819 if(state & DrawItemState.FOCUS) 820 DrawFocusRect(dis.hDC, &dis.rcItem); 821 } 822 else 823 { 824 DrawItemEventArgs diea; 825 Color bc, fc; 826 827 if(state & DrawItemState.SELECTED) 828 { 829 bc = Color.systemColor(COLOR_HIGHLIGHT); 830 fc = Color.systemColor(COLOR_HIGHLIGHTTEXT); 831 } 832 else 833 { 834 bc = backColor; 835 fc = foreColor; 836 } 837 838 prepareDc(dis.hDC); 839 diea = new DrawItemEventArgs(new Graphics(dis.hDC, false), wfont, 840 Rect(&dis.rcItem), dis.itemID, state, fc, bc); 841 842 onDrawItem(diea); 843 } 844 } 845 846 847 package final void _WmMeasureItem(MEASUREITEMSTRUCT* mis) 848 in 849 { 850 assert(mis.CtlType == ODT_COMBOBOX); 851 } 852 body 853 { 854 MeasureItemEventArgs miea; 855 scope Graphics gpx = new CommonGraphics(handle(), GetDC(handle)); 856 miea = new MeasureItemEventArgs(gpx, mis.itemID, /+ mis.itemHeight +/ iheight); 857 miea.itemWidth = mis.itemWidth; 858 859 onMeasureItem(miea); 860 861 mis.itemHeight = miea.itemHeight; 862 mis.itemWidth = miea.itemWidth; 863 } 864 865 866 override void prevWndProc(ref Message msg) 867 { 868 //msg.result = CallWindowProcA(comboboxPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam); 869 msg.result = dfl.internal.utf.callWindowProc(comboboxPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam); 870 } 871 872 873 protected override void onReflectedMessage(ref Message m) 874 { 875 super.onReflectedMessage(m); 876 877 switch(m.msg) 878 { 879 case WM_DRAWITEM: 880 _WmDrawItem(cast(DRAWITEMSTRUCT*)m.lParam); 881 m.result = 1; 882 break; 883 884 case WM_MEASUREITEM: 885 _WmMeasureItem(cast(MEASUREITEMSTRUCT*)m.lParam); 886 m.result = 1; 887 break; 888 889 /+ 890 case WM_CTLCOLORSTATIC: 891 case WM_CTLCOLOREDIT: 892 /+ 893 //SetBkColor(cast(HDC)m.wParam, backColor.toRgb()); // ? 894 SetBkMode(cast(HDC)m.wParam, OPAQUE); // ? 895 +/ 896 break; 897 +/ 898 899 case WM_COMMAND: 900 //assert(cast(HWND)msg.lParam == handle); // Might be one of its children. 901 switch(HIWORD(m.wParam)) 902 { 903 case CBN_SELCHANGE: 904 /+ 905 if(drawMode != DrawMode.NORMAL) 906 { 907 // Hack. 908 Object item = selectedItem; 909 text = item ? getObjectString(item) : cast(Dstring)null; 910 } 911 +/ 912 onSelectedIndexChanged(EventArgs.empty); 913 onTextChanged(EventArgs.empty); // ? 914 break; 915 916 case CBN_SETFOCUS: 917 _wmSetFocus(); 918 break; 919 920 case CBN_KILLFOCUS: 921 _wmKillFocus(); 922 break; 923 924 case CBN_EDITCHANGE: 925 onTextChanged(EventArgs.empty); // ? 926 break; 927 928 default: 929 } 930 break; 931 932 default: 933 } 934 } 935 936 937 override void wndProc(ref Message msg) 938 { 939 switch(msg.msg) 940 { 941 case CB_ADDSTRING: 942 //msg.result = icollection.add2(stringFromStringz(cast(char*)msg.lParam).dup); // TODO: fix. 943 //msg.result = icollection.add2(stringFromStringz(cast(char*)msg.lParam).idup); // TODO: fix. // Needed in D2. Doesn't work in D1. 944 msg.result = icollection.add2(cast(Dstring)stringFromStringz(cast(char*)msg.lParam).dup); // TODO: fix. // Needed in D2. 945 return; 946 947 case CB_INSERTSTRING: 948 //msg.result = icollection.insert2(msg.wParam, stringFromStringz(cast(char*)msg.lParam).dup); // TODO: fix. 949 //msg.result = icollection.insert2(msg.wParam, stringFromStringz(cast(char*)msg.lParam).idup); // TODO: fix. // Needed in D2. Doesn't work in D1. 950 msg.result = icollection.insert2(msg.wParam, cast(Dstring)stringFromStringz(cast(char*)msg.lParam).dup); // TODO: fix. // Needed in D2. 951 return; 952 953 case CB_DELETESTRING: 954 icollection.removeAt(msg.wParam); 955 msg.result = icollection.length; 956 return; 957 958 case CB_RESETCONTENT: 959 icollection.clear(); 960 return; 961 962 case CB_SETITEMDATA: 963 // Cannot set item data from outside DFL. 964 msg.result = CB_ERR; 965 return; 966 967 case CB_DIR: 968 msg.result = CB_ERR; 969 return; 970 971 case CB_LIMITTEXT: 972 maxLength = msg.wParam; 973 return; 974 975 case WM_SETFOCUS: 976 case WM_KILLFOCUS: 977 prevWndProc(msg); 978 return; // Handled by reflected message. 979 980 default: 981 } 982 super.wndProc(msg); 983 } 984 985 986 private: 987 int iheight = DEFAULT_ITEM_HEIGHT; 988 int dropw = -1; 989 ObjectCollection icollection; 990 package uint lim = 30_000; // Documented as default. 991 bool _sorting = false; 992 993 994 package: 995 final: 996 LRESULT prevwproc(UINT msg, WPARAM wparam, LPARAM lparam) 997 { 998 //return CallWindowProcA(listviewPrevWndProc, hwnd, msg, wparam, lparam); 999 return dfl.internal.utf.callWindowProc(comboboxPrevWndProc, hwnd, msg, wparam, lparam); 1000 } 1001 } 1002