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