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"
30 * Note: Combos are probably implemented in a different way by Windows.
31 * Using a message spy for Windows, you can see some undocumented
32 * messages being passed between ComboBox and ComboLBox.
33 * I hope no programs rely on the implementation of combos.
38 #define CBLMM_EDGE 4 /* distance inside box which is same as moving mouse
39 outside box, to trigger scrolling of CBL */
41 static BOOL
CBCheckSize(HWND hwnd
);
42 static BOOL
CBLCheckSize(HWND hwnd
);
44 static HBITMAP16 hComboBit
= 0;
45 static WORD CBitHeight
, CBitWidth
;
47 static int COMBO_Init()
51 dprintf_combo(stddeb
, "COMBO_Init\n");
52 hComboBit
= LoadBitmap16(0, MAKEINTRESOURCE(OBM_COMBO
));
53 GetObject16( hComboBit
, sizeof(bm
), &bm
);
54 CBitHeight
= bm
.bmHeight
;
55 CBitWidth
= bm
.bmWidth
;
59 LPHEADCOMBO
ComboGetStorageHeader(HWND hwnd
)
61 return (LPHEADCOMBO
)GetWindowLong32A(hwnd
,4);
64 LPHEADLIST
ComboGetListHeader(HWND hwnd
)
66 return (LPHEADLIST
)GetWindowLong32A(hwnd
,0);
69 int CreateComboStruct(HWND hwnd
, LONG style
)
73 lphc
= (LPHEADCOMBO
)xmalloc(sizeof(HEADCOMBO
));
74 SetWindowLong32A(hwnd
,4,(LONG
)lphc
);
79 lphc
->dwStyle
= style
;
80 lphc
->DropDownVisible
= FALSE
;
84 void ComboUpdateWindow(HWND hwnd
, LPHEADLIST lphl
, LPHEADCOMBO lphc
, BOOL repaint
)
86 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
88 if (wndPtr
->dwStyle
& WS_VSCROLL
)
89 SetScrollRange32(lphc
->hWndLBox
,SB_VERT
,0,ListMaxFirstVisible(lphl
),TRUE
);
90 if (repaint
&& lphl
->bRedrawFlag
) InvalidateRect32( hwnd
, NULL
, TRUE
);
93 /***********************************************************************
96 static LRESULT
CBNCCreate(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
98 CREATESTRUCT16
*createStruct
;
100 if (!hComboBit
) COMBO_Init();
102 createStruct
= (CREATESTRUCT16
*)PTR_SEG_TO_LIN(lParam
);
103 createStruct
->style
|= WS_BORDER
;
104 SetWindowLong32A(hwnd
, GWL_STYLE
, createStruct
->style
);
106 dprintf_combo(stddeb
,"ComboBox WM_NCCREATE!\n");
107 return DefWindowProc16(hwnd
, WM_NCCREATE
, wParam
, lParam
);
111 /***********************************************************************
114 static LRESULT
CBCreate(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
119 LONG cstyle
= GetWindowLong32A(hwnd
,GWL_STYLE
);
120 RECT16 rect
,lboxrect
;
121 WND
* wndPtr
= WIN_FindWndPtr(hwnd
);
122 char className
[] = "COMBOLBOX"; /* Hack so that class names are > 0x10000 */
123 char editName
[] = "EDIT";
126 /* translate combo into listbox styles */
128 if (cstyle
& CBS_OWNERDRAWFIXED
) style
|= LBS_OWNERDRAWFIXED
;
129 if (cstyle
& CBS_OWNERDRAWVARIABLE
) style
|= LBS_OWNERDRAWVARIABLE
;
130 if (cstyle
& CBS_SORT
) style
|= LBS_SORT
;
131 if (cstyle
& CBS_HASSTRINGS
) style
|= LBS_HASSTRINGS
;
133 CreateListBoxStruct(hwnd
, ODT_COMBOBOX
, style
, GetParent16(hwnd
));
134 CreateComboStruct(hwnd
,cstyle
);
136 lphl
= ComboGetListHeader(hwnd
);
137 lphc
= ComboGetStorageHeader(hwnd
);
139 GetClientRect16(hwnd
,&rect
);
140 lphc
->LBoxTop
= lphl
->StdItemHeight
;
144 case CBS_SIMPLE
: /* edit control, list always visible */
146 dprintf_combo(stddeb
,"CBS_SIMPLE\n");
147 style
= WS_BORDER
| WS_CHILD
| WS_VISIBLE
| WS_VSCROLL
;
148 SetRectEmpty16(&lphc
->RectButton
);
152 case CBS_DROPDOWNLIST
: /* static control, dropdown listbox */
153 case CBS_DROPDOWN
: /* edit control, dropdown listbox */
154 GetWindowRect16(hwnd
,&lboxrect
);
155 style
= WS_POPUP
| WS_BORDER
| WS_VSCROLL
;
156 /* FIXME: WinSight says these should be CHILD windows with the TOPMOST flag
157 * set. Wine doesn't support TOPMOST, and simply setting the WS_CHILD
158 * flag doesn't work. */
159 lphc
->RectButton
= rect
;
160 lphc
->RectButton
.left
= lphc
->RectButton
.right
- 6 - CBitWidth
;
161 lphc
->RectButton
.bottom
= lphc
->RectButton
.top
+ lphl
->StdItemHeight
;
162 SetWindowPos(hwnd
, 0, 0, 0, rect
.right
-rect
.left
+ 2*SYSMETRICS_CXBORDER
,
163 lphl
->StdItemHeight
+ 2*SYSMETRICS_CYBORDER
,
164 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOSENDCHANGING
| SWP_NOACTIVATE
);
165 dprintf_combo(stddeb
,(cstyle
& 3)==CBS_DROPDOWN
? "CBS_DROPDOWN\n": "CBS_DROPDOWNLIST\n");
168 default: fprintf(stderr
,"COMBOBOX error: bad class style!\n");
172 if ((cstyle
& 3) != CBS_DROPDOWNLIST
)
173 lphc
->hWndEdit
= CreateWindow16( editName
, NULL
,
174 WS_CHILD
| WS_CLIPCHILDREN
| WS_VISIBLE
| ES_LEFT
,
175 0, 0, rect
.right
-6-CBitWidth
,
176 lphl
->StdItemHeight
+2*SYSMETRICS_CYBORDER
,
177 hwnd
, (HMENU16
)ID_EDIT
, WIN_GetWindowInstance(hwnd
), NULL
);
179 lboxrect
.top
+=lphc
->LBoxTop
;
180 lphc
->hWndLBox
= CreateWindow16( className
, NULL
, style
|
181 ((cstyle
& WS_HSCROLL
)? WS_HSCROLL
: 0) |
182 ((cstyle
& WS_VSCROLL
)? WS_VSCROLL
: 0),
183 lboxrect
.left
, lboxrect
.top
,
184 lboxrect
.right
- lboxrect
.left
,
185 lboxrect
.bottom
- lboxrect
.top
,
186 hwndp
,(HMENU16
)ID_CLB
, WIN_GetWindowInstance(hwnd
),
187 (LPVOID
)(HWND32
)hwnd
);
189 wndPtr
->dwStyle
&= ~(WS_VSCROLL
| WS_HSCROLL
);
191 dprintf_combo( stddeb
, "Combo Creation hwnd=%04x LBox=%04x Edit=%04x\n",
192 hwnd
, lphc
->hWndLBox
, lphc
->hWndEdit
);
193 dprintf_combo( stddeb
, " lbox %d,%d-%d,%d button %d,%d-%d,%d\n",
194 lboxrect
.left
, lboxrect
.top
, lboxrect
.right
, lboxrect
.bottom
,
195 lphc
->RectButton
.left
, lphc
->RectButton
.top
,
196 lphc
->RectButton
.right
, lphc
->RectButton
.bottom
);
197 dprintf_combo( stddeb
, " client %d,%d-%d,%d window %d,%d-%d,%d\n",
198 wndPtr
->rectClient
.left
, wndPtr
->rectClient
.top
,
199 wndPtr
->rectClient
.right
, wndPtr
->rectClient
.bottom
,
200 wndPtr
->rectWindow
.left
, wndPtr
->rectWindow
.top
,
201 wndPtr
->rectWindow
.right
, wndPtr
->rectWindow
.bottom
);
205 /***********************************************************************
208 static LRESULT
CBDestroy(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
210 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
212 if (lphc
->hWndEdit
) DestroyWindow( lphc
->hWndEdit
);
213 if (lphc
->hWndLBox
) DestroyWindow( lphc
->hWndLBox
);
217 /***********************************************************************
220 static LRESULT
CBPaint(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
222 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
223 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
231 hdc
= BeginPaint16(hwnd
, &ps
);
233 GetClientRect16(hwnd
, &rect
);
235 /* 1 for button border */
236 rect
.right
= lphc
->RectButton
.left
- 1;
238 if (hComboBit
!= 0 && !IsRectEmpty16(&lphc
->RectButton
))
240 Rectangle32(hdc
,lphc
->RectButton
.left
-1,lphc
->RectButton
.top
-1,
241 lphc
->RectButton
.right
+1,lphc
->RectButton
.bottom
+1);
244 CONV_RECT16TO32( &lphc
->RectButton
, &r
);
245 GRAPH_DrawReliefRect(hdc
, &r
, 2, 2, FALSE
);
247 GRAPH_DrawBitmap(hdc
, hComboBit
,
248 lphc
->RectButton
.left
+ 2,lphc
->RectButton
.top
+ 2,
249 0, 0, CBitWidth
, CBitHeight
);
251 if (!IsWindowVisible(hwnd
) || !lphl
->bRedrawFlag
252 || (lphc
->dwStyle
& 3) != CBS_DROPDOWNLIST
)
254 /* we don't want to draw an entry when there is an edit control */
255 EndPaint16(hwnd
, &ps
);
259 hOldFont
= SelectObject32(hdc
, lphl
->hFont
);
261 hBrush
= SendMessage32A( lphl
->hParent
, WM_CTLCOLORLISTBOX
, hdc
, hwnd
);
262 if (hBrush
== 0) hBrush
= GetStockObject32(WHITE_BRUSH
);
264 lpls
= ListBoxGetItem(lphl
,lphl
->ItemFocused
);
266 FillRect16(hdc
, &rect
, hBrush
);
267 ListBoxDrawItem (hwnd
, lphl
, hdc
, lpls
, &rect
, ODA_DRAWENTIRE
, 0);
268 if (GetFocus32() == hwnd
)
269 ListBoxDrawItem (hwnd
,lphl
, hdc
, lpls
, &rect
, ODA_FOCUS
, ODS_FOCUS
);
271 else FillRect16(hdc
, &rect
, hBrush
);
272 SelectObject32(hdc
,hOldFont
);
273 EndPaint16(hwnd
, &ps
);
277 /***********************************************************************
280 static LRESULT
CBGetDlgCode(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
282 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
285 /***********************************************************************
288 static LRESULT
CBLButtonDown(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
290 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
291 SendMessage16(hwnd
,CB_SHOWDROPDOWN16
,!lphc
->DropDownVisible
,0);
295 /***********************************************************************
298 static LRESULT
CBKeyDown(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
300 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
301 WORD newFocused
= lphl
->ItemFocused
;
308 newFocused
= lphl
->ItemsCount
- 1;
311 if (newFocused
> 0) newFocused
--;
320 if (newFocused
>= lphl
->ItemsCount
)
321 newFocused
= lphl
->ItemsCount
- 1;
323 ListBoxSetCurSel(lphl
, newFocused
);
324 SendMessage16(hwnd
, WM_COMMAND
,ID_CLB
,MAKELONG(0,CBN_SELCHANGE
));
325 ListBoxSendNotification(lphl
, CBN_SELCHANGE
);
327 lphl
->ItemFocused
= newFocused
;
328 ListBoxScrollToFocus(lphl
);
329 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
330 InvalidateRect32( hwnd
, NULL
, TRUE
);
335 /***********************************************************************
338 static LRESULT
CBChar(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
340 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
343 newFocused
= ListBoxFindNextMatch(lphl
, wParam
);
344 if (newFocused
== (WORD
)LB_ERR
) return 0;
346 if (newFocused
>= lphl
->ItemsCount
)
347 newFocused
= lphl
->ItemsCount
- 1;
349 ListBoxSetCurSel(lphl
, newFocused
);
350 SendMessage16(hwnd
, WM_COMMAND
,ID_CLB
,MAKELONG(0,CBN_SELCHANGE
));
351 ListBoxSendNotification(lphl
, CBN_SELCHANGE
);
352 lphl
->ItemFocused
= newFocused
;
353 ListBoxScrollToFocus(lphl
);
355 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
356 InvalidateRect32( hwnd
, NULL
, TRUE
);
361 /***********************************************************************
364 static LRESULT
CBKillFocus(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
369 /***********************************************************************
372 static LRESULT
CBSetFocus(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
377 /***********************************************************************
380 static LRESULT
CBResetContent(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
382 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
383 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
385 ListBoxResetContent(lphl
);
386 ComboUpdateWindow(hwnd
, lphl
, lphc
, TRUE
);
390 /***********************************************************************
393 static LRESULT
CBDir(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
396 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
397 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
399 wRet
= ListBoxDirectory(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
400 ComboUpdateWindow(hwnd
, lphl
, lphc
, TRUE
);
404 /***********************************************************************
407 static LRESULT
CBInsertString(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
410 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
411 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
413 if (lphl
->HasStrings
)
414 wRet
= ListBoxInsertString(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
416 wRet
= ListBoxInsertString(lphl
, wParam
, (LPSTR
)lParam
);
417 ComboUpdateWindow(hwnd
, lphl
, lphc
, TRUE
);
421 /***********************************************************************
424 static LRESULT
CBAddString(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
427 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
428 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
430 wRet
= ListBoxAddString(lphl
, (SEGPTR
)lParam
);
432 ComboUpdateWindow(hwnd
, lphl
, lphc
, TRUE
);
436 /***********************************************************************
439 static LRESULT
CBDeleteString(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
441 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
442 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
443 LONG lRet
= ListBoxDeleteString(lphl
,wParam
);
445 ComboUpdateWindow(hwnd
, lphl
, lphc
, TRUE
);
449 /***********************************************************************
452 static LRESULT
CBSelectString(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
454 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
457 wRet
= ListBoxFindString(lphl
, wParam
, (SEGPTR
)lParam
);
459 /* XXX add functionality here */
464 /***********************************************************************
467 static LRESULT
CBFindString(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
469 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
470 return ListBoxFindString(lphl
, wParam
, (SEGPTR
)lParam
);
473 /***********************************************************************
476 static LRESULT
CBFindStringExact(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
478 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
479 return ListBoxFindStringExact(lphl
, wParam
, (SEGPTR
)lParam
);
482 /***********************************************************************
485 static LRESULT
CBGetCount(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
487 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
488 return lphl
->ItemsCount
;
491 /***********************************************************************
494 static LRESULT
CBSetCurSel(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
496 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
499 wRet
= ListBoxSetCurSel(lphl
, wParam
);
501 dprintf_combo(stddeb
,"CBSetCurSel: hwnd %04x wp %x lp %lx wRet %d\n",
502 hwnd
,wParam
,lParam
,wRet
);
503 /* SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
504 InvalidateRect32( hwnd
, NULL
, TRUE
);
509 /***********************************************************************
512 static LRESULT
CBGetCurSel(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
514 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
515 return lphl
->ItemFocused
;
518 /***********************************************************************
521 static LRESULT
CBGetItemHeight(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
523 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
524 LPLISTSTRUCT lpls
= ListBoxGetItem (lphl
, wParam
);
526 if (lpls
== NULL
) return LB_ERR
;
527 return lpls
->mis
.itemHeight
;
530 /***********************************************************************
533 static LRESULT
CBSetItemHeight(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
535 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
536 return ListBoxSetItemHeight(lphl
, wParam
, lParam
);
539 /***********************************************************************
542 static LRESULT
CBSetRedraw(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
544 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
545 lphl
->bRedrawFlag
= wParam
;
549 /***********************************************************************
552 static LRESULT
CBSetFont(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
554 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
555 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
558 lphl
->hFont
= GetStockObject32(SYSTEM_FONT
);
560 lphl
->hFont
= (HFONT16
)wParam
;
562 SendMessage16(lphc
->hWndEdit
,WM_SETFONT
,lphl
->hFont
,0);
566 /***********************************************************************
569 static LRESULT
CBGetLBTextLen(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
571 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
572 LPLISTSTRUCT lpls
= ListBoxGetItem(lphl
,wParam
);
574 if (lpls
== NULL
|| !lphl
->HasStrings
) return LB_ERR
;
575 return strlen(lpls
->itemText
);
578 /***********************************************************************
581 static LRESULT
CBGetLBText(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
583 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
584 return ListBoxGetText(lphl
, wParam
, (LPSTR
)PTR_SEG_TO_LIN(lParam
));
587 /***********************************************************************
590 static LRESULT
CBGetItemData(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
592 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
593 return ListBoxGetItemData(lphl
, wParam
);
596 /***********************************************************************
599 static LRESULT
CBSetItemData(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
601 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
602 return ListBoxSetItemData(lphl
, wParam
, lParam
);
605 /***********************************************************************
608 static LRESULT
CBShowDropDown(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
610 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
613 if ((lphc
->dwStyle
& 3) == CBS_SIMPLE
) return LB_ERR
;
616 if (wParam
!= lphc
->DropDownVisible
) {
617 lphc
->DropDownVisible
= wParam
;
618 GetWindowRect32(hwnd
,&rect
);
619 SetWindowPos(lphc
->hWndLBox
, 0, rect
.left
, rect
.top
+lphc
->LBoxTop
, 0, 0,
620 SWP_NOSIZE
| SWP_NOACTIVATE
|
621 (wParam
? SWP_SHOWWINDOW
: SWP_HIDEWINDOW
));
622 if (!wParam
) SetFocus32(hwnd
);
628 /***********************************************************************
631 static BOOL
CBCheckSize(HWND hwnd
)
633 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
634 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
635 LONG cstyle
= GetWindowLong32A(hwnd
,GWL_STYLE
);
638 if (lphc
->hWndLBox
== 0) return FALSE
;
640 GetClientRect16(hwnd
,&cRect
);
641 GetWindowRect16(hwnd
,&wRect
);
643 dprintf_combo(stddeb
,
644 "CBCheckSize: hwnd %04x Rect %d,%d-%d,%d wRect %d,%d-%d,%d\n",
645 hwnd
,cRect
.left
,cRect
.top
,cRect
.right
,cRect
.bottom
,
646 wRect
.left
,wRect
.top
,wRect
.right
,wRect
.bottom
);
647 if ((cstyle
& 3) == CBS_SIMPLE
) return TRUE
;
649 if ((cRect
.bottom
- cRect
.top
) >
650 (lphl
->StdItemHeight
+ 2*SYSMETRICS_CYBORDER
)) {
651 SetWindowPos(hwnd
, 0, 0, 0,
652 cRect
.right
-cRect
.left
,
653 lphl
->StdItemHeight
+2*SYSMETRICS_CYBORDER
,
654 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOREDRAW
| SWP_NOACTIVATE
);
655 GetClientRect16(hwnd
,&cRect
);
656 GetWindowRect16(hwnd
,&wRect
);
658 lphc
->RectButton
.right
= cRect
.right
;
659 lphc
->RectButton
.left
= cRect
.right
- 2*SYSMETRICS_CXBORDER
- 4
661 lphc
->RectButton
.top
= cRect
.top
;
662 lphc
->RectButton
.bottom
= cRect
.bottom
;
665 if (cRect
.right
< lphc
->RectButton
.left
) {
666 /* if the button is outside the window move it in */
667 if ((wRect
.right
- wRect
.left
- 2*SYSMETRICS_CXBORDER
) == (cRect
.right
- cRect
.left
)) {
668 lphc
->RectButton
.right
= cRect
.right
;
669 lphc
->RectButton
.left
= cRect
.right
- 2*SYSMETRICS_CXBORDER
- 4
671 lphc
->RectButton
.top
= cRect
.top
;
672 lphc
->RectButton
.bottom
= cRect
.bottom
;
674 /* otherwise we need to make the client include the button */
676 SetWindowPos(hwnd
, 0, 0, 0, lphc
->RectButton
.right
,
677 lphl
->StdItemHeight
+2*SYSMETRICS_CYBORDER
,
678 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOREDRAW
| SWP_NOACTIVATE
);
680 if ((lphc
->dwStyle
& 3) != CBS_DROPDOWNLIST
)
681 SetWindowPos(lphc
->hWndEdit
, 0, 0, 0, lphc
->RectButton
.left
,
683 SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
);
690 /***********************************************************************
693 static LRESULT
CBCommand(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
695 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
696 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
700 if (lphc
->hWndEdit
) /* interdependence only used for CBS_SIMPLE and CBS_DROPDOWN styles */
704 case ID_CLB
: /* update EDIT window */
705 if (HIWORD(lParam
)==CBN_SELCHANGE
)
706 if (lphl
->HasStrings
)
708 ListBoxGetText(lphl
,lphl
->ItemFocused
, buffer
);
709 dprintf_combo(stddeb
,"CBCommand: update Edit: %s\n",buffer
);
710 SetWindowText32A( lphc
->hWndEdit
, buffer
);
713 case ID_EDIT
: /* update LISTBOX window */
714 id
=GetWindowWord(hwnd
,GWW_ID
);
715 switch (HIWORD(lParam
))
717 case EN_UPDATE
:GetWindowText32A(lphc
->hWndEdit
,buffer
,255);
720 char *str
= SEGPTR_STRDUP(buffer
);
721 newFocused
=ListBoxFindString(lphl
, -1, SEGPTR_GET(str
));
723 dprintf_combo(stddeb
,"CBCommand: new selection #%d is= %s\n",
725 if (newFocused
!= (WORD
)LB_ERR
)
726 { /* if found something */
727 ListBoxSetCurSel(lphl
, newFocused
);
728 ListBoxSendNotification(lphl
, CBN_SELCHANGE
);
729 InvalidateRect32(hwnd
, NULL
, TRUE
);
732 SendMessage16(GetParent16(hwnd
),WM_COMMAND
,id
,
733 MAKELONG(hwnd
, CBN_EDITUPDATE
));
735 case EN_CHANGE
:SendMessage16(GetParent16(hwnd
),WM_COMMAND
,id
,
736 MAKELONG(hwnd
, CBN_EDITCHANGE
));
738 case EN_ERRSPACE
:SendMessage16(GetParent16(hwnd
),WM_COMMAND
,id
,
739 MAKELONG(hwnd
, CBN_ERRSPACE
));
749 /***********************************************************************
751 * Look out! Under Win32, the parameter packing is very different.
753 static LRESULT
CBGetEditSel(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
755 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
757 if ((lphc
->dwStyle
& 3) == CBS_DROPDOWNLIST
)
758 return CB_ERR
; /* err, documented for CBSetEditSel */
759 return SendMessage16(lphc
->hWndEdit
, EM_GETSEL
, 0, 0);
763 /***********************************************************************
765 * Look out! Under Win32, the parameter packing is very different.
767 static LRESULT
CBSetEditSel(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
769 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
771 if ((lphc
->dwStyle
& 3) == CBS_DROPDOWNLIST
)
773 return SendMessage16(lphc
->hWndEdit
, EM_SETSEL
, 0, lParam
);
776 /***********************************************************************
779 static LRESULT
CBGetText(HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
781 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
783 return SendMessage16(lphc
->hWndEdit
, WM_GETTEXT
, wParam
, lParam
);
786 /***********************************************************************
789 LRESULT
ComboBoxWndProc(HWND hwnd
, UINT message
, WPARAM16 wParam
, LPARAM lParam
)
792 case WM_NCCREATE
: return CBNCCreate(hwnd
, wParam
, lParam
);
793 case WM_CREATE
: return CBCreate(hwnd
, wParam
, lParam
);
794 case WM_DESTROY
: return CBDestroy(hwnd
, wParam
, lParam
);
795 case WM_GETDLGCODE
: return CBGetDlgCode(hwnd
, wParam
, lParam
);
796 case WM_KEYDOWN
: return CBKeyDown(hwnd
, wParam
, lParam
);
797 case WM_CHAR
: return CBChar(hwnd
, wParam
, lParam
);
798 case WM_SETFONT
: return CBSetFont(hwnd
, wParam
, lParam
);
799 case WM_SETREDRAW
: return CBSetRedraw(hwnd
, wParam
, lParam
);
800 case WM_PAINT
: return CBPaint(hwnd
, wParam
, lParam
);
801 case WM_GETTEXT
: return CBGetText( hwnd
, wParam
, lParam
);
802 case WM_LBUTTONDOWN
: return CBLButtonDown(hwnd
, wParam
, lParam
);
803 case WM_SETFOCUS
: return CBSetFocus(hwnd
, wParam
, lParam
);
804 case WM_KILLFOCUS
: return CBKillFocus(hwnd
, wParam
, lParam
);
805 case WM_SIZE
: return CBCheckSize(hwnd
);
806 case WM_COMMAND
: return CBCommand(hwnd
, wParam
, lParam
);
807 case CB_RESETCONTENT16
: return CBResetContent(hwnd
, wParam
, lParam
);
808 case CB_DIR16
: return CBDir(hwnd
, wParam
, lParam
);
809 case CB_ADDSTRING16
: return CBAddString(hwnd
, wParam
, lParam
);
810 case CB_INSERTSTRING16
: return CBInsertString(hwnd
, wParam
, lParam
);
811 case CB_DELETESTRING16
: return CBDeleteString(hwnd
, wParam
, lParam
);
812 case CB_FINDSTRING16
: return CBFindString(hwnd
, wParam
, lParam
);
813 case CB_GETCOUNT16
: return CBGetCount(hwnd
, wParam
, lParam
);
814 case CB_GETCURSEL16
: return CBGetCurSel(hwnd
, wParam
, lParam
);
815 case CB_GETITEMDATA16
: return CBGetItemData(hwnd
, wParam
, lParam
);
816 case CB_GETITEMHEIGHT16
: return CBGetItemHeight(hwnd
, wParam
, lParam
);
817 case CB_GETLBTEXT16
: return CBGetLBText(hwnd
, wParam
, lParam
);
818 case CB_GETLBTEXTLEN16
: return CBGetLBTextLen(hwnd
, wParam
, lParam
);
819 case CB_SELECTSTRING16
: return CBSelectString(hwnd
, wParam
, lParam
);
820 case CB_SETITEMDATA16
: return CBSetItemData(hwnd
, wParam
, lParam
);
821 case CB_SETCURSEL16
: return CBSetCurSel(hwnd
, wParam
, lParam
);
822 case CB_SETITEMHEIGHT16
: return CBSetItemHeight(hwnd
, wParam
, lParam
);
823 case CB_SHOWDROPDOWN16
: return CBShowDropDown(hwnd
, wParam
, lParam
);
824 case CB_GETEDITSEL16
: return CBGetEditSel(hwnd
, wParam
, lParam
);
825 case CB_SETEDITSEL16
: return CBSetEditSel(hwnd
, wParam
, lParam
);
826 case CB_FINDSTRINGEXACT16
: return CBFindStringExact(hwnd
, wParam
, lParam
);
828 return DefWindowProc16(hwnd
, message
, wParam
, lParam
);
831 /*--------------------------------------------------------------------*/
832 /* ComboLBox code starts here */
834 HWND
CLBoxGetCombo(HWND hwnd
)
836 return (HWND
)GetWindowLong32A(hwnd
,0);
839 LPHEADLIST
CLBoxGetListHeader(HWND hwnd
)
841 return ComboGetListHeader(CLBoxGetCombo(hwnd
));
844 /***********************************************************************
847 static LRESULT
CBLCreate( HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
849 CREATESTRUCT16
*createStruct
= (CREATESTRUCT16
*)PTR_SEG_TO_LIN(lParam
);
850 SetWindowLong32A(hwnd
,0,(LONG
)createStruct
->lpCreateParams
);
854 /***********************************************************************
857 static LRESULT
CBLGetDlgCode( HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
859 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
862 /***********************************************************************
865 static LRESULT
CBLKeyDown( HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
867 LPHEADLIST lphl
= CLBoxGetListHeader(hwnd
);
868 WORD newFocused
= lphl
->ItemFocused
;
875 newFocused
= lphl
->ItemsCount
- 1;
878 if (newFocused
> 0) newFocused
--;
884 if (newFocused
> lphl
->ItemsVisible
) {
885 newFocused
-= lphl
->ItemsVisible
;
891 newFocused
+= lphl
->ItemsVisible
;
897 if (newFocused
>= lphl
->ItemsCount
)
898 newFocused
= lphl
->ItemsCount
- 1;
900 ListBoxSetCurSel(lphl
, newFocused
);
901 ListBoxSendNotification(lphl
, CBN_SELCHANGE
);
902 SendMessage16(GetParent16(hwnd
), WM_COMMAND
,ID_CLB
,MAKELONG(0,CBN_SELCHANGE
));
903 lphl
->ItemFocused
= newFocused
;
904 ListBoxScrollToFocus(lphl
);
905 SetScrollPos32(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
906 InvalidateRect32( hwnd
, NULL
, TRUE
);
910 /***********************************************************************
913 static LRESULT
CBLChar( HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
918 /***********************************************************************
921 static LRESULT
CBLPaint( HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
923 LPHEADLIST lphl
= CLBoxGetListHeader(hwnd
);
928 WND
* wndPtr
= WIN_FindWndPtr(hwnd
);
929 HWND combohwnd
= CLBoxGetCombo(hwnd
);
935 hdc
= BeginPaint16( hwnd
, &ps
);
937 if (!IsWindowVisible(hwnd
) || !lphl
->bRedrawFlag
) {
938 EndPaint16(hwnd
, &ps
);
942 hOldFont
= SelectObject32(hdc
, lphl
->hFont
);
943 /* listboxes should be white */
944 hBrush
= GetStockObject32(WHITE_BRUSH
);
946 GetClientRect16(hwnd
, &rect
);
947 FillRect16(hdc
, &rect
, hBrush
);
950 lpls
= lphl
->lpFirst
;
952 lphl
->ItemsVisible
= 0;
953 for(i
= 0; i
< lphl
->ItemsCount
; i
++) {
954 if (lpls
== NULL
) break;
956 if (i
>= lphl
->FirstVisible
) {
957 height
= lpls
->mis
.itemHeight
;
958 /* must have enough room to draw entire item */
959 if (top
> (rect
.bottom
-height
+1)) break;
961 lpls
->itemRect
.top
= top
;
962 lpls
->itemRect
.bottom
= top
+ height
;
963 lpls
->itemRect
.left
= rect
.left
;
964 lpls
->itemRect
.right
= rect
.right
;
966 dprintf_listbox(stddeb
,"drawing item: %d %d %d %d %d\n",
967 rect
.left
,top
,rect
.right
,top
+height
,lpls
->itemState
);
968 if (lphl
->OwnerDrawn
) {
969 ListBoxDrawItem (combohwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_DRAWENTIRE
, 0);
971 ListBoxDrawItem (combohwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_SELECT
, ODS_SELECTED
);
973 ListBoxDrawItem (combohwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_DRAWENTIRE
,
976 if ((lphl
->ItemFocused
== i
) && GetFocus32() == hwnd
)
977 ListBoxDrawItem (combohwnd
, lphl
, hdc
, lpls
, &lpls
->itemRect
, ODA_FOCUS
, ODS_FOCUS
);
980 lphl
->ItemsVisible
++;
986 if (wndPtr
->dwStyle
& WS_VSCROLL
)
987 SetScrollRange32(hwnd
, SB_VERT
, 0, ListMaxFirstVisible(lphl
), TRUE
);
989 SelectObject32(hdc
,hOldFont
);
990 EndPaint16( hwnd
, &ps
);
995 /***********************************************************************
998 static LRESULT
CBLKillFocus( HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
1000 /* SendMessage16(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN16,0,0);*/
1004 /***********************************************************************
1007 static LRESULT
CBLActivate( HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
1009 if (wParam
== WA_INACTIVE
)
1010 SendMessage16(CLBoxGetCombo(hwnd
),CB_SHOWDROPDOWN16
,0,0);
1014 /***********************************************************************
1017 static LRESULT
CBLLButtonDown( HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
1019 LPHEADLIST lphl
= CLBoxGetListHeader(hwnd
);
1023 /* SetFocus32(hwnd); */
1026 lphl
->PrevFocused
= lphl
->ItemFocused
;
1028 y
= ListBoxFindMouse(lphl
, LOWORD(lParam
), HIWORD(lParam
));
1032 ListBoxSetCurSel(lphl
, y
);
1033 ListBoxGetItemRect(lphl
, y
, &rectsel
);
1035 InvalidateRect32( hwnd
, NULL
, TRUE
);
1039 /***********************************************************************
1042 static LRESULT
CBLLButtonUp( HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
1044 LPHEADLIST lphl
= CLBoxGetListHeader(hwnd
);
1046 if (GetCapture32() == hwnd
) ReleaseCapture();
1050 fprintf(stdnimp
,"CBLLButtonUp: CLBoxGetListHeader returned NULL!\n");
1052 else if (lphl
->PrevFocused
!= lphl
->ItemFocused
)
1054 SendMessage16(CLBoxGetCombo(hwnd
),CB_SETCURSEL16
,lphl
->ItemFocused
,0);
1055 SendMessage16(GetParent16(hwnd
), WM_COMMAND
,ID_CLB
,MAKELONG(0,CBN_SELCHANGE
));
1056 ListBoxSendNotification(lphl
, CBN_SELCHANGE
);
1059 SendMessage16(CLBoxGetCombo(hwnd
),CB_SHOWDROPDOWN16
,0,0);
1064 /***********************************************************************
1067 static LRESULT
CBLMouseMove( HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
1069 LPHEADLIST lphl
= CLBoxGetListHeader(hwnd
);
1072 RECT16 rect
, rectsel
;
1074 y
= SHIWORD(lParam
);
1075 wRet
= ListBoxFindMouse(lphl
, LOWORD(lParam
), HIWORD(lParam
));
1076 ListBoxGetItemRect(lphl
, wRet
, &rectsel
);
1077 GetClientRect16(hwnd
, &rect
);
1079 dprintf_combo(stddeb
,"CBLMouseMove: hwnd %04x wp %x lp %lx y %d if %d wret %d %d,%d-%d,%d\n",
1080 hwnd
,wParam
,lParam
,y
,lphl
->ItemFocused
,wRet
,rectsel
.left
,rectsel
.top
,rectsel
.right
,rectsel
.bottom
);
1082 if ((wParam
& MK_LBUTTON
) != 0) {
1083 if (y
< CBLMM_EDGE
) {
1084 if (lphl
->FirstVisible
> 0) {
1085 lphl
->FirstVisible
--;
1086 SetScrollPos32(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1087 ListBoxSetCurSel(lphl
, wRet
);
1088 InvalidateRect32( hwnd
, NULL
, TRUE
);
1092 else if (y
>= (rect
.bottom
-CBLMM_EDGE
)) {
1093 if (lphl
->FirstVisible
< ListMaxFirstVisible(lphl
)) {
1094 lphl
->FirstVisible
++;
1095 SetScrollPos32(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1096 ListBoxSetCurSel(lphl
, wRet
);
1097 InvalidateRect32( hwnd
, NULL
, TRUE
);
1102 if ((short) wRet
== lphl
->ItemFocused
) return 0;
1103 ListBoxSetCurSel(lphl
, wRet
);
1104 InvalidateRect32( hwnd
, NULL
, TRUE
);
1111 /***********************************************************************
1114 static LRESULT
CBLVScroll( HWND hwnd
, WPARAM16 wParam
, LPARAM lParam
)
1116 LPHEADLIST lphl
= CLBoxGetListHeader(hwnd
);
1119 y
= lphl
->FirstVisible
;
1123 if (lphl
->FirstVisible
> 0)
1124 lphl
->FirstVisible
--;
1128 lphl
->FirstVisible
++;
1132 if (lphl
->FirstVisible
> lphl
->ItemsVisible
) {
1133 lphl
->FirstVisible
-= lphl
->ItemsVisible
;
1135 lphl
->FirstVisible
= 0;
1140 lphl
->FirstVisible
+= lphl
->ItemsVisible
;
1144 lphl
->FirstVisible
= LOWORD(lParam
);
1148 if (lphl
->FirstVisible
> ListMaxFirstVisible(lphl
))
1149 lphl
->FirstVisible
= ListMaxFirstVisible(lphl
);
1151 if (y
!= lphl
->FirstVisible
) {
1152 SetScrollPos32(hwnd
, SB_VERT
, lphl
->FirstVisible
, TRUE
);
1153 InvalidateRect32( hwnd
, NULL
, TRUE
);
1160 /***********************************************************************
1163 static BOOL
CBLCheckSize(HWND hwnd
)
1165 LPHEADCOMBO lphc
= ComboGetStorageHeader(hwnd
);
1166 LPHEADLIST lphl
= ComboGetListHeader(hwnd
);
1169 RECT16 cRect
,wRect
,lRect
,lwRect
;
1173 GetClassName32A(hwnd
,className
,80);
1175 if (strncmp(className
,"COMBOBOX",8)) return FALSE
;
1176 if ((hWndLBox
= lphc
->hWndLBox
) == 0) return FALSE
;
1177 dprintf_combo(stddeb
,"CBLCheckSize headers hw %04x lb %04x name %s\n",
1178 hwnd
,hWndLBox
,className
);
1180 GetClientRect16(hwnd
,&cRect
);
1181 GetWindowRect16(hwnd
,&wRect
);
1182 GetClientRect16(hWndLBox
,&lRect
);
1183 GetWindowRect16(hWndLBox
,&lwRect
);
1185 dprintf_combo(stddeb
,"CBLCheckSize: init cRect %d,%d-%d,%d wRect %d,%d-%d,%d\n",
1186 cRect
.left
,cRect
.top
,cRect
.right
,cRect
.bottom
,
1187 wRect
.left
,wRect
.top
,wRect
.right
,wRect
.bottom
);
1188 dprintf_combo(stddeb
," lRect %d,%d-%d,%d lwRect %d,%d-%d,%d\n",
1189 lRect
.left
,lRect
.top
,lRect
.right
,lRect
.bottom
,
1190 lwRect
.left
,lwRect
.top
,lwRect
.right
,lwRect
.bottom
);
1194 for (lpls
=lphl
->lpFirst
; lpls
!= NULL
; lpls
=lpls
->lpNext
)
1195 totheight
+= lpls
->mis
.itemHeight
;
1197 dw
= cRect
.right
-cRect
.left
+2*SYSMETRICS_CXBORDER
+SYSMETRICS_CXVSCROLL
;
1198 dw
-= lwRect
.right
-lwRect
.left
;
1199 dw
-= SYSMETRICS_CXVSCROLL
;
1201 /* TODO: This isn't really what windows does */
1202 if ((lRect
.bottom
-lRect
.top
< 3*lphl
->StdItemHeight
) || dw
) {
1203 dprintf_combo(stddeb
," Changing; totHeight %d StdItemHght %d dw %d\n",
1204 totheight
,lphl
->StdItemHeight
,dw
);
1205 SetWindowPos(hWndLBox
, 0, lRect
.left
, lRect
.top
,
1206 lwRect
.right
-lwRect
.left
+dw
, totheight
+2*SYSMETRICS_CYBORDER
,
1207 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOREDRAW
| SWP_NOACTIVATE
);
1213 /***********************************************************************
1216 LRESULT
ComboLBoxWndProc(HWND hwnd
, UINT message
, WPARAM16 wParam
, LPARAM lParam
)
1219 case WM_CREATE
: return CBLCreate(hwnd
, wParam
, lParam
);
1220 case WM_GETDLGCODE
: return CBLGetDlgCode(hwnd
, wParam
, lParam
);
1221 case WM_KEYDOWN
: return CBLKeyDown(hwnd
, wParam
, lParam
);
1222 case WM_CHAR
: return CBLChar(hwnd
, wParam
, lParam
);
1223 case WM_PAINT
: return CBLPaint(hwnd
, wParam
, lParam
);
1224 case WM_KILLFOCUS
: return CBLKillFocus(hwnd
, wParam
, lParam
);
1225 case WM_ACTIVATE
: return CBLActivate(hwnd
, wParam
, lParam
);
1226 case WM_LBUTTONDOWN
: return CBLLButtonDown(hwnd
, wParam
, lParam
);
1227 case WM_LBUTTONUP
: return CBLLButtonUp(hwnd
, wParam
, lParam
);
1228 case WM_MOUSEMOVE
: return CBLMouseMove(hwnd
, wParam
, lParam
);
1229 case WM_VSCROLL
: return CBLVScroll(hwnd
, wParam
, lParam
);
1230 case WM_SIZE
: return CBLCheckSize(hwnd
);
1231 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1232 return MA_NOACTIVATE
;
1234 return DefWindowProc16(hwnd
, message
, wParam
, lParam
);