4 * Copyright 1993 Martin Ayotte
5 * Copyright 1995 Bernd Schmidt
6 * Copyright 1996 Albrecht Kleine [some fixes]
13 #include <sys/types.h>
17 #include "sysmetrics.h"
31 * Note: Combos are probably implemented in a different way by Windows.
32 * Using a message spy for Windows, you can see some undocumented
33 * messages being passed between ComboBox and ComboLBox.
34 * I hope no programs rely on the implementation of combos.
39 #define CBLMM_EDGE 4 /* distance inside box which is same as moving mouse
40 outside box, to trigger scrolling of CBL */
42 static BOOL CBCheckSize(HWND hwnd);
43 static BOOL CBLCheckSize(HWND hwnd);
45 static HBITMAP16 hComboBit = 0;
46 static WORD CBitHeight, CBitWidth;
48 static int COMBO_Init()
52 dprintf_combo(stddeb, "COMBO_Init\n");
53 hComboBit = LoadBitmap16(0, MAKEINTRESOURCE(OBM_COMBO));
54 GetObject16( hComboBit, sizeof(bm), &bm );
55 CBitHeight = bm.bmHeight;
56 CBitWidth = bm.bmWidth;
60 LPHEADCOMBO ComboGetStorageHeader(HWND hwnd)
62 return (LPHEADCOMBO)GetWindowLong32A(hwnd,4);
65 LPHEADLIST ComboGetListHeader(HWND hwnd)
67 return (LPHEADLIST)GetWindowLong32A(hwnd,0);
70 int CreateComboStruct(HWND hwnd, LONG style)
74 lphc = (LPHEADCOMBO)xmalloc(sizeof(HEADCOMBO));
75 SetWindowLong32A(hwnd,4,(LONG)lphc);
80 lphc->dwStyle = style;
81 lphc->DropDownVisible = FALSE;
85 void ComboUpdateWindow(HWND hwnd, LPHEADLIST lphl, LPHEADCOMBO lphc, BOOL repaint)
87 WND *wndPtr = WIN_FindWndPtr(hwnd);
89 if (wndPtr->dwStyle & WS_VSCROLL)
90 SetScrollRange32(lphc->hWndLBox,SB_VERT,0,ListMaxFirstVisible(lphl),TRUE);
91 if (repaint && lphl->bRedrawFlag) InvalidateRect32( hwnd, NULL, TRUE );
94 /***********************************************************************
97 static LRESULT CBNCCreate(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
99 CREATESTRUCT16 *createStruct;
101 if (!hComboBit) COMBO_Init();
103 createStruct = (CREATESTRUCT16 *)PTR_SEG_TO_LIN(lParam);
104 createStruct->style |= WS_BORDER;
105 SetWindowLong32A(hwnd, GWL_STYLE, createStruct->style);
107 dprintf_combo(stddeb,"ComboBox WM_NCCREATE!\n");
108 return DefWindowProc16(hwnd, WM_NCCREATE, wParam, lParam);
112 /***********************************************************************
115 static LRESULT CBCreate(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
120 LONG cstyle = GetWindowLong32A(hwnd,GWL_STYLE);
121 RECT16 rect,lboxrect;
122 WND* wndPtr = WIN_FindWndPtr(hwnd);
123 char className[] = "COMBOLBOX"; /* Hack so that class names are > 0x10000 */
124 char editName[] = "EDIT";
127 /* translate combo into listbox styles */
129 if (cstyle & CBS_OWNERDRAWFIXED) style |= LBS_OWNERDRAWFIXED;
130 if (cstyle & CBS_OWNERDRAWVARIABLE) style |= LBS_OWNERDRAWVARIABLE;
131 if (cstyle & CBS_SORT) style |= LBS_SORT;
132 if (cstyle & CBS_HASSTRINGS) style |= LBS_HASSTRINGS;
134 CreateListBoxStruct(hwnd, ODT_COMBOBOX, style, GetParent16(hwnd));
135 CreateComboStruct(hwnd,cstyle);
137 lphl = ComboGetListHeader(hwnd);
138 lphc = ComboGetStorageHeader(hwnd);
140 GetClientRect16(hwnd,&rect);
141 lphc->LBoxTop = lphl->StdItemHeight;
145 case CBS_SIMPLE: /* edit control, list always visible */
147 dprintf_combo(stddeb,"CBS_SIMPLE\n");
148 style= WS_BORDER | WS_CHILD | WS_VISIBLE | WS_VSCROLL;
149 SetRectEmpty16(&lphc->RectButton);
153 case CBS_DROPDOWNLIST: /* static control, dropdown listbox */
154 case CBS_DROPDOWN: /* edit control, dropdown listbox */
155 GetWindowRect16(hwnd,&lboxrect);
156 style = WS_POPUP | WS_BORDER | WS_VSCROLL;
157 /* FIXME: WinSight says these should be CHILD windows with the TOPMOST flag
158 * set. Wine doesn't support TOPMOST, and simply setting the WS_CHILD
159 * flag doesn't work. */
160 lphc->RectButton = rect;
161 lphc->RectButton.left = lphc->RectButton.right - 6 - CBitWidth;
162 lphc->RectButton.bottom = lphc->RectButton.top + lphl->StdItemHeight;
163 SetWindowPos(hwnd, 0, 0, 0, rect.right -rect.left + 2*SYSMETRICS_CXBORDER,
164 lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER,
165 SWP_NOMOVE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_NOACTIVATE);
166 dprintf_combo(stddeb,(cstyle & 3)==CBS_DROPDOWN ? "CBS_DROPDOWN\n": "CBS_DROPDOWNLIST\n");
169 default: fprintf(stderr,"COMBOBOX error: bad class style!\n");
173 if ((cstyle & 3) != CBS_DROPDOWNLIST)
174 lphc->hWndEdit = CreateWindow16( editName, NULL,
175 WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | ES_LEFT,
176 0, 0, rect.right-6-CBitWidth,
177 lphl->StdItemHeight+2*SYSMETRICS_CYBORDER,
178 hwnd, (HMENU16)ID_EDIT, WIN_GetWindowInstance(hwnd), NULL );
180 lboxrect.top+=lphc->LBoxTop;
181 lphc->hWndLBox = CreateWindow16( className, NULL, style |
182 ((cstyle & WS_HSCROLL)? WS_HSCROLL : 0) |
183 ((cstyle & WS_VSCROLL)? WS_VSCROLL : 0),
184 lboxrect.left, lboxrect.top,
185 lboxrect.right - lboxrect.left,
186 lboxrect.bottom - lboxrect.top,
187 hwndp,(HMENU16)ID_CLB, WIN_GetWindowInstance(hwnd),
188 (LPVOID)(HWND32)hwnd );
190 wndPtr->dwStyle &= ~(WS_VSCROLL | WS_HSCROLL);
192 dprintf_combo( stddeb, "Combo Creation hwnd=%04x LBox=%04x Edit=%04x\n",
193 hwnd, lphc->hWndLBox, lphc->hWndEdit);
194 dprintf_combo( stddeb, " lbox %d,%d-%d,%d button %d,%d-%d,%d\n",
195 lboxrect.left, lboxrect.top, lboxrect.right, lboxrect.bottom,
196 lphc->RectButton.left, lphc->RectButton.top,
197 lphc->RectButton.right, lphc->RectButton.bottom );
198 dprintf_combo( stddeb, " client %d,%d-%d,%d window %d,%d-%d,%d\n",
199 wndPtr->rectClient.left, wndPtr->rectClient.top,
200 wndPtr->rectClient.right, wndPtr->rectClient.bottom,
201 wndPtr->rectWindow.left, wndPtr->rectWindow.top,
202 wndPtr->rectWindow.right, wndPtr->rectWindow.bottom );
206 /***********************************************************************
209 static LRESULT CBDestroy(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
211 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
213 if (lphc->hWndEdit) DestroyWindow( lphc->hWndEdit );
214 if (lphc->hWndLBox) DestroyWindow( lphc->hWndLBox );
218 /***********************************************************************
221 static LRESULT CBPaint(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
223 LPHEADLIST lphl = ComboGetListHeader(hwnd);
224 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
232 hdc = BeginPaint16(hwnd, &ps);
234 GetClientRect16(hwnd, &rect);
236 /* 1 for button border */
237 rect.right = lphc->RectButton.left - 1;
239 if (hComboBit != 0 && !IsRectEmpty16(&lphc->RectButton))
241 Rectangle32(hdc,lphc->RectButton.left-1,lphc->RectButton.top-1,
242 lphc->RectButton.right+1,lphc->RectButton.bottom+1);
245 CONV_RECT16TO32( &lphc->RectButton, &r );
246 GRAPH_DrawReliefRect(hdc, &r, 2, 2, FALSE);
248 GRAPH_DrawBitmap(hdc, hComboBit,
249 lphc->RectButton.left + 2,lphc->RectButton.top + 2,
250 0, 0, CBitWidth, CBitHeight );
252 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag
253 || (lphc->dwStyle & 3) != CBS_DROPDOWNLIST)
255 /* we don't want to draw an entry when there is an edit control */
256 EndPaint16(hwnd, &ps);
260 hOldFont = SelectObject32(hdc, lphl->hFont);
262 hBrush = SendMessage32A( lphl->hParent, WM_CTLCOLORLISTBOX, hdc, hwnd );
263 if (hBrush == 0) hBrush = GetStockObject32(WHITE_BRUSH);
265 lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
267 FillRect16(hdc, &rect, hBrush);
268 ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
269 if (GetFocus32() == hwnd)
270 ListBoxDrawItem (hwnd,lphl, hdc, lpls, &rect, ODA_FOCUS, ODS_FOCUS);
272 else FillRect16(hdc, &rect, hBrush);
273 SelectObject32(hdc,hOldFont);
274 EndPaint16(hwnd, &ps);
278 /***********************************************************************
281 static LRESULT CBGetDlgCode(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
283 return DLGC_WANTARROWS | DLGC_WANTCHARS;
286 /***********************************************************************
289 static LRESULT CBLButtonDown(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
291 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
292 SendMessage16(hwnd,CB_SHOWDROPDOWN,!lphc->DropDownVisible,0);
296 /***********************************************************************
299 static LRESULT CBKeyDown(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
301 LPHEADLIST lphl = ComboGetListHeader(hwnd);
302 WORD newFocused = lphl->ItemFocused;
309 newFocused = lphl->ItemsCount - 1;
312 if (newFocused > 0) newFocused--;
321 if (newFocused >= lphl->ItemsCount)
322 newFocused = lphl->ItemsCount - 1;
324 ListBoxSetCurSel(lphl, newFocused);
325 SendMessage16(hwnd, WM_COMMAND,ID_CLB,MAKELONG(0,CBN_SELCHANGE));
326 ListBoxSendNotification(lphl, CBN_SELCHANGE);
328 lphl->ItemFocused = newFocused;
329 ListBoxScrollToFocus(lphl);
330 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
331 InvalidateRect32( hwnd, NULL, TRUE );
336 /***********************************************************************
339 static LRESULT CBChar(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
341 LPHEADLIST lphl = ComboGetListHeader(hwnd);
344 newFocused = ListBoxFindNextMatch(lphl, wParam);
345 if (newFocused == (WORD)LB_ERR) return 0;
347 if (newFocused >= lphl->ItemsCount)
348 newFocused = lphl->ItemsCount - 1;
350 ListBoxSetCurSel(lphl, newFocused);
351 SendMessage16(hwnd, WM_COMMAND,ID_CLB,MAKELONG(0,CBN_SELCHANGE));
352 ListBoxSendNotification(lphl, CBN_SELCHANGE);
353 lphl->ItemFocused = newFocused;
354 ListBoxScrollToFocus(lphl);
356 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
357 InvalidateRect32( hwnd, NULL, TRUE );
362 /***********************************************************************
365 static LRESULT CBKillFocus(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
370 /***********************************************************************
373 static LRESULT CBSetFocus(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
378 /***********************************************************************
381 static LRESULT CBResetContent(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
383 LPHEADLIST lphl = ComboGetListHeader(hwnd);
384 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
386 ListBoxResetContent(lphl);
387 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
391 /***********************************************************************
394 static LRESULT CBDir(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
397 LPHEADLIST lphl = ComboGetListHeader(hwnd);
398 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
400 wRet = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
401 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
405 /***********************************************************************
408 static LRESULT CBInsertString(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
411 LPHEADLIST lphl = ComboGetListHeader(hwnd);
412 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
414 if (lphl->HasStrings)
415 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
417 wRet = ListBoxInsertString(lphl, wParam, (LPSTR)lParam);
418 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
422 /***********************************************************************
425 static LRESULT CBAddString(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
428 LPHEADLIST lphl = ComboGetListHeader(hwnd);
429 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
431 wRet = ListBoxAddString(lphl, (SEGPTR)lParam);
433 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
437 /***********************************************************************
440 static LRESULT CBDeleteString(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
442 LPHEADLIST lphl = ComboGetListHeader(hwnd);
443 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
444 LONG lRet = ListBoxDeleteString(lphl,wParam);
446 ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
450 /***********************************************************************
453 static LRESULT CBSelectString(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
455 LPHEADLIST lphl = ComboGetListHeader(hwnd);
458 wRet = ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
460 /* XXX add functionality here */
465 /***********************************************************************
468 static LRESULT CBFindString(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
470 LPHEADLIST lphl = ComboGetListHeader(hwnd);
471 return ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
474 /***********************************************************************
477 static LRESULT CBFindStringExact(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
479 LPHEADLIST lphl = ComboGetListHeader(hwnd);
480 return ListBoxFindStringExact(lphl, wParam, (SEGPTR)lParam);
483 /***********************************************************************
486 static LRESULT CBGetCount(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
488 LPHEADLIST lphl = ComboGetListHeader(hwnd);
489 return lphl->ItemsCount;
492 /***********************************************************************
495 static LRESULT CBSetCurSel(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
497 LPHEADLIST lphl = ComboGetListHeader(hwnd);
500 wRet = ListBoxSetCurSel(lphl, wParam);
502 dprintf_combo(stddeb,"CBSetCurSel: hwnd %04x wp %x lp %lx wRet %d\n",
503 hwnd,wParam,lParam,wRet);
504 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
505 InvalidateRect32( hwnd, NULL, TRUE );
510 /***********************************************************************
513 static LRESULT CBGetCurSel(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
515 LPHEADLIST lphl = ComboGetListHeader(hwnd);
516 return lphl->ItemFocused;
519 /***********************************************************************
522 static LRESULT CBGetItemHeight(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
524 LPHEADLIST lphl = ComboGetListHeader(hwnd);
525 LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
527 if (lpls == NULL) return LB_ERR;
528 return lpls->mis.itemHeight;
531 /***********************************************************************
534 static LRESULT CBSetItemHeight(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
536 LPHEADLIST lphl = ComboGetListHeader(hwnd);
537 return ListBoxSetItemHeight(lphl, wParam, lParam);
540 /***********************************************************************
543 static LRESULT CBSetRedraw(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
545 LPHEADLIST lphl = ComboGetListHeader(hwnd);
546 lphl->bRedrawFlag = wParam;
550 /***********************************************************************
553 static LRESULT CBSetFont(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
555 LPHEADLIST lphl = ComboGetListHeader(hwnd);
556 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
559 lphl->hFont = GetStockObject32(SYSTEM_FONT);
561 lphl->hFont = (HFONT16)wParam;
563 SendMessage16(lphc->hWndEdit,WM_SETFONT,lphl->hFont,0);
567 /***********************************************************************
570 static LRESULT CBGetLBTextLen(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
572 LPHEADLIST lphl = ComboGetListHeader(hwnd);
573 LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
575 if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
576 return strlen(lpls->itemText);
579 /***********************************************************************
582 static LRESULT CBGetLBText(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
584 LPHEADLIST lphl = ComboGetListHeader(hwnd);
585 return ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
588 /***********************************************************************
591 static LRESULT CBGetItemData(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
593 LPHEADLIST lphl = ComboGetListHeader(hwnd);
594 return ListBoxGetItemData(lphl, wParam);
597 /***********************************************************************
600 static LRESULT CBSetItemData(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
602 LPHEADLIST lphl = ComboGetListHeader(hwnd);
603 return ListBoxSetItemData(lphl, wParam, lParam);
606 /***********************************************************************
609 static LRESULT CBShowDropDown(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
611 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
614 if ((lphc->dwStyle & 3) == CBS_SIMPLE) return LB_ERR;
617 if (wParam != lphc->DropDownVisible) {
618 lphc->DropDownVisible = wParam;
619 GetWindowRect32(hwnd,&rect);
620 SetWindowPos(lphc->hWndLBox, 0, rect.left, rect.top+lphc->LBoxTop, 0, 0,
621 SWP_NOSIZE | SWP_NOACTIVATE |
622 (wParam ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
623 if (!wParam) SetFocus32(hwnd);
629 /***********************************************************************
632 static BOOL CBCheckSize(HWND hwnd)
634 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
635 LPHEADLIST lphl = ComboGetListHeader(hwnd);
636 LONG cstyle = GetWindowLong32A(hwnd,GWL_STYLE);
639 if (lphc->hWndLBox == 0) return FALSE;
641 GetClientRect16(hwnd,&cRect);
642 GetWindowRect16(hwnd,&wRect);
644 dprintf_combo(stddeb,
645 "CBCheckSize: hwnd %04x Rect %d,%d-%d,%d wRect %d,%d-%d,%d\n",
646 hwnd,cRect.left,cRect.top,cRect.right,cRect.bottom,
647 wRect.left,wRect.top,wRect.right,wRect.bottom);
648 if ((cstyle & 3) == CBS_SIMPLE) return TRUE;
650 if ((cRect.bottom - cRect.top) >
651 (lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER)) {
652 SetWindowPos(hwnd, 0, 0, 0,
653 cRect.right-cRect.left,
654 lphl->StdItemHeight+2*SYSMETRICS_CYBORDER,
655 SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE );
656 GetClientRect16(hwnd,&cRect);
657 GetWindowRect16(hwnd,&wRect);
659 lphc->RectButton.right = cRect.right;
660 lphc->RectButton.left = cRect.right - 2*SYSMETRICS_CXBORDER - 4
662 lphc->RectButton.top = cRect.top;
663 lphc->RectButton.bottom = cRect.bottom;
666 if (cRect.right < lphc->RectButton.left) {
667 /* if the button is outside the window move it in */
668 if ((wRect.right - wRect.left - 2*SYSMETRICS_CXBORDER) == (cRect.right - cRect.left)) {
669 lphc->RectButton.right = cRect.right;
670 lphc->RectButton.left = cRect.right - 2*SYSMETRICS_CXBORDER - 4
672 lphc->RectButton.top = cRect.top;
673 lphc->RectButton.bottom = cRect.bottom;
675 /* otherwise we need to make the client include the button */
677 SetWindowPos(hwnd, 0, 0, 0, lphc->RectButton.right,
678 lphl->StdItemHeight+2*SYSMETRICS_CYBORDER,
679 SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE);
681 if ((lphc->dwStyle & 3) != CBS_DROPDOWNLIST)
682 SetWindowPos(lphc->hWndEdit, 0, 0, 0, lphc->RectButton.left,
684 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
691 /***********************************************************************
694 static LRESULT CBCommand(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
696 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
697 LPHEADLIST lphl = ComboGetListHeader(hwnd);
701 if (lphc->hWndEdit) /* interdependence only used for CBS_SIMPLE and CBS_DROPDOWN styles */
705 case ID_CLB: /* update EDIT window */
706 if (HIWORD(lParam)==CBN_SELCHANGE)
707 if (lphl->HasStrings)
709 ListBoxGetText(lphl,lphl->ItemFocused, buffer);
710 dprintf_combo(stddeb,"CBCommand: update Edit: %s\n",buffer);
711 SetWindowText32A( lphc->hWndEdit, buffer );
714 case ID_EDIT: /* update LISTBOX window */
715 id=GetWindowWord(hwnd,GWW_ID);
716 switch (HIWORD(lParam))
718 case EN_UPDATE:GetWindowText32A(lphc->hWndEdit,buffer,255);
721 char *str = SEGPTR_STRDUP(buffer);
722 newFocused=ListBoxFindString(lphl, -1, SEGPTR_GET(str));
724 dprintf_combo(stddeb,"CBCommand: new selection #%d is= %s\n",
726 if (newFocused != (WORD)LB_ERR)
727 { /* if found something */
728 ListBoxSetCurSel(lphl, newFocused);
729 ListBoxSendNotification(lphl, CBN_SELCHANGE);
730 InvalidateRect32(hwnd, NULL, TRUE);
733 SendMessage16(GetParent16(hwnd),WM_COMMAND,id,
734 MAKELONG(hwnd, CBN_EDITUPDATE));
736 case EN_CHANGE:SendMessage16(GetParent16(hwnd),WM_COMMAND,id,
737 MAKELONG(hwnd, CBN_EDITCHANGE));
739 case EN_ERRSPACE:SendMessage16(GetParent16(hwnd),WM_COMMAND,id,
740 MAKELONG(hwnd, CBN_ERRSPACE));
750 /***********************************************************************
752 * Look out! Under Win32, the parameter packing is very different.
754 static LRESULT CBGetEditSel(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
756 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
758 if ((lphc->dwStyle & 3) == CBS_DROPDOWNLIST)
759 return CB_ERR; /* err, documented for CBSetEditSel */
760 return SendMessage16(lphc->hWndEdit, EM_GETSEL, 0, 0);
764 /***********************************************************************
766 * Look out! Under Win32, the parameter packing is very different.
768 static LRESULT CBSetEditSel(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
770 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
772 if ((lphc->dwStyle & 3) == CBS_DROPDOWNLIST)
774 return SendMessage16(lphc->hWndEdit, EM_SETSEL, 0, lParam);
778 /***********************************************************************
781 LRESULT ComboBoxWndProc(HWND hwnd, UINT message, WPARAM16 wParam, LPARAM lParam)
784 case WM_NCCREATE: return CBNCCreate(hwnd, wParam, lParam);
785 case WM_CREATE: return CBCreate(hwnd, wParam, lParam);
786 case WM_DESTROY: return CBDestroy(hwnd, wParam, lParam);
787 case WM_GETDLGCODE: return CBGetDlgCode(hwnd, wParam, lParam);
788 case WM_KEYDOWN: return CBKeyDown(hwnd, wParam, lParam);
789 case WM_CHAR: return CBChar(hwnd, wParam, lParam);
790 case WM_SETFONT: return CBSetFont(hwnd, wParam, lParam);
791 case WM_SETREDRAW: return CBSetRedraw(hwnd, wParam, lParam);
792 case WM_PAINT: return CBPaint(hwnd, wParam, lParam);
793 case WM_LBUTTONDOWN: return CBLButtonDown(hwnd, wParam, lParam);
794 case WM_SETFOCUS: return CBSetFocus(hwnd, wParam, lParam);
795 case WM_KILLFOCUS: return CBKillFocus(hwnd, wParam, lParam);
796 case WM_SIZE: return CBCheckSize(hwnd);
797 case WM_COMMAND: return CBCommand(hwnd, wParam, lParam);
798 case CB_RESETCONTENT: return CBResetContent(hwnd, wParam, lParam);
799 case CB_DIR: return CBDir(hwnd, wParam, lParam);
800 case CB_ADDSTRING: return CBAddString(hwnd, wParam, lParam);
801 case CB_INSERTSTRING: return CBInsertString(hwnd, wParam, lParam);
802 case CB_DELETESTRING: return CBDeleteString(hwnd, wParam, lParam);
803 case CB_FINDSTRING: return CBFindString(hwnd, wParam, lParam);
804 case CB_GETCOUNT: return CBGetCount(hwnd, wParam, lParam);
805 case CB_GETCURSEL: return CBGetCurSel(hwnd, wParam, lParam);
806 case CB_GETITEMDATA: return CBGetItemData(hwnd, wParam, lParam);
807 case CB_GETITEMHEIGHT: return CBGetItemHeight(hwnd, wParam, lParam);
808 case CB_GETLBTEXT: return CBGetLBText(hwnd, wParam, lParam);
809 case CB_GETLBTEXTLEN: return CBGetLBTextLen(hwnd, wParam, lParam);
810 case CB_SELECTSTRING: return CBSelectString(hwnd, wParam, lParam);
811 case CB_SETITEMDATA: return CBSetItemData(hwnd, wParam, lParam);
812 case CB_SETCURSEL: return CBSetCurSel(hwnd, wParam, lParam);
813 case CB_SETITEMHEIGHT: return CBSetItemHeight(hwnd, wParam, lParam);
814 case CB_SHOWDROPDOWN: return CBShowDropDown(hwnd, wParam, lParam);
815 case CB_GETEDITSEL: return CBGetEditSel(hwnd, wParam, lParam);
816 case CB_SETEDITSEL: return CBSetEditSel(hwnd, wParam, lParam);
817 case CB_FINDSTRINGEXACT: return CBFindStringExact(hwnd, wParam, lParam);
819 return DefWindowProc16(hwnd, message, wParam, lParam);
822 /*--------------------------------------------------------------------*/
823 /* ComboLBox code starts here */
825 HWND CLBoxGetCombo(HWND hwnd)
827 return (HWND)GetWindowLong32A(hwnd,0);
830 LPHEADLIST CLBoxGetListHeader(HWND hwnd)
832 return ComboGetListHeader(CLBoxGetCombo(hwnd));
835 /***********************************************************************
838 static LRESULT CBLCreate( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
840 CREATESTRUCT16 *createStruct = (CREATESTRUCT16 *)PTR_SEG_TO_LIN(lParam);
841 SetWindowLong32A(hwnd,0,(LONG)createStruct->lpCreateParams);
845 /***********************************************************************
848 static LRESULT CBLGetDlgCode( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
850 return DLGC_WANTARROWS | DLGC_WANTCHARS;
853 /***********************************************************************
856 static LRESULT CBLKeyDown( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
858 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
859 WORD newFocused = lphl->ItemFocused;
866 newFocused = lphl->ItemsCount - 1;
869 if (newFocused > 0) newFocused--;
875 if (newFocused > lphl->ItemsVisible) {
876 newFocused -= lphl->ItemsVisible;
882 newFocused += lphl->ItemsVisible;
888 if (newFocused >= lphl->ItemsCount)
889 newFocused = lphl->ItemsCount - 1;
891 ListBoxSetCurSel(lphl, newFocused);
892 ListBoxSendNotification(lphl, CBN_SELCHANGE);
893 SendMessage16(GetParent16(hwnd), WM_COMMAND,ID_CLB,MAKELONG(0,CBN_SELCHANGE));
894 lphl->ItemFocused = newFocused;
895 ListBoxScrollToFocus(lphl);
896 SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
897 InvalidateRect32( hwnd, NULL, TRUE );
901 /***********************************************************************
904 static LRESULT CBLChar( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
909 /***********************************************************************
912 static LRESULT CBLPaint( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
914 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
919 WND * wndPtr = WIN_FindWndPtr(hwnd);
920 HWND combohwnd = CLBoxGetCombo(hwnd);
926 hdc = BeginPaint16( hwnd, &ps );
928 if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
929 EndPaint16(hwnd, &ps);
933 hOldFont = SelectObject32(hdc, lphl->hFont);
934 /* listboxes should be white */
935 hBrush = GetStockObject32(WHITE_BRUSH);
937 GetClientRect16(hwnd, &rect);
938 FillRect16(hdc, &rect, hBrush);
941 lpls = lphl->lpFirst;
943 lphl->ItemsVisible = 0;
944 for(i = 0; i < lphl->ItemsCount; i++) {
945 if (lpls == NULL) break;
947 if (i >= lphl->FirstVisible) {
948 height = lpls->mis.itemHeight;
949 /* must have enough room to draw entire item */
950 if (top > (rect.bottom-height+1)) break;
952 lpls->itemRect.top = top;
953 lpls->itemRect.bottom = top + height;
954 lpls->itemRect.left = rect.left;
955 lpls->itemRect.right = rect.right;
957 dprintf_listbox(stddeb,"drawing item: %d %d %d %d %d\n",
958 rect.left,top,rect.right,top+height,lpls->itemState);
959 if (lphl->OwnerDrawn) {
960 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 0);
962 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_SELECT, ODS_SELECTED);
964 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE,
967 if ((lphl->ItemFocused == i) && GetFocus32() == hwnd)
968 ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, ODS_FOCUS);
971 lphl->ItemsVisible++;
977 if (wndPtr->dwStyle & WS_VSCROLL)
978 SetScrollRange32(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
980 SelectObject32(hdc,hOldFont);
981 EndPaint16( hwnd, &ps );
986 /***********************************************************************
989 static LRESULT CBLKillFocus( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
991 /* SendMessage16(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);*/
995 /***********************************************************************
998 static LRESULT CBLActivate( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
1000 if (wParam == WA_INACTIVE)
1001 SendMessage16(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
1005 /***********************************************************************
1008 static LRESULT CBLLButtonDown( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
1010 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
1014 /* SetFocus32(hwnd); */
1017 lphl->PrevFocused = lphl->ItemFocused;
1019 y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
1023 ListBoxSetCurSel(lphl, y);
1024 ListBoxGetItemRect(lphl, y, &rectsel);
1026 InvalidateRect32( hwnd, NULL, TRUE );
1030 /***********************************************************************
1033 static LRESULT CBLLButtonUp( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
1035 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
1037 if (GetCapture32() == hwnd) ReleaseCapture();
1041 fprintf(stdnimp,"CBLLButtonUp: CLBoxGetListHeader returned NULL!\n");
1043 else if (lphl->PrevFocused != lphl->ItemFocused)
1045 SendMessage16(CLBoxGetCombo(hwnd),CB_SETCURSEL,lphl->ItemFocused,0);
1046 SendMessage16(GetParent16(hwnd), WM_COMMAND,ID_CLB,MAKELONG(0,CBN_SELCHANGE));
1047 ListBoxSendNotification(lphl, CBN_SELCHANGE);
1050 SendMessage16(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
1055 /***********************************************************************
1058 static LRESULT CBLMouseMove( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
1060 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
1063 RECT16 rect, rectsel;
1065 y = SHIWORD(lParam);
1066 wRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
1067 ListBoxGetItemRect(lphl, wRet, &rectsel);
1068 GetClientRect16(hwnd, &rect);
1070 dprintf_combo(stddeb,"CBLMouseMove: hwnd %04x wp %x lp %lx y %d if %d wret %d %d,%d-%d,%d\n",
1071 hwnd,wParam,lParam,y,lphl->ItemFocused,wRet,rectsel.left,rectsel.top,rectsel.right,rectsel.bottom);
1073 if ((wParam & MK_LBUTTON) != 0) {
1074 if (y < CBLMM_EDGE) {
1075 if (lphl->FirstVisible > 0) {
1076 lphl->FirstVisible--;
1077 SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1078 ListBoxSetCurSel(lphl, wRet);
1079 InvalidateRect32( hwnd, NULL, TRUE );
1083 else if (y >= (rect.bottom-CBLMM_EDGE)) {
1084 if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
1085 lphl->FirstVisible++;
1086 SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1087 ListBoxSetCurSel(lphl, wRet);
1088 InvalidateRect32( hwnd, NULL, TRUE );
1093 if ((short) wRet == lphl->ItemFocused) return 0;
1094 ListBoxSetCurSel(lphl, wRet);
1095 InvalidateRect32( hwnd, NULL, TRUE );
1102 /***********************************************************************
1105 static LRESULT CBLVScroll( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
1107 LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
1110 y = lphl->FirstVisible;
1114 if (lphl->FirstVisible > 0)
1115 lphl->FirstVisible--;
1119 lphl->FirstVisible++;
1123 if (lphl->FirstVisible > lphl->ItemsVisible) {
1124 lphl->FirstVisible -= lphl->ItemsVisible;
1126 lphl->FirstVisible = 0;
1131 lphl->FirstVisible += lphl->ItemsVisible;
1135 lphl->FirstVisible = LOWORD(lParam);
1139 if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
1140 lphl->FirstVisible = ListMaxFirstVisible(lphl);
1142 if (y != lphl->FirstVisible) {
1143 SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1144 InvalidateRect32( hwnd, NULL, TRUE );
1151 /***********************************************************************
1154 static BOOL CBLCheckSize(HWND hwnd)
1156 LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
1157 LPHEADLIST lphl = ComboGetListHeader(hwnd);
1160 RECT16 cRect,wRect,lRect,lwRect;
1164 GetClassName32A(hwnd,className,80);
1166 if (strncmp(className,"COMBOBOX",8)) return FALSE;
1167 if ((hWndLBox = lphc->hWndLBox) == 0) return FALSE;
1168 dprintf_combo(stddeb,"CBLCheckSize headers hw %04x lb %04x name %s\n",
1169 hwnd,hWndLBox,className);
1171 GetClientRect16(hwnd,&cRect);
1172 GetWindowRect16(hwnd,&wRect);
1173 GetClientRect16(hWndLBox,&lRect);
1174 GetWindowRect16(hWndLBox,&lwRect);
1176 dprintf_combo(stddeb,"CBLCheckSize: init cRect %d,%d-%d,%d wRect %d,%d-%d,%d\n",
1177 cRect.left,cRect.top,cRect.right,cRect.bottom,
1178 wRect.left,wRect.top,wRect.right,wRect.bottom);
1179 dprintf_combo(stddeb," lRect %d,%d-%d,%d lwRect %d,%d-%d,%d\n",
1180 lRect.left,lRect.top,lRect.right,lRect.bottom,
1181 lwRect.left,lwRect.top,lwRect.right,lwRect.bottom);
1185 for (lpls=lphl->lpFirst; lpls != NULL; lpls=lpls->lpNext)
1186 totheight += lpls->mis.itemHeight;
1188 dw = cRect.right-cRect.left+2*SYSMETRICS_CXBORDER+SYSMETRICS_CXVSCROLL;
1189 dw -= lwRect.right-lwRect.left;
1190 dw -= SYSMETRICS_CXVSCROLL;
1192 /* TODO: This isn't really what windows does */
1193 if ((lRect.bottom-lRect.top < 3*lphl->StdItemHeight) || dw) {
1194 dprintf_combo(stddeb," Changing; totHeight %d StdItemHght %d dw %d\n",
1195 totheight,lphl->StdItemHeight,dw);
1196 SetWindowPos(hWndLBox, 0, lRect.left, lRect.top,
1197 lwRect.right-lwRect.left+dw, totheight+2*SYSMETRICS_CYBORDER,
1198 SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE );
1204 /***********************************************************************
1207 LRESULT ComboLBoxWndProc(HWND hwnd, UINT message, WPARAM16 wParam, LPARAM lParam)
1210 case WM_CREATE: return CBLCreate(hwnd, wParam, lParam);
1211 case WM_GETDLGCODE: return CBLGetDlgCode(hwnd, wParam, lParam);
1212 case WM_KEYDOWN: return CBLKeyDown(hwnd, wParam, lParam);
1213 case WM_CHAR: return CBLChar(hwnd, wParam, lParam);
1214 case WM_PAINT: return CBLPaint(hwnd, wParam, lParam);
1215 case WM_KILLFOCUS: return CBLKillFocus(hwnd, wParam, lParam);
1216 case WM_ACTIVATE: return CBLActivate(hwnd, wParam, lParam);
1217 case WM_LBUTTONDOWN: return CBLLButtonDown(hwnd, wParam, lParam);
1218 case WM_LBUTTONUP: return CBLLButtonUp(hwnd, wParam, lParam);
1219 case WM_MOUSEMOVE: return CBLMouseMove(hwnd, wParam, lParam);
1220 case WM_VSCROLL: return CBLVScroll(hwnd, wParam, lParam);
1221 case WM_SIZE: return CBLCheckSize(hwnd);
1222 case WM_MOUSEACTIVATE: /* We don't want to be activated */
1223 return MA_NOACTIVATE;
1225 return DefWindowProc16(hwnd, message, wParam, lParam);
1228 /************************************************************************
1229 * DlgDirSelectComboBox [USER.194]
1231 BOOL DlgDirSelectComboBox(HWND hDlg, LPSTR lpStr, INT nIDLBox)
1233 fprintf(stdnimp,"DlgDirSelectComboBox(%04x, '%s', %d) \n",
1234 hDlg, lpStr, nIDLBox);
1238 static INT32 COMBO_DlgDirList( HWND32 hDlg, LPARAM path, INT32 idCBox,
1239 INT32 idStatic, UINT32 wType, BOOL32 unicode )
1245 SendDlgItemMessage32A( hDlg, idCBox, CB_RESETCONTENT, 0, 0 );
1247 res = SendDlgItemMessage32W( hDlg, idCBox, CB_DIR, wType, path );
1249 res = SendDlgItemMessage32A( hDlg, idCBox, CB_DIR, wType, path );
1253 char temp[512] = "A:\\";
1254 int drive = DRIVE_GetCurrentDrive();
1256 lstrcpyn32A( temp + 3, DRIVE_GetDosCwd(drive), sizeof(temp)-3 );
1258 SetDlgItemText32A( hDlg, idStatic, temp );
1264 /***********************************************************************
1265 * DlgDirListComboBox16 (USER.195)
1267 INT16 DlgDirListComboBox16( HWND16 hDlg, SEGPTR path, INT16 idCBox,
1268 INT16 idStatic, UINT16 wType )
1270 dprintf_combo( stddeb,"DlgDirListComboBox16(%04x,%08x,%d,%d,%04x)\n",
1271 hDlg, (UINT32)path, idCBox, idStatic, wType );
1272 return COMBO_DlgDirList( hDlg, (LPARAM)path, idCBox,
1273 idStatic, wType, FALSE );
1277 /***********************************************************************
1278 * DlgDirListComboBox32A (USER32.143)
1280 INT32 DlgDirListComboBox32A( HWND32 hDlg, LPCSTR path, INT32 idCBox,
1281 INT32 idStatic, UINT32 wType )
1283 dprintf_combo( stddeb,"DlgDirListComboBox32A(%08x,'%s',%d,%d,%08X)\n",
1284 hDlg, path, idCBox, idStatic, wType );
1285 return COMBO_DlgDirList( hDlg, (LPARAM)path, idCBox,
1286 idStatic, wType, FALSE );
1290 /***********************************************************************
1291 * DlgDirListComboBox32W (USER32.144)
1293 INT32 DlgDirListComboBox32W( HWND32 hDlg, LPCWSTR path, INT32 idCBox,
1294 INT32 idStatic, UINT32 wType )
1296 dprintf_combo( stddeb,"DlgDirListComboBox32W(%08x,%p,%d,%d,%08X)\n",
1297 hDlg, path, idCBox, idStatic, wType );
1298 return COMBO_DlgDirList( hDlg, (LPARAM)path, idCBox,
1299 idStatic, wType, TRUE );