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"
19 #include "stackframe.h"
32 * Note: Combos are probably implemented in a different way by Windows.
33 * Using a message spy for Windows, you can see some undocumented
34 * messages being passed between ComboBox and ComboLBox.
35 * I hope no programs rely on the implementation of combos.
40 #define CBLMM_EDGE 4 /* distance inside box which is same as moving mouse
41 outside box, to trigger scrolling of CBL */
43 static BOOL
CBCheckSize(HWND hwnd
);
44 static BOOL
CBLCheckSize(HWND hwnd
);
46 static HBITMAP hComboBit
= 0;
47 static WORD CBitHeight
, CBitWidth
;
49 static int COMBO_Init()
53 dprintf_combo(stddeb
, "COMBO_Init\n");
54 hComboBit
= LoadBitmap(0, MAKEINTRESOURCE(OBM_COMBO
));
55 GetObject(hComboBit
, sizeof(BITMAP
), (LPSTR
)&bm
);
56 CBitHeight
= bm
.bmHeight
;
57 CBitWidth
= bm
.bmWidth
;
61 LPHEADCOMBO
ComboGetStorageHeader(HWND hwnd
)
63 return (LPHEADCOMBO
)GetWindowLong(hwnd
,4);
66 LPHEADLIST
ComboGetListHeader(HWND hwnd
)
68 return (LPHEADLIST
)GetWindowLong(hwnd
,0);
71 int CreateComboStruct(HWND hwnd
, LONG style
)
75 lphc
= (LPHEADCOMBO
)xmalloc(sizeof(HEADCOMBO
));
76 SetWindowLong32A(hwnd
,4,(LONG
)lphc
);
81 lphc
->dwStyle
= style
;
82 lphc
->DropDownVisible
= FALSE
;
86 void ComboUpdateWindow(HWND hwnd
, LPHEADLIST lphl
, LPHEADCOMBO lphc
, BOOL repaint
)
88 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
90 if (wndPtr
->dwStyle
& WS_VSCROLL
)
91 SetScrollRange(lphc
->hWndLBox
,SB_VERT
,0,ListMaxFirstVisible(lphl
),TRUE
);
92 if (repaint
&& lphl
->bRedrawFlag
) InvalidateRect32( hwnd
, NULL
, TRUE
);
95 /***********************************************************************
98 static LRESULT
CBNCCreate(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
100 CREATESTRUCT16
*createStruct
;
102 if (!hComboBit
) COMBO_Init();
104 createStruct
= (CREATESTRUCT16
*)PTR_SEG_TO_LIN(lParam
);
105 createStruct
->style
|= WS_BORDER
;
106 SetWindowLong32A(hwnd
, GWL_STYLE
, createStruct
->style
);
108 dprintf_combo(stddeb
,"ComboBox WM_NCCREATE!\n");
109 return DefWindowProc16(hwnd
, WM_NCCREATE
, wParam
, lParam
);
113 /***********************************************************************
116 static LRESULT
CBCreate(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
121 LONG cstyle
= GetWindowLong(hwnd
,GWL_STYLE
);
122 RECT16 rect
,lboxrect
;
123 WND
* wndPtr
= WIN_FindWndPtr(hwnd
);
124 char className
[] = "COMBOLBOX"; /* Hack so that class names are > 0x10000 */
125 char editName
[] = "EDIT";
128 /* translate combo into listbox styles */
130 if (cstyle
& CBS_OWNERDRAWFIXED
) style
|= LBS_OWNERDRAWFIXED
;
131 if (cstyle
& CBS_OWNERDRAWVARIABLE
) style
|= LBS_OWNERDRAWVARIABLE
;
132 if (cstyle
& CBS_SORT
) style
|= LBS_SORT
;
133 if (cstyle
& CBS_HASSTRINGS
) style
|= LBS_HASSTRINGS
;
135 CreateListBoxStruct(hwnd
, ODT_COMBOBOX
, style
, GetParent(hwnd
));
136 CreateComboStruct(hwnd
,cstyle
);
138 lphl
= ComboGetListHeader(hwnd
);
139 lphc
= ComboGetStorageHeader(hwnd
);
141 GetClientRect16(hwnd
,&rect
);
142 lphc
->LBoxTop
= lphl
->StdItemHeight
;
146 case CBS_SIMPLE
: /* edit control, list always visible */
148 dprintf_combo(stddeb
,"CBS_SIMPLE\n");
149 style
= WS_BORDER
| WS_CHILD
| WS_VISIBLE
| WS_VSCROLL
;
150 SetRectEmpty16(&lphc
->RectButton
);
154 case CBS_DROPDOWNLIST
: /* static control, dropdown listbox */
155 case CBS_DROPDOWN
: /* edit control, dropdown listbox */
156 GetWindowRect16(hwnd
,&lboxrect
);
157 style
= WS_POPUP
| WS_BORDER
| WS_VSCROLL
;
158 /* FIXME: WinSight says these should be CHILD windows with the TOPMOST flag
159 * set. Wine doesn't support TOPMOST, and simply setting the WS_CHILD
160 * flag doesn't work. */
161 lphc
->RectButton
= rect
;
162 lphc
->RectButton
.left
= lphc
->RectButton
.right
- 6 - CBitWidth
;
163 lphc
->RectButton
.bottom
= lphc
->RectButton
.top
+ lphl
->StdItemHeight
;
164 SetWindowPos(hwnd
, 0, 0, 0, rect
.right
-rect
.left
+ 2*SYSMETRICS_CXBORDER
,
165 lphl
->StdItemHeight
+ 2*SYSMETRICS_CYBORDER
,
166 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOSENDCHANGING
);
167 dprintf_combo(stddeb
,(cstyle
& 3)==CBS_DROPDOWN
? "CBS_DROPDOWN\n": "CBS_DROPDOWNLIST\n");
170 default: fprintf(stderr
,"COMBOBOX error: bad class style!\n");
174 if ((cstyle
& 3) != CBS_DROPDOWNLIST
)
175 lphc
->hWndEdit
= CreateWindow16(MAKE_SEGPTR(editName
), (SEGPTR
)0,
176 WS_CHILD
| WS_CLIPCHILDREN
| WS_VISIBLE
| ES_LEFT
,
177 0, 0, rect
.right
-6-CBitWidth
,
178 lphl
->StdItemHeight
+2*SYSMETRICS_CYBORDER
,
179 hwnd
, (HMENU
)ID_EDIT
, WIN_GetWindowInstance(hwnd
), 0L);
181 lboxrect
.top
+=lphc
->LBoxTop
;
182 lphc
->hWndLBox
= CreateWindow16(MAKE_SEGPTR(className
), (SEGPTR
)0, style
|
183 ((cstyle
& WS_HSCROLL
)? WS_HSCROLL
: 0) |
184 ((cstyle
& WS_VSCROLL
)? WS_VSCROLL
: 0),
185 lboxrect
.left
, lboxrect
.top
,
186 lboxrect
.right
- lboxrect
.left
,
187 lboxrect
.bottom
- lboxrect
.top
,
188 hwndp
,(HMENU
)ID_CLB
, WIN_GetWindowInstance(hwnd
),
191 wndPtr
->dwStyle
&= ~(WS_VSCROLL
| WS_HSCROLL
);
193 dprintf_combo( stddeb
, "Combo Creation hwnd=%04x LBox=%04x Edit=%04x\n",
194 hwnd
, lphc
->hWndLBox
, lphc
->hWndEdit
);
195 dprintf_combo( stddeb
, " lbox %d,%d-%d,%d button %d,%d-%d,%d\n",
196 lboxrect
.left
, lboxrect
.top
, lboxrect
.right
, lboxrect
.bottom
,
197 lphc
->RectButton
.left
, lphc
->RectButton
.top
,
198 lphc
->RectButton
.right
, lphc
->RectButton
.bottom
);
199 dprintf_combo( stddeb
, " client %d,%d-%d,%d window %d,%d-%d,%d\n",
200 wndPtr
->rectClient
.left
, wndPtr
->rectClient
.top
,
201 wndPtr
->rectClient
.right
, wndPtr
->rectClient
.bottom
,
202 wndPtr
->rectWindow
.left
, wndPtr
->rectWindow
.top
,
203 wndPtr
->rectWindow
.right
, wndPtr
->rectWindow
.bottom
);
207 /***********************************************************************
210 static LRESULT
CBDestroy(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
212 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
214 if (lphc
->hWndEdit
) DestroyWindow( lphc
->hWndEdit
);
215 if (lphc
->hWndLBox
) DestroyWindow( lphc
->hWndLBox
);
219 /***********************************************************************
222 static LRESULT
CBPaint(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
224 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
225 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
233 hdc
= BeginPaint16(hwnd
, &ps
);
235 GetClientRect16(hwnd
, &rect
);
237 /* 1 for button border */
238 rect
.right
= lphc
->RectButton
.left
- 1;
240 if (hComboBit
!= 0 && !IsRectEmpty16(&lphc
->RectButton
))
242 Rectangle(hdc
,lphc
->RectButton
.left
-1,lphc
->RectButton
.top
-1,
243 lphc
->RectButton
.right
+1,lphc
->RectButton
.bottom
+1);
244 GRAPH_DrawReliefRect(hdc
, &lphc
->RectButton
, 2, 2, FALSE
);
245 GRAPH_DrawBitmap(hdc
, hComboBit
,
246 lphc
->RectButton
.left
+ 2,lphc
->RectButton
.top
+ 2,
247 0, 0, CBitWidth
, CBitHeight
);
249 if (!IsWindowVisible(hwnd
) || !lphl
->bRedrawFlag
250 || (lphc
->dwStyle
& 3) != CBS_DROPDOWNLIST
)
252 /* we don't want to draw an entry when there is an edit control */
253 EndPaint16(hwnd
, &ps
);
257 hOldFont
= SelectObject(hdc
, lphl
->hFont
);
260 hBrush
= SendMessage32A(lphl
->hParent
, WM_CTLCOLORLISTBOX
, hdc
, hwnd
);
262 hBrush
= SendMessage16(lphl
->hParent
, WM_CTLCOLOR
, hdc
,
263 MAKELONG(hwnd
, CTLCOLOR_LISTBOX
));
265 if (hBrush
== 0) hBrush
= GetStockObject(WHITE_BRUSH
);
267 lpls
= ListBoxGetItem(lphl
,lphl
->ItemFocused
);
269 FillRect16(hdc
, &rect
, hBrush
);
270 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &rect
, ODA_DRAWENTIRE
, 0);
271 if (GetFocus() == hwnd
)
272 ListBoxDrawItem (hwnd
,lphl
, hdc
, lpls
, &rect
, ODA_FOCUS
, ODS_FOCUS
);
274 else FillRect16(hdc
, &rect
, hBrush
);
275 SelectObject(hdc
,hOldFont
);
276 EndPaint16(hwnd
, &ps
);
280 /***********************************************************************
283 static LRESULT
CBGetDlgCode(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
285 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
288 /***********************************************************************
291 static LRESULT
CBLButtonDown(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
293 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
294 SendMessage16(hwnd
,CB_SHOWDROPDOWN
,!lphc
->DropDownVisible
,0);
298 /***********************************************************************
301 static LRESULT
CBKeyDown(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
303 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
304 WORD newFocused
= lphl
->ItemFocused
;
311 newFocused
= lphl
->ItemsCount
- 1;
314 if (newFocused
> 0) newFocused
--;
323 if (newFocused
>= lphl
->ItemsCount
)
324 newFocused
= lphl
->ItemsCount
- 1;
326 ListBoxSetCurSel(lphl
, newFocused
);
327 SendMessage16(hwnd
, WM_COMMAND
,ID_CLB
,MAKELONG(0,CBN_SELCHANGE
));
328 ListBoxSendNotification(lphl
, CBN_SELCHANGE
);
330 lphl
->ItemFocused
= newFocused
;
331 ListBoxScrollToFocus(lphl
);
332 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
333 InvalidateRect32( hwnd
, NULL
, TRUE
);
338 /***********************************************************************
341 static LRESULT
CBChar(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
343 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
346 newFocused
= ListBoxFindNextMatch(lphl
, wParam
);
347 if (newFocused
== (WORD
)LB_ERR
) return 0;
349 if (newFocused
>= lphl
->ItemsCount
)
350 newFocused
= lphl
->ItemsCount
- 1;
352 ListBoxSetCurSel(lphl
, newFocused
);
353 SendMessage16(hwnd
, WM_COMMAND
,ID_CLB
,MAKELONG(0,CBN_SELCHANGE
));
354 ListBoxSendNotification(lphl
, CBN_SELCHANGE
);
355 lphl
->ItemFocused
= newFocused
;
356 ListBoxScrollToFocus(lphl
);
358 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
359 InvalidateRect32( hwnd
, NULL
, TRUE
);
364 /***********************************************************************
367 static LRESULT
CBKillFocus(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
372 /***********************************************************************
375 static LRESULT
CBSetFocus(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
380 /***********************************************************************
383 static LRESULT
CBResetContent(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
385 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
386 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
388 ListBoxResetContent(lphl
);
389 ComboUpdateWindow(hwnd
, lphl
, lphc
, TRUE
);
393 /***********************************************************************
396 static LRESULT
CBDir(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
399 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
400 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
402 wRet
= ListBoxDirectory(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
403 ComboUpdateWindow(hwnd
, lphl
, lphc
, TRUE
);
407 /***********************************************************************
410 static LRESULT
CBInsertString(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
413 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
414 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
416 if (lphl
->HasStrings
)
417 wRet
= ListBoxInsertString(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
419 wRet
= ListBoxInsertString(lphl
, wParam
, (LPSTR
)lParam
);
420 ComboUpdateWindow(hwnd
, lphl
, lphc
, TRUE
);
424 /***********************************************************************
427 static LRESULT
CBAddString(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
430 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
431 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
433 if (lphl
->HasStrings
)
434 wRet
= ListBoxAddString(lphl
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
436 wRet
= ListBoxAddString(lphl
, (LPSTR
)lParam
);
438 ComboUpdateWindow(hwnd
, lphl
, lphc
, TRUE
);
442 /***********************************************************************
445 static LRESULT
CBDeleteString(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
447 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
448 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
449 LONG lRet
= ListBoxDeleteString(lphl
,wParam
);
451 ComboUpdateWindow(hwnd
, lphl
, lphc
, TRUE
);
455 /***********************************************************************
458 static LRESULT
CBSelectString(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
460 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
463 wRet
= ListBoxFindString(lphl
, wParam
, (SEGPTR
)lParam
);
465 /* XXX add functionality here */
470 /***********************************************************************
473 static LRESULT
CBFindString(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
475 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
476 return ListBoxFindString(lphl
, wParam
, (SEGPTR
)lParam
);
479 /***********************************************************************
482 static LRESULT
CBGetCount(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
484 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
485 return lphl
->ItemsCount
;
488 /***********************************************************************
491 static LRESULT
CBSetCurSel(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
493 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
496 wRet
= ListBoxSetCurSel(lphl
, wParam
);
498 dprintf_combo(stddeb
,"CBSetCurSel: hwnd %04x wp %x lp %lx wRet %d\n",
499 hwnd
,wParam
,lParam
,wRet
);
500 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
501 InvalidateRect32( hwnd
, NULL
, TRUE
);
506 /***********************************************************************
509 static LRESULT
CBGetCurSel(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
511 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
512 return lphl
->ItemFocused
;
515 /***********************************************************************
518 static LRESULT
CBGetItemHeight(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
520 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
521 LPLISTSTRUCT lpls
= ListBoxGetItem (lphl
, wParam
);
523 if (lpls
== NULL
) return LB_ERR
;
524 return lpls
->mis
.itemHeight
;
527 /***********************************************************************
530 static LRESULT
CBSetItemHeight(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
532 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
533 return ListBoxSetItemHeight(lphl
, wParam
, lParam
);
536 /***********************************************************************
539 static LRESULT
CBSetRedraw(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
541 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
542 lphl
->bRedrawFlag
= wParam
;
546 /***********************************************************************
549 static LRESULT
CBSetFont(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
551 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
552 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
555 lphl
->hFont
= GetStockObject(SYSTEM_FONT
);
557 lphl
->hFont
= (HFONT
)wParam
;
559 SendMessage16(lphc
->hWndEdit
,WM_SETFONT
,lphl
->hFont
,0);
563 /***********************************************************************
566 static LRESULT
CBGetLBTextLen(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
568 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
569 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
,wParam
);
571 if (lpls
== NULL
|| !lphl
->HasStrings
) return LB_ERR
;
572 return strlen(lpls
->itemText
);
575 /***********************************************************************
578 static LRESULT
CBGetLBText(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
580 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
581 return ListBoxGetText(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
584 /***********************************************************************
587 static LRESULT
CBGetItemData(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
589 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
590 return ListBoxGetItemData(lphl
, wParam
);
593 /***********************************************************************
596 static LRESULT
CBSetItemData(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
598 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
599 return ListBoxSetItemData(lphl
, wParam
, lParam
);
602 /***********************************************************************
605 static LRESULT
CBShowDropDown(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
607 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
610 if ((lphc
->dwStyle
& 3) == CBS_SIMPLE
) return LB_ERR
;
613 if (wParam
!= lphc
->DropDownVisible
) {
614 lphc
->DropDownVisible
= wParam
;
615 GetWindowRect32(hwnd
,&rect
);
616 SetWindowPos(lphc
->hWndLBox
, 0, rect
.left
, rect
.top
+lphc
->LBoxTop
, 0, 0,
617 SWP_NOSIZE
| (wParam
? SWP_SHOWWINDOW
: SWP_HIDEWINDOW
));
618 if (!wParam
) SetFocus(hwnd
);
624 /***********************************************************************
627 static BOOL
CBCheckSize(HWND hwnd
)
629 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
630 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
631 LONG cstyle
= GetWindowLong(hwnd
,GWL_STYLE
);
634 if (lphc
->hWndLBox
== 0) return FALSE
;
636 GetClientRect16(hwnd
,&cRect
);
637 GetWindowRect16(hwnd
,&wRect
);
639 dprintf_combo(stddeb
,
640 "CBCheckSize: hwnd %04x Rect %d,%d-%d,%d wRect %d,%d-%d,%d\n",
641 hwnd
,cRect
.left
,cRect
.top
,cRect
.right
,cRect
.bottom
,
642 wRect
.left
,wRect
.top
,wRect
.right
,wRect
.bottom
);
643 if ((cstyle
& 3) == CBS_SIMPLE
) return TRUE
;
645 if ((cRect
.bottom
- cRect
.top
) >
646 (lphl
->StdItemHeight
+ 2*SYSMETRICS_CYBORDER
)) {
647 SetWindowPos(hwnd
, 0, 0, 0,
648 cRect
.right
-cRect
.left
,
649 lphl
->StdItemHeight
+2*SYSMETRICS_CYBORDER
,
650 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOREDRAW
| SWP_NOACTIVATE
);
651 GetClientRect16(hwnd
,&cRect
);
652 GetWindowRect16(hwnd
,&wRect
);
654 lphc
->RectButton
.right
= cRect
.right
;
655 lphc
->RectButton
.left
= cRect
.right
- 2*SYSMETRICS_CXBORDER
- 4
657 lphc
->RectButton
.top
= cRect
.top
;
658 lphc
->RectButton
.bottom
= cRect
.bottom
;
661 if (cRect
.right
< lphc
->RectButton
.left
) {
662 /* if the button is outside the window, move it in */
663 if ((wRect
.right
- wRect
.left
- 2*SYSMETRICS_CXBORDER
) == (cRect
.right
- cRect
.left
)) {
664 lphc
->RectButton
.right
= cRect
.right
;
665 lphc
->RectButton
.left
= cRect
.right
- 2*SYSMETRICS_CXBORDER
- 4
667 lphc
->RectButton
.top
= cRect
.top
;
668 lphc
->RectButton
.bottom
= cRect
.bottom
;
670 /* otherwise we need to make the client include the button */
672 SetWindowPos(hwnd
, 0, 0, 0, lphc
->RectButton
.right
,
673 lphl
->StdItemHeight
+2*SYSMETRICS_CYBORDER
,
674 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOREDRAW
| SWP_NOACTIVATE
);
681 /***********************************************************************
684 static LRESULT
CBCommand(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
686 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
687 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
691 if (lphc
->hWndEdit
) /* interdependence only used for CBS_SIMPLE and CBS_DROPDOWN styles */
695 case ID_CLB
: /* update EDIT window */
696 if (HIWORD(lParam
)==CBN_SELCHANGE
)
697 if (lphl
->HasStrings
)
699 ListBoxGetText(lphl
,lphl
->ItemFocused
, buffer
);
700 dprintf_combo(stddeb
,"CBCommand: update Edit: %s\n",buffer
);
701 SetWindowText32A( lphc
->hWndEdit
, buffer
);
704 case ID_EDIT
: /* update LISTBOX window */
705 id
=GetWindowWord(hwnd
,GWW_ID
);
706 switch (HIWORD(lParam
))
708 case EN_UPDATE
:GetWindowText32A(lphc
->hWndEdit
,buffer
,255);
711 newFocused
=ListBoxFindString(lphl
, -1, MAKE_SEGPTR(buffer
));
712 dprintf_combo(stddeb
,"CBCommand: new selection #%d is= %s\n",
714 if (newFocused
!= (WORD
)LB_ERR
)
715 { /* if found something */
716 ListBoxSetCurSel(lphl
, newFocused
);
717 ListBoxSendNotification(lphl
, CBN_SELCHANGE
);
718 InvalidateRect32(hwnd
, NULL
, TRUE
);
721 SendMessage16(GetParent(hwnd
),WM_COMMAND
,id
,
722 MAKELONG(hwnd
, CBN_EDITUPDATE
));
724 case EN_CHANGE
:SendMessage16(GetParent(hwnd
),WM_COMMAND
,id
,
725 MAKELONG(hwnd
, CBN_EDITCHANGE
));
727 case EN_ERRSPACE
:SendMessage16(GetParent(hwnd
),WM_COMMAND
,id
,
728 MAKELONG(hwnd
, CBN_ERRSPACE
));
738 /***********************************************************************
741 LRESULT
ComboBoxWndProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
744 case WM_NCCREATE
: return CBNCCreate(hwnd
, wParam
, lParam
);
745 case WM_CREATE
: return CBCreate(hwnd
, wParam
, lParam
);
746 case WM_DESTROY
: return CBDestroy(hwnd
, wParam
, lParam
);
747 case WM_GETDLGCODE
: return CBGetDlgCode(hwnd
, wParam
, lParam
);
748 case WM_KEYDOWN
: return CBKeyDown(hwnd
, wParam
, lParam
);
749 case WM_CHAR
: return CBChar(hwnd
, wParam
, lParam
);
750 case WM_SETFONT
: return CBSetFont(hwnd
, wParam
, lParam
);
751 case WM_SETREDRAW
: return CBSetRedraw(hwnd
, wParam
, lParam
);
752 case WM_PAINT
: return CBPaint(hwnd
, wParam
, lParam
);
753 case WM_LBUTTONDOWN
: return CBLButtonDown(hwnd
, wParam
, lParam
);
754 case WM_SETFOCUS
: return CBSetFocus(hwnd
, wParam
, lParam
);
755 case WM_KILLFOCUS
: return CBKillFocus(hwnd
, wParam
, lParam
);
756 case WM_SIZE
: return CBCheckSize(hwnd
);
757 case WM_COMMAND
: return CBCommand(hwnd
, wParam
, lParam
);
758 case CB_RESETCONTENT
: return CBResetContent(hwnd
, wParam
, lParam
);
759 case CB_DIR
: return CBDir(hwnd
, wParam
, lParam
);
760 case CB_ADDSTRING
: return CBAddString(hwnd
, wParam
, lParam
);
761 case CB_INSERTSTRING
: return CBInsertString(hwnd
, wParam
, lParam
);
762 case CB_DELETESTRING
: return CBDeleteString(hwnd
, wParam
, lParam
);
763 case CB_FINDSTRING
: return CBFindString(hwnd
, wParam
, lParam
);
764 case CB_GETCOUNT
: return CBGetCount(hwnd
, wParam
, lParam
);
765 case CB_GETCURSEL
: return CBGetCurSel(hwnd
, wParam
, lParam
);
766 case CB_GETITEMDATA
: return CBGetItemData(hwnd
, wParam
, lParam
);
767 case CB_GETITEMHEIGHT
: return CBGetItemHeight(hwnd
, wParam
, lParam
);
768 case CB_GETLBTEXT
: return CBGetLBText(hwnd
, wParam
, lParam
);
769 case CB_GETLBTEXTLEN
: return CBGetLBTextLen(hwnd
, wParam
, lParam
);
770 case CB_SELECTSTRING
: return CBSelectString(hwnd
, wParam
, lParam
);
771 case CB_SETITEMDATA
: return CBSetItemData(hwnd
, wParam
, lParam
);
772 case CB_SETCURSEL
: return CBSetCurSel(hwnd
, wParam
, lParam
);
773 case CB_SETITEMHEIGHT
: return CBSetItemHeight(hwnd
, wParam
, lParam
);
774 case CB_SHOWDROPDOWN
: return CBShowDropDown(hwnd
, wParam
, lParam
);
776 return DefWindowProc16(hwnd
, message
, wParam
, lParam
);
779 /*--------------------------------------------------------------------*/
780 /* ComboLBox code starts here */
782 HWND
CLBoxGetCombo(HWND hwnd
)
785 return (HWND
)GetWindowLong(hwnd
,0);
787 return (HWND
)GetWindowWord(hwnd
,0);
791 LPHEADLIST
CLBoxGetListHeader(HWND hwnd
)
793 return ComboGetListHeader(CLBoxGetCombo(hwnd
));
796 /***********************************************************************
799 static LRESULT
CBLCreate( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
801 CREATESTRUCT16
*createStruct
= (CREATESTRUCT16
*)PTR_SEG_TO_LIN(lParam
);
803 SetWindowLong(hwnd
,0,(LONG
)createStruct
->lpCreateParams
);
805 SetWindowWord(hwnd
,0,LOWORD(createStruct
->lpCreateParams
));
810 /***********************************************************************
813 static LRESULT
CBLGetDlgCode( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
815 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
818 /***********************************************************************
821 static LRESULT
CBLKeyDown( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
823 LPHEADLIST lphl
= CLBoxGetListHeader(hwnd
);
824 WORD newFocused
= lphl
->ItemFocused
;
831 newFocused
= lphl
->ItemsCount
- 1;
834 if (newFocused
> 0) newFocused
--;
840 if (newFocused
> lphl
->ItemsVisible
) {
841 newFocused
-= lphl
->ItemsVisible
;
847 newFocused
+= lphl
->ItemsVisible
;
853 if (newFocused
>= lphl
->ItemsCount
)
854 newFocused
= lphl
->ItemsCount
- 1;
856 ListBoxSetCurSel(lphl
, newFocused
);
857 ListBoxSendNotification(lphl
, CBN_SELCHANGE
);
858 SendMessage16(GetParent(hwnd
), WM_COMMAND
,ID_CLB
,MAKELONG(0,CBN_SELCHANGE
));
859 lphl
->ItemFocused
= newFocused
;
860 ListBoxScrollToFocus(lphl
);
861 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
862 InvalidateRect32( hwnd
, NULL
, TRUE
);
866 /***********************************************************************
869 static LRESULT
CBLChar( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
874 /***********************************************************************
877 static LRESULT
CBLPaint( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
879 LPHEADLIST lphl
= CLBoxGetListHeader(hwnd
);
884 WND
* wndPtr
= WIN_FindWndPtr(hwnd
);
885 HWND combohwnd
= CLBoxGetCombo(hwnd
);
891 hdc
= BeginPaint16( hwnd
, &ps
);
893 if (!IsWindowVisible(hwnd
) || !lphl
->bRedrawFlag
) {
894 EndPaint16(hwnd
, &ps
);
898 hOldFont
= SelectObject(hdc
, lphl
->hFont
);
899 /* listboxes should be white */
900 hBrush
= GetStockObject(WHITE_BRUSH
);
902 GetClientRect16(hwnd
, &rect
);
903 FillRect16(hdc
, &rect
, hBrush
);
906 lpls
= lphl
->lpFirst
;
908 lphl
->ItemsVisible
= 0;
909 for(i
= 0; i
< lphl
->ItemsCount
; i
++) {
910 if (lpls
== NULL
) break;
912 if (i
>= lphl
->FirstVisible
) {
913 height
= lpls
->mis
.itemHeight
;
914 /* must have enough room to draw entire item */
915 if (top
> (rect
.bottom
-height
+1)) break;
917 lpls
->itemRect
.top
= top
;
918 lpls
->itemRect
.bottom
= top
+ height
;
919 lpls
->itemRect
.left
= rect
.left
;
920 lpls
->itemRect
.right
= rect
.right
;
922 dprintf_listbox(stddeb
,"drawing item: %d %d %d %d %d\n",
923 rect
.left
,top
,rect
.right
,top
+height
,lpls
->itemState
);
924 if (lphl
->OwnerDrawn
) {
925 ListBoxDrawItem (combohwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_DRAWENTIRE
, 0);
927 ListBoxDrawItem (combohwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_SELECT
, ODS_SELECTED
);
929 ListBoxDrawItem (combohwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_DRAWENTIRE
,
932 if ((lphl
->ItemFocused
== i
) && GetFocus() == hwnd
)
933 ListBoxDrawItem (combohwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_FOCUS
, ODS_FOCUS
);
936 lphl
->ItemsVisible
++;
942 if (wndPtr
->dwStyle
& WS_VSCROLL
)
943 SetScrollRange(hwnd
, SB_VERT
, 0, ListMaxFirstVisible(lphl
), TRUE
);
945 SelectObject(hdc
,hOldFont
);
946 EndPaint16( hwnd
, &ps
);
951 /***********************************************************************
954 static LRESULT
CBLKillFocus( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
956 /* SendMessage16(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);*/
960 /***********************************************************************
963 static LRESULT
CBLActivate( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
965 if (wParam
== WA_INACTIVE
)
966 SendMessage16(CLBoxGetCombo(hwnd
),CB_SHOWDROPDOWN
,0,0);
970 /***********************************************************************
973 static LRESULT
CBLLButtonDown( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
975 LPHEADLIST lphl
= CLBoxGetListHeader(hwnd
);
982 lphl
->PrevFocused
= lphl
->ItemFocused
;
984 y
= ListBoxFindMouse(lphl
, LOWORD(lParam
), HIWORD(lParam
));
988 ListBoxSetCurSel(lphl
, y
);
989 ListBoxGetItemRect(lphl
, y
, &rectsel
);
991 InvalidateRect32( hwnd
, NULL
, TRUE
);
995 /***********************************************************************
998 static LRESULT
CBLLButtonUp( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1000 LPHEADLIST lphl
= CLBoxGetListHeader(hwnd
);
1002 if (GetCapture() == hwnd
) ReleaseCapture();
1006 fprintf(stdnimp
,"CBLLButtonUp: CLBoxGetListHeader returned NULL!\n");
1008 else if (lphl
->PrevFocused
!= lphl
->ItemFocused
)
1010 SendMessage16(CLBoxGetCombo(hwnd
),CB_SETCURSEL
,lphl
->ItemFocused
,0);
1011 SendMessage16(GetParent(hwnd
), WM_COMMAND
,ID_CLB
,MAKELONG(0,CBN_SELCHANGE
));
1012 ListBoxSendNotification(lphl
, CBN_SELCHANGE
);
1015 SendMessage16(CLBoxGetCombo(hwnd
),CB_SHOWDROPDOWN
,0,0);
1020 /***********************************************************************
1023 static LRESULT
CBLMouseMove( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1025 LPHEADLIST lphl
= CLBoxGetListHeader(hwnd
);
1028 RECT16 rect
, rectsel
;
1030 y
= SHIWORD(lParam
);
1031 wRet
= ListBoxFindMouse(lphl
, LOWORD(lParam
), HIWORD(lParam
));
1032 ListBoxGetItemRect(lphl
, wRet
, &rectsel
);
1033 GetClientRect16(hwnd
, &rect
);
1035 dprintf_combo(stddeb
,"CBLMouseMove: hwnd %04x wp %x lp %lx y %d if %d wret %d %d,%d-%d,%d\n",
1036 hwnd
,wParam
,lParam
,y
,lphl
->ItemFocused
,wRet
,rectsel
.left
,rectsel
.top
,rectsel
.right
,rectsel
.bottom
);
1038 if ((wParam
& MK_LBUTTON
) != 0) {
1039 if (y
< CBLMM_EDGE
) {
1040 if (lphl
->FirstVisible
> 0) {
1041 lphl
->FirstVisible
--;
1042 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1043 ListBoxSetCurSel(lphl
, wRet
);
1044 InvalidateRect32( hwnd
, NULL
, TRUE
);
1048 else if (y
>= (rect
.bottom
-CBLMM_EDGE
)) {
1049 if (lphl
->FirstVisible
< ListMaxFirstVisible(lphl
)) {
1050 lphl
->FirstVisible
++;
1051 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1052 ListBoxSetCurSel(lphl
, wRet
);
1053 InvalidateRect32( hwnd
, NULL
, TRUE
);
1058 if ((short) wRet
== lphl
->ItemFocused
) return 0;
1059 ListBoxSetCurSel(lphl
, wRet
);
1060 InvalidateRect32( hwnd
, NULL
, TRUE
);
1067 /***********************************************************************
1070 static LRESULT
CBLVScroll( HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1072 LPHEADLIST lphl
= CLBoxGetListHeader(hwnd
);
1075 y
= lphl
->FirstVisible
;
1079 if (lphl
->FirstVisible
> 0)
1080 lphl
->FirstVisible
--;
1084 lphl
->FirstVisible
++;
1088 if (lphl
->FirstVisible
> lphl
->ItemsVisible
) {
1089 lphl
->FirstVisible
-= lphl
->ItemsVisible
;
1091 lphl
->FirstVisible
= 0;
1096 lphl
->FirstVisible
+= lphl
->ItemsVisible
;
1100 lphl
->FirstVisible
= LOWORD(lParam
);
1104 if (lphl
->FirstVisible
> ListMaxFirstVisible(lphl
))
1105 lphl
->FirstVisible
= ListMaxFirstVisible(lphl
);
1107 if (y
!= lphl
->FirstVisible
) {
1108 SetScrollPos(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1109 InvalidateRect32( hwnd
, NULL
, TRUE
);
1116 /***********************************************************************
1119 static BOOL
CBLCheckSize(HWND hwnd
)
1121 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
1122 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
1125 RECT16 cRect
,wRect
,lRect
,lwRect
;
1129 GetClassName32A(hwnd
,className
,80);
1131 if (strncmp(className
,"COMBOBOX",8)) return FALSE
;
1132 if ((hWndLBox
= lphc
->hWndLBox
) == 0) return FALSE
;
1133 dprintf_combo(stddeb
,"CBLCheckSize headers hw %04x lb %04x name %s\n",
1134 hwnd
,hWndLBox
,className
);
1136 GetClientRect16(hwnd
,&cRect
);
1137 GetWindowRect16(hwnd
,&wRect
);
1138 GetClientRect16(hWndLBox
,&lRect
);
1139 GetWindowRect16(hWndLBox
,&lwRect
);
1141 dprintf_combo(stddeb
,"CBLCheckSize: init cRect %d,%d-%d,%d wRect %d,%d-%d,%d\n",
1142 cRect
.left
,cRect
.top
,cRect
.right
,cRect
.bottom
,
1143 wRect
.left
,wRect
.top
,wRect
.right
,wRect
.bottom
);
1144 dprintf_combo(stddeb
," lRect %d,%d-%d,%d lwRect %d,%d-%d,%d\n",
1145 lRect
.left
,lRect
.top
,lRect
.right
,lRect
.bottom
,
1146 lwRect
.left
,lwRect
.top
,lwRect
.right
,lwRect
.bottom
);
1150 for (lpls
=lphl
->lpFirst
; lpls
!= NULL
; lpls
=lpls
->lpNext
)
1151 totheight
+= lpls
->mis
.itemHeight
;
1153 dw
= cRect
.right
-cRect
.left
+2*SYSMETRICS_CXBORDER
+SYSMETRICS_CXVSCROLL
;
1154 dw
-= lwRect
.right
-lwRect
.left
;
1155 dw
-= SYSMETRICS_CXVSCROLL
;
1157 /* TODO: This isn't really what windows does */
1158 if ((lRect
.bottom
-lRect
.top
< 3*lphl
->StdItemHeight
) || dw
) {
1159 dprintf_combo(stddeb
," Changing; totHeight %d StdItemHght %d dw %d\n",
1160 totheight
,lphl
->StdItemHeight
,dw
);
1161 SetWindowPos(hWndLBox
, 0, lRect
.left
, lRect
.top
,
1162 lwRect
.right
-lwRect
.left
+dw
, totheight
+2*SYSMETRICS_CYBORDER
,
1163 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOREDRAW
| SWP_NOACTIVATE
);
1169 /***********************************************************************
1172 LRESULT
ComboLBoxWndProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1175 case WM_CREATE
: return CBLCreate(hwnd
, wParam
, lParam
);
1176 case WM_GETDLGCODE
: return CBLGetDlgCode(hwnd
, wParam
, lParam
);
1177 case WM_KEYDOWN
: return CBLKeyDown(hwnd
, wParam
, lParam
);
1178 case WM_CHAR
: return CBLChar(hwnd
, wParam
, lParam
);
1179 case WM_PAINT
: return CBLPaint(hwnd
, wParam
, lParam
);
1180 case WM_KILLFOCUS
: return CBLKillFocus(hwnd
, wParam
, lParam
);
1181 case WM_ACTIVATE
: return CBLActivate(hwnd
, wParam
, lParam
);
1182 case WM_LBUTTONDOWN
: return CBLLButtonDown(hwnd
, wParam
, lParam
);
1183 case WM_LBUTTONUP
: return CBLLButtonUp(hwnd
, wParam
, lParam
);
1184 case WM_MOUSEMOVE
: return CBLMouseMove(hwnd
, wParam
, lParam
);
1185 case WM_VSCROLL
: return CBLVScroll(hwnd
, wParam
, lParam
);
1186 case WM_SIZE
: return CBLCheckSize(hwnd
);
1188 return DefWindowProc16(hwnd
, message
, wParam
, lParam
);
1191 /************************************************************************
1192 * DlgDirSelectComboBox [USER.194]
1194 BOOL
DlgDirSelectComboBox(HWND hDlg
, LPSTR lpStr
, INT nIDLBox
)
1196 fprintf(stdnimp
,"DlgDirSelectComboBox(%04x, '%s', %d) \n",
1197 hDlg
, lpStr
, nIDLBox
);
1201 static INT32
COMBO_DlgDirList( HWND32 hDlg
, LPARAM path
, INT32 idCBox
,
1202 INT32 idStatic
, UINT32 wType
, BOOL32 unicode
)
1208 SendDlgItemMessage32A( hDlg
, idCBox
, CB_RESETCONTENT
, 0, 0 );
1210 res
= SendDlgItemMessage32W( hDlg
, idCBox
, CB_DIR
, wType
, path
);
1212 res
= SendDlgItemMessage32A( hDlg
, idCBox
, CB_DIR
, wType
, path
);
1216 char temp
[512] = "A:\\";
1217 int drive
= DRIVE_GetCurrentDrive();
1219 lstrcpyn( temp
+ 3, DRIVE_GetDosCwd(drive
), sizeof(temp
)-3 );
1221 SetDlgItemText32A( hDlg
, idStatic
, temp
);
1227 /***********************************************************************
1228 * DlgDirListComboBox16 (USER.195)
1230 INT16
DlgDirListComboBox16( HWND16 hDlg
, LPCSTR path
, INT16 idCBox
,
1231 INT16 idStatic
, UINT16 wType
)
1233 dprintf_combo( stddeb
,"DlgDirListComboBox16(%04x,'%s',%d,%d,%04x)\n",
1234 hDlg
, path
, idCBox
, idStatic
, wType
);
1235 return COMBO_DlgDirList( hDlg
, (LPARAM
)path
, idCBox
,
1236 idStatic
, wType
, FALSE
);
1240 /***********************************************************************
1241 * DlgDirListComboBox32A (USER32.143)
1243 INT32
DlgDirListComboBox32A( HWND32 hDlg
, LPCSTR path
, INT32 idCBox
,
1244 INT32 idStatic
, UINT32 wType
)
1246 dprintf_combo( stddeb
,"DlgDirListComboBox32A(%08x,'%s',%d,%d,%08X)\n",
1247 hDlg
, path
, idCBox
, idStatic
, wType
);
1248 return COMBO_DlgDirList( hDlg
, (LPARAM
)path
, idCBox
,
1249 idStatic
, wType
, FALSE
);
1253 /***********************************************************************
1254 * DlgDirListComboBox32W (USER32.144)
1256 INT32
DlgDirListComboBox32W( HWND32 hDlg
, LPCWSTR path
, INT32 idCBox
,
1257 INT32 idStatic
, UINT32 wType
)
1259 dprintf_combo( stddeb
,"DlgDirListComboBox32W(%08x,%p,%d,%d,%08X)\n",
1260 hDlg
, path
, idCBox
, idStatic
, wType
);
1261 return COMBO_DlgDirList( hDlg
, (LPARAM
)path
, idCBox
,
1262 idStatic
, wType
, TRUE
);