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