4 * Copyright 1997 Alex Korobka
6 * FIXME: roll up in Netscape 3.01.
12 #include "wine/winuser16.h"
13 #include "sysmetrics.h"
22 /* bits in the dwKeyData */
23 #define KEYDATA_ALT 0x2000
24 #define KEYDATA_PREVSTATE 0x4000
27 * Additional combo box definitions
30 #define CB_GETPTR( wnd ) (*(LPHEADCOMBO*)((wnd)->wExtra))
31 #define CB_NOTIFY( lphc, code ) \
32 (SendMessageA( (lphc)->owner, WM_COMMAND, \
33 MAKEWPARAM((lphc)->self->wIDmenu, (code)), (lphc)->self->hwndSelf))
34 #define CB_GETEDITTEXTLENGTH( lphc ) \
35 (SendMessageA( (lphc)->hWndEdit, WM_GETTEXTLENGTH, 0, 0 ))
37 static HBITMAP hComboBmp
= 0;
38 static UINT CBitHeight
, CBitWidth
;
39 static UINT CBitOffset
= 8;
41 /***********************************************************************
44 * Load combo button bitmap.
46 static BOOL
COMBO_Init()
50 if( hComboBmp
) return TRUE
;
51 if( (hDC
= CreateCompatibleDC(0)) )
54 if( (hComboBmp
= LoadBitmapA(0, MAKEINTRESOURCEA(OBM_COMBO
))) )
60 GetObjectA( hComboBmp
, sizeof(bm
), &bm
);
61 CBitHeight
= bm
.bmHeight
;
62 CBitWidth
= bm
.bmWidth
;
64 TRACE(combo
, "combo bitmap [%i,%i]\n", CBitWidth
, CBitHeight
);
66 hPrevB
= SelectObject16( hDC
, hComboBmp
);
67 SetRect( &r
, 0, 0, CBitWidth
, CBitHeight
);
68 InvertRect( hDC
, &r
);
69 SelectObject( hDC
, hPrevB
);
78 /***********************************************************************
81 static LRESULT
COMBO_NCCreate(WND
* wnd
, LPARAM lParam
)
85 if ( wnd
&& COMBO_Init() &&
86 (lphc
= HeapAlloc(GetProcessHeap(), 0, sizeof(HEADCOMBO
))) )
88 LPCREATESTRUCTA lpcs
= (CREATESTRUCTA
*)lParam
;
90 memset( lphc
, 0, sizeof(HEADCOMBO
) );
91 *(LPHEADCOMBO
*)wnd
->wExtra
= lphc
;
93 /* some braindead apps do try to use scrollbar/border flags */
95 lphc
->dwStyle
= (lpcs
->style
& ~(WS_BORDER
| WS_HSCROLL
| WS_VSCROLL
));
96 wnd
->dwStyle
&= ~(WS_BORDER
| WS_HSCROLL
| WS_VSCROLL
);
98 if( !(lpcs
->style
& (CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
)) )
99 lphc
->dwStyle
|= CBS_HASSTRINGS
;
100 if( !(wnd
->dwExStyle
& WS_EX_NOPARENTNOTIFY
) )
101 lphc
->wState
|= CBF_NOTIFY
;
103 TRACE(combo
, "[0x%08x], style = %08x\n",
104 (UINT
)lphc
, lphc
->dwStyle
);
106 return (LRESULT
)(UINT
)wnd
->hwndSelf
;
108 return (LRESULT
)FALSE
;
111 /***********************************************************************
114 static LRESULT
COMBO_NCDestroy( LPHEADCOMBO lphc
)
119 WND
* wnd
= lphc
->self
;
121 TRACE(combo
,"[%04x]: freeing storage\n", CB_HWND(lphc
));
123 if( (CB_GETTYPE(lphc
) != CBS_SIMPLE
) && lphc
->hWndLBox
)
124 DestroyWindow( lphc
->hWndLBox
);
126 HeapFree( GetProcessHeap(), 0, lphc
);
132 /***********************************************************************
133 * CBGetDefaultTextHeight
135 static void CBGetDefaultTextHeight( LPHEADCOMBO lphc
, LPSIZE lpSize
)
137 if( lphc
->editHeight
) /* explicitly set height */
138 lpSize
->cy
= lphc
->editHeight
;
141 HDC hDC
= GetDC( lphc
->self
->hwndSelf
);
144 if( lphc
->hFont
) hPrevFont
= SelectObject( hDC
, lphc
->hFont
);
146 GetTextExtentPoint32A( hDC
, "0", 1, lpSize
);
148 lpSize
->cy
+= lpSize
->cy
/ 4 + 4 * SYSMETRICS_CYBORDER
;
150 if( hPrevFont
) SelectObject( hDC
, hPrevFont
);
151 ReleaseDC( lphc
->self
->hwndSelf
, hDC
);
153 lpSize
->cx
= lphc
->RectCombo
.right
- lphc
->RectCombo
.left
;
157 /***********************************************************************
160 * Set up component coordinates given valid lphc->RectCombo.
162 static void CBCalcPlacement( LPHEADCOMBO lphc
, LPRECT lprEdit
,
163 LPRECT lprButton
, LPRECT lprLB
)
165 RECT rect
= lphc
->RectCombo
;
168 /* get combo height and width */
170 if( CB_OWNERDRAWN(lphc
) )
172 UINT u
= lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
;
174 if( lphc
->wState
& CBF_MEASUREITEM
) /* first initialization */
176 MEASUREITEMSTRUCT mi32
;
178 /* calculate defaults before sending WM_MEASUREITEM */
180 CBGetDefaultTextHeight( lphc
, &size
);
182 lphc
->wState
&= ~CBF_MEASUREITEM
;
184 mi32
.CtlType
= ODT_COMBOBOX
;
185 mi32
.CtlID
= lphc
->self
->wIDmenu
;
187 mi32
.itemWidth
= size
.cx
;
188 mi32
.itemHeight
= size
.cy
- 6; /* ownerdrawn cb is taller */
190 SendMessageA(lphc
->owner
, WM_MEASUREITEM
,
191 (WPARAM
)mi32
.CtlID
, (LPARAM
)&mi32
);
192 u
= 6 + (UINT16
)mi32
.itemHeight
;
195 size
.cx
= rect
.right
- rect
.left
;
199 CBGetDefaultTextHeight( lphc
, &size
);
201 /* calculate text and button placement */
203 lprEdit
->left
= lprEdit
->top
= lprButton
->top
= 0;
204 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
) /* no button */
205 lprButton
->left
= lprButton
->right
= lprButton
->bottom
= 0;
208 INT i
= size
.cx
- CBitWidth
- 10; /* seems ok */
210 lprButton
->right
= size
.cx
;
211 lprButton
->left
= (INT16
)i
;
212 lprButton
->bottom
= lprButton
->top
+ size
.cy
;
214 if( i
< 0 ) size
.cx
= 0;
218 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
220 size
.cx
-= CBitOffset
;
221 if( size
.cx
< 0 ) size
.cx
= 0;
224 lprEdit
->right
= size
.cx
; lprEdit
->bottom
= size
.cy
;
226 /* listbox placement */
228 lprLB
->left
= ( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
) ? 0 : CBitOffset
;
229 lprLB
->top
= lprEdit
->bottom
- SYSMETRICS_CYBORDER
;
230 lprLB
->right
= rect
.right
- rect
.left
;
231 lprLB
->bottom
= rect
.bottom
- rect
.top
;
233 if( lphc
->droppedWidth
> (lprLB
->right
- lprLB
->left
) )
234 lprLB
->right
= lprLB
->left
+ lphc
->droppedWidth
;
236 TRACE(combo
,"[%04x]: (%i,%i-%i,%i) placement\n",
237 CB_HWND(lphc
), lphc
->RectCombo
.left
, lphc
->RectCombo
.top
,
238 lphc
->RectCombo
.right
, lphc
->RectCombo
.bottom
);
240 TRACE(combo
,"\ttext\t= (%i,%i-%i,%i)\n",
241 lprEdit
->left
, lprEdit
->top
, lprEdit
->right
, lprEdit
->bottom
);
243 TRACE(combo
,"\tbutton\t= (%i,%i-%i,%i)\n",
244 lprButton
->left
, lprButton
->top
, lprButton
->right
, lprButton
->bottom
);
246 TRACE(combo
,"\tlbox\t= (%i,%i-%i,%i)\n",
247 lprLB
->left
, lprLB
->top
, lprLB
->right
, lprLB
->bottom
);
250 /***********************************************************************
251 * CBGetDroppedControlRect32
253 static void CBGetDroppedControlRect( LPHEADCOMBO lphc
, LPRECT lpRect
)
255 lpRect
->left
= lphc
->RectCombo
.left
+
256 (lphc
->wState
& CBF_EDIT
) ? CBitOffset
: 0;
257 lpRect
->top
= lphc
->RectCombo
.top
+ lphc
->RectEdit
.bottom
-
259 lpRect
->right
= lphc
->RectCombo
.right
;
260 lpRect
->bottom
= lphc
->RectCombo
.bottom
- SYSMETRICS_CYBORDER
;
263 /***********************************************************************
266 static LRESULT
COMBO_Create( LPHEADCOMBO lphc
, WND
* wnd
, LPARAM lParam
)
268 static char clbName
[] = "ComboLBox";
269 static char editName
[] = "Edit";
271 LPCREATESTRUCTA lpcs
= (CREATESTRUCTA
*)lParam
;
273 if( !CB_GETTYPE(lphc
) ) lphc
->dwStyle
|= CBS_SIMPLE
;
274 else if( CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
) lphc
->wState
|= CBF_EDIT
;
277 lphc
->owner
= lpcs
->hwndParent
;
279 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
281 if( lphc
->owner
|| !(lpcs
->style
& WS_VISIBLE
) )
284 RECT editRect
, btnRect
, lbRect
;
286 GetWindowRect( wnd
->hwndSelf
, &lphc
->RectCombo
);
288 lphc
->wState
|= CBF_MEASUREITEM
;
289 CBCalcPlacement( lphc
, &editRect
, &btnRect
, &lbRect
);
290 lphc
->RectButton
= btnRect
;
291 lphc
->droppedWidth
= lphc
->editHeight
= 0;
293 /* create listbox popup */
295 lbeStyle
= (LBS_NOTIFY
| WS_BORDER
| WS_CLIPSIBLINGS
) |
296 (lpcs
->style
& (WS_VSCROLL
| CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
));
298 if( lphc
->dwStyle
& CBS_SORT
)
299 lbeStyle
|= LBS_SORT
;
300 if( lphc
->dwStyle
& CBS_HASSTRINGS
)
301 lbeStyle
|= LBS_HASSTRINGS
;
302 if( lphc
->dwStyle
& CBS_NOINTEGRALHEIGHT
)
303 lbeStyle
|= LBS_NOINTEGRALHEIGHT
;
304 if( lphc
->dwStyle
& CBS_DISABLENOSCROLL
)
305 lbeStyle
|= LBS_DISABLENOSCROLL
;
307 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
) /* child listbox */
308 lbeStyle
|= WS_CHILD
| WS_VISIBLE
;
309 else /* popup listbox */
311 lbeStyle
|= WS_POPUP
;
312 OffsetRect( &lbRect
, lphc
->RectCombo
.left
, lphc
->RectCombo
.top
);
315 /* Dropdown ComboLBox is not a child window and we cannot pass
316 * ID_CB_LISTBOX directly because it will be treated as a menu handle.
319 lphc
->hWndLBox
= CreateWindowExA( 0, clbName
, NULL
, lbeStyle
,
320 lbRect
.left
+ SYSMETRICS_CXBORDER
,
321 lbRect
.top
+ SYSMETRICS_CYBORDER
,
322 lbRect
.right
- lbRect
.left
- 2 * SYSMETRICS_CXBORDER
,
323 lbRect
.bottom
- lbRect
.top
- 2 * SYSMETRICS_CYBORDER
,
324 lphc
->self
->hwndSelf
,
325 (lphc
->dwStyle
& CBS_DROPDOWN
)? (HMENU
)0 : (HMENU
)ID_CB_LISTBOX
,
326 lphc
->self
->hInstance
, (LPVOID
)lphc
);
330 lbeStyle
= WS_CHILD
| WS_VISIBLE
| WS_BORDER
| ES_NOHIDESEL
| ES_LEFT
;
331 if( lphc
->wState
& CBF_EDIT
)
333 if( lphc
->dwStyle
& CBS_OEMCONVERT
)
334 lbeStyle
|= ES_OEMCONVERT
;
335 if( lphc
->dwStyle
& CBS_AUTOHSCROLL
)
336 lbeStyle
|= ES_AUTOHSCROLL
;
337 if( lphc
->dwStyle
& CBS_LOWERCASE
)
338 lbeStyle
|= ES_LOWERCASE
;
339 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
340 lbeStyle
|= ES_UPPERCASE
;
341 lphc
->hWndEdit
= CreateWindowExA( 0, editName
, NULL
, lbeStyle
,
342 editRect
.left
, editRect
.top
, editRect
.right
- editRect
.left
,
343 editRect
.bottom
- editRect
.top
, lphc
->self
->hwndSelf
,
344 (HMENU
)ID_CB_EDIT
, lphc
->self
->hInstance
, NULL
);
345 if( !lphc
->hWndEdit
) bEdit
= FALSE
;
350 lphc
->RectEdit
= editRect
;
351 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
353 lphc
->wState
|= CBF_NORESIZE
;
354 SetWindowPos( wnd
->hwndSelf
, 0, 0, 0,
355 lphc
->RectCombo
.right
- lphc
->RectCombo
.left
,
356 lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
,
357 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
358 lphc
->wState
&= ~CBF_NORESIZE
;
360 TRACE(combo
,"init done\n");
361 return wnd
->hwndSelf
;
363 ERR(combo
, "edit control failure.\n");
364 } else ERR(combo
, "listbox failure.\n");
365 } else ERR(combo
, "no owner for visible combo.\n");
367 /* CreateWindow() will send WM_NCDESTROY to cleanup */
372 /***********************************************************************
375 * Paint combo button (normal, pressed, and disabled states).
377 static void CBPaintButton(LPHEADCOMBO lphc
, HDC hdc
)
384 COLORREF oldTextColor
, oldBkColor
;
386 if( lphc
->wState
& CBF_NOREDRAW
) return;
388 hPrevBrush
= SelectObject(hdc
, GetSysColorBrush(COLOR_BTNFACE
));
389 CONV_RECT16TO32( &lphc
->RectButton
, &r
);
391 Rectangle(hdc
, r
.left
, r
.top
, r
.right
, r
.bottom
);
392 if( (bBool
= lphc
->wState
& CBF_BUTTONDOWN
) )
394 DrawEdge( hdc
, &r
, EDGE_SUNKEN
, BF_RECT
);
395 OffsetRect( &r
, 1, 1 );
398 DrawEdge( hdc
, &r
, EDGE_RAISED
, BF_RECT
);
402 InflateRect( &r
, -1, -1 );
404 x
= (r
.left
+ r
.right
- CBitWidth
) >> 1;
405 y
= (r
.top
+ r
.bottom
- CBitHeight
) >> 1;
407 InflateRect( &r
, -3, -3 );
409 hMemDC
= CreateCompatibleDC( hdc
);
410 SelectObject( hMemDC
, hComboBmp
);
411 oldTextColor
= SetTextColor( hdc
, GetSysColor(COLOR_BTNFACE
) );
412 oldBkColor
= SetBkColor( hdc
, CB_DISABLED(lphc
) ? RGB(128,128,128) :
414 BitBlt( hdc
, x
, y
, 8, 8, hMemDC
, 0, 0, SRCCOPY
);
415 SetBkColor( hdc
, oldBkColor
);
416 SetTextColor( hdc
, oldTextColor
);
418 SelectObject( hdc
, hPrevBrush
);
421 /***********************************************************************
424 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
426 static void CBPaintText(LPHEADCOMBO lphc
, HDC hdc
)
431 if( lphc
->wState
& CBF_NOREDRAW
) return;
433 /* follow Windows combobox that sends a bunch of text
434 * inquiries to its listbox while processing WM_PAINT. */
436 if( (id
= SendMessageA(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0) ) != LB_ERR
)
438 size
= SendMessageA( lphc
->hWndLBox
, LB_GETTEXTLEN
, id
, 0);
439 if( (pText
= HeapAlloc( GetProcessHeap(), 0, size
+ 1)) )
441 SendMessageA( lphc
->hWndLBox
, LB_GETTEXT
, (WPARAM
)id
, (LPARAM
)pText
);
442 pText
[size
] = '\0'; /* just in case */
446 if( lphc
->wState
& CBF_EDIT
)
448 if( CB_HASSTRINGS(lphc
) ) SetWindowTextA( lphc
->hWndEdit
, pText
? pText
: "" );
449 if( lphc
->wState
& CBF_FOCUSED
)
450 SendMessageA( lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1));
452 else /* paint text field ourselves */
454 HBRUSH hPrevBrush
= 0;
459 if ((hDC
= GetDC(lphc
->self
->hwndSelf
)))
461 HBRUSH hBrush
= SendMessageA( lphc
->owner
,
463 hDC
, lphc
->self
->hwndSelf
);
464 hPrevBrush
= SelectObject( hDC
,
465 (hBrush
) ? hBrush
: GetStockObject(WHITE_BRUSH
) );
472 HFONT hPrevFont
= (lphc
->hFont
) ? SelectObject(hDC
, lphc
->hFont
) : 0;
474 PatBlt( hDC
, (rect
.left
= lphc
->RectEdit
.left
+ SYSMETRICS_CXBORDER
),
475 (rect
.top
= lphc
->RectEdit
.top
+ SYSMETRICS_CYBORDER
),
476 (rect
.right
= lphc
->RectEdit
.right
- SYSMETRICS_CXBORDER
),
477 (rect
.bottom
= lphc
->RectEdit
.bottom
- SYSMETRICS_CYBORDER
) - 1, PATCOPY
);
478 InflateRect( &rect
, -1, -1 );
480 if( lphc
->wState
& CBF_FOCUSED
&&
481 !(lphc
->wState
& CBF_DROPPED
) )
485 FillRect( hDC
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
486 SetBkColor( hDC
, GetSysColor( COLOR_HIGHLIGHT
) );
487 SetTextColor( hDC
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
488 itemState
= ODS_SELECTED
| ODS_FOCUS
;
489 } else itemState
= 0;
491 if( CB_OWNERDRAWN(lphc
) )
495 if( lphc
->self
->dwStyle
& WS_DISABLED
) itemState
|= ODS_DISABLED
;
497 dis
.CtlType
= ODT_COMBOBOX
;
498 dis
.CtlID
= lphc
->self
->wIDmenu
;
499 dis
.hwndItem
= lphc
->self
->hwndSelf
;
500 dis
.itemAction
= ODA_DRAWENTIRE
;
502 dis
.itemState
= itemState
;
505 dis
.itemData
= SendMessageA( lphc
->hWndLBox
, LB_GETITEMDATA
,
507 SendMessageA( lphc
->owner
, WM_DRAWITEM
,
508 lphc
->self
->wIDmenu
, (LPARAM
)&dis
);
512 ExtTextOutA( hDC
, rect
.left
+ 1, rect
.top
+ 1,
513 ETO_OPAQUE
| ETO_CLIPPED
, &rect
,
514 pText
? pText
: "" , size
, NULL
);
515 if(lphc
->wState
& CBF_FOCUSED
&& !(lphc
->wState
& CBF_DROPPED
))
516 DrawFocusRect( hDC
, &rect
);
519 if( hPrevFont
) SelectObject(hDC
, hPrevFont
);
522 if( hPrevBrush
) SelectObject( hDC
, hPrevBrush
);
523 ReleaseDC( lphc
->self
->hwndSelf
, hDC
);
528 HeapFree( GetProcessHeap(), 0, pText
);
531 /***********************************************************************
534 static LRESULT
COMBO_Paint(LPHEADCOMBO lphc
, HDC hParamDC
)
539 hDC
= (hParamDC
) ? hParamDC
540 : BeginPaint( lphc
->self
->hwndSelf
, &ps
);
541 if( hDC
&& !(lphc
->wState
& CBF_NOREDRAW
) )
543 HBRUSH hPrevBrush
, hBkgBrush
;
545 hBkgBrush
= SendMessageA( lphc
->owner
, WM_CTLCOLORLISTBOX
,
546 hDC
, lphc
->self
->hwndSelf
);
547 if( !hBkgBrush
) hBkgBrush
= GetStockObject(WHITE_BRUSH
);
549 hPrevBrush
= SelectObject( hDC
, hBkgBrush
);
550 if( !IsRectEmpty(&lphc
->RectButton
) )
552 /* paint everything to the right of the text field */
554 PatBlt( hDC
, lphc
->RectEdit
.right
, lphc
->RectEdit
.top
,
555 lphc
->RectButton
.right
- lphc
->RectEdit
.right
,
556 lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
, PATCOPY
);
557 CBPaintButton( lphc
, hDC
);
560 if( !(lphc
->wState
& CBF_EDIT
) )
562 /* paint text field */
564 HPEN hPrevPen
= SelectObject( hDC
, GetSysColorPen(
565 COLOR_WINDOWFRAME
) );
567 Rectangle( hDC
, lphc
->RectEdit
.left
, lphc
->RectEdit
.top
,
568 lphc
->RectEdit
.right
, lphc
->RectButton
.bottom
);
569 SelectObject( hDC
, hPrevPen
);
570 CBPaintText( lphc
, hDC
);
572 if( hPrevBrush
) SelectObject( hDC
, hPrevBrush
);
574 if( !hParamDC
) EndPaint(lphc
->self
->hwndSelf
, &ps
);
578 /***********************************************************************
581 * Select listbox entry according to the contents of the edit control.
583 static INT
CBUpdateLBox( LPHEADCOMBO lphc
)
585 INT length
, idx
, ret
;
589 length
= CB_GETEDITTEXTLENGTH( lphc
);
592 pText
= (LPSTR
) HeapAlloc( GetProcessHeap(), 0, length
+ 1);
594 TRACE(combo
,"\t edit text length %i\n", length
);
598 if( length
) GetWindowTextA( lphc
->hWndEdit
, pText
, length
+ 1);
599 else pText
[0] = '\0';
600 idx
= SendMessageA( lphc
->hWndLBox
, LB_FINDSTRING
,
601 (WPARAM
)(-1), (LPARAM
)pText
);
602 if( idx
== LB_ERR
) idx
= 0; /* select first item */
604 HeapFree( GetProcessHeap(), 0, pText
);
609 SendMessageA( lphc
->hWndLBox
, LB_SETCURSEL
, (WPARAM
)idx
, 0 );
613 SendMessageA( lphc
->hWndLBox
, LB_SETTOPINDEX
, (WPARAM
)idx
, 0 );
614 /* probably superfluous but Windows sends this too */
615 SendMessageA( lphc
->hWndLBox
, LB_SETCARETINDEX
, (WPARAM
)idx
, 0 );
620 /***********************************************************************
623 * Copy a listbox entry to the edit control.
625 static void CBUpdateEdit( LPHEADCOMBO lphc
, INT index
)
630 TRACE(combo
,"\t %i\n", index
);
634 length
= CB_GETEDITTEXTLENGTH( lphc
);
637 if( (pText
= (LPSTR
) HeapAlloc( GetProcessHeap(), 0, length
+ 1)) )
639 GetWindowTextA( lphc
->hWndEdit
, pText
, length
+ 1 );
640 index
= SendMessageA( lphc
->hWndLBox
, LB_FINDSTRING
,
641 (WPARAM
)(-1), (LPARAM
)pText
);
642 HeapFree( GetProcessHeap(), 0, pText
);
647 if( index
>= 0 ) /* got an entry */
649 length
= SendMessageA( lphc
->hWndLBox
, LB_GETTEXTLEN
, (WPARAM
)index
, 0);
652 if( (pText
= (LPSTR
) HeapAlloc( GetProcessHeap(), 0, length
+ 1)) )
654 SendMessageA( lphc
->hWndLBox
, LB_GETTEXT
,
655 (WPARAM
)index
, (LPARAM
)pText
);
656 SendMessageA( lphc
->hWndEdit
, WM_SETTEXT
, 0, (LPARAM
)pText
);
657 SendMessageA( lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1) );
658 HeapFree( GetProcessHeap(), 0, pText
);
664 /***********************************************************************
667 * Show listbox popup.
669 static void CBDropDown( LPHEADCOMBO lphc
)
675 TRACE(combo
,"[%04x]: drop down\n", CB_HWND(lphc
));
677 CB_NOTIFY( lphc
, CBN_DROPDOWN
);
681 lphc
->wState
|= CBF_DROPPED
;
682 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
684 index
= CBUpdateLBox( lphc
);
685 if( !(lphc
->wState
& CBF_CAPTURE
) ) CBUpdateEdit( lphc
, index
);
689 index
= SendMessageA( lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0 );
690 if( index
== LB_ERR
) index
= 0;
691 SendMessageA( lphc
->hWndLBox
, LB_SETTOPINDEX
, (WPARAM
)index
, 0 );
692 SendMessageA( lphc
->hWndLBox
, LB_CARETON
, 0, 0 );
693 pRect
= &lphc
->RectEdit
;
696 /* now set popup position */
698 GetWindowRect( lphc
->self
->hwndSelf
, &rect
);
700 rect
.top
+= lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
- SYSMETRICS_CYBORDER
;
701 rect
.bottom
= rect
.top
+ lphc
->RectCombo
.bottom
-
702 lphc
->RectCombo
.top
- SYSMETRICS_CYBORDER
;
703 rect
.right
= rect
.left
+ lphc
->RectCombo
.right
- lphc
->RectCombo
.left
;
704 rect
.left
+= ( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
) ? 0 : CBitOffset
;
706 SetWindowPos( lphc
->hWndLBox
, HWND_TOP
, rect
.left
, rect
.top
,
707 rect
.right
- rect
.left
, rect
.bottom
- rect
.top
,
708 SWP_NOACTIVATE
| SWP_NOSIZE
| SWP_NOREDRAW
);
710 if( !(lphc
->wState
& CBF_NOREDRAW
) )
712 RedrawWindow( lphc
->self
->hwndSelf
, pRect
, 0, RDW_INVALIDATE
|
713 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
714 ShowWindow( lphc
->hWndLBox
, SW_SHOWNA
);
717 /***********************************************************************
720 * Hide listbox popup.
722 static void CBRollUp( LPHEADCOMBO lphc
, BOOL ok
, BOOL bButton
)
724 HWND hWnd
= lphc
->self
->hwndSelf
;
726 CB_NOTIFY( lphc
, (ok
) ? CBN_SELENDOK
: CBN_SELENDCANCEL
);
728 if( IsWindow( hWnd
) && CB_GETTYPE(lphc
) != CBS_SIMPLE
)
731 TRACE(combo
,"[%04x]: roll up [%i]\n", CB_HWND(lphc
), (INT
)ok
);
733 /* always send WM_LBUTTONUP? */
734 SendMessageA( lphc
->hWndLBox
, WM_LBUTTONUP
, 0, (LPARAM
)(-1) );
736 if( lphc
->wState
& CBF_DROPPED
)
740 lphc
->wState
&= ~CBF_DROPPED
;
741 ShowWindow( lphc
->hWndLBox
, SW_HIDE
);
743 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
745 INT index
= SendMessageA( lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0 );
746 CBUpdateEdit( lphc
, index
);
747 rect
= lphc
->RectButton
;
752 UnionRect( &rect
, &lphc
->RectButton
,
755 rect
= lphc
->RectEdit
;
759 if( bButton
&& !(lphc
->wState
& CBF_NOREDRAW
) )
760 RedrawWindow( hWnd
, &rect
, 0, RDW_INVALIDATE
|
761 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
762 CB_NOTIFY( lphc
, CBN_CLOSEUP
);
767 /***********************************************************************
770 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
772 BOOL
COMBO_FlipListbox( LPHEADCOMBO lphc
, BOOL bRedrawButton
)
774 if( lphc
->wState
& CBF_DROPPED
)
776 CBRollUp( lphc
, TRUE
, bRedrawButton
);
784 /***********************************************************************
787 * Edit control helper.
789 HWND
COMBO_GetLBWindow( WND
* pWnd
)
791 LPHEADCOMBO lphc
= CB_GETPTR(pWnd
);
792 if( lphc
) return lphc
->hWndLBox
;
797 /***********************************************************************
800 static void CBRepaintButton( LPHEADCOMBO lphc
)
802 HDC hDC
= GetDC( lphc
->self
->hwndSelf
);
806 CBPaintButton( lphc
, hDC
);
807 ReleaseDC( lphc
->self
->hwndSelf
, hDC
);
811 /***********************************************************************
814 static void COMBO_SetFocus( LPHEADCOMBO lphc
)
816 if( !(lphc
->wState
& CBF_FOCUSED
) )
818 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
819 SendMessageA( lphc
->hWndLBox
, LB_CARETON
, 0, 0 );
821 if( lphc
->wState
& CBF_EDIT
)
822 SendMessageA( lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1) );
823 lphc
->wState
|= CBF_FOCUSED
;
824 if( !(lphc
->wState
& CBF_EDIT
) ) CBPaintText( lphc
, 0 );
826 CB_NOTIFY( lphc
, CBN_SETFOCUS
);
830 /***********************************************************************
833 static void COMBO_KillFocus( LPHEADCOMBO lphc
)
835 HWND hWnd
= lphc
->self
->hwndSelf
;
837 if( lphc
->wState
& CBF_FOCUSED
)
839 SendMessageA( hWnd
, WM_LBUTTONUP
, 0, (LPARAM
)(-1) );
841 CBRollUp( lphc
, FALSE
, TRUE
);
842 if( IsWindow( hWnd
) )
844 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
845 SendMessageA( lphc
->hWndLBox
, LB_CARETOFF
, 0, 0 );
847 lphc
->wState
&= ~CBF_FOCUSED
;
850 if( lphc
->wState
& CBF_EDIT
)
851 SendMessageA( lphc
->hWndEdit
, EM_SETSEL
, (WPARAM
)(-1), 0 );
852 else CBPaintText( lphc
, 0 );
854 CB_NOTIFY( lphc
, CBN_KILLFOCUS
);
859 /***********************************************************************
862 static LRESULT
COMBO_Command( LPHEADCOMBO lphc
, WPARAM wParam
, HWND hWnd
)
864 if( lphc
->wState
& CBF_EDIT
&& lphc
->hWndEdit
== hWnd
)
866 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
868 switch( HIWORD(wParam
) >> 8 )
870 case (EN_SETFOCUS
>> 8):
872 TRACE(combo
,"[%04x]: edit [%04x] got focus\n",
873 CB_HWND(lphc
), lphc
->hWndEdit
);
875 if( !(lphc
->wState
& CBF_FOCUSED
) ) COMBO_SetFocus( lphc
);
878 case (EN_KILLFOCUS
>> 8):
880 TRACE(combo
,"[%04x]: edit [%04x] lost focus\n",
881 CB_HWND(lphc
), lphc
->hWndEdit
);
883 /* NOTE: it seems that Windows' edit control sends an
884 * undocumented message WM_USER + 0x1B instead of this
885 * notification (only when it happens to be a part of
886 * the combo). ?? - AK.
889 COMBO_KillFocus( lphc
);
893 case (EN_CHANGE
>> 8):
894 CB_NOTIFY( lphc
, CBN_EDITCHANGE
);
895 CBUpdateLBox( lphc
);
898 case (EN_UPDATE
>> 8):
899 CB_NOTIFY( lphc
, CBN_EDITUPDATE
);
902 case (EN_ERRSPACE
>> 8):
903 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
906 else if( lphc
->hWndLBox
== hWnd
)
908 switch( HIWORD(wParam
) )
911 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
915 CB_NOTIFY( lphc
, CBN_DBLCLK
);
921 TRACE(combo
,"[%04x]: lbox selection change [%04x]\n",
922 CB_HWND(lphc
), lphc
->wState
);
924 /* do not roll up if selection is being tracked
925 * by arrowkeys in the dropdown listbox */
927 if( (lphc
->wState
& CBF_DROPPED
) && !(lphc
->wState
& CBF_NOROLLUP
) )
928 CBRollUp( lphc
, (HIWORD(wParam
) == LBN_SELCHANGE
), TRUE
);
929 else lphc
->wState
&= ~CBF_NOROLLUP
;
931 CB_NOTIFY( lphc
, CBN_SELCHANGE
);
932 CBPaintText( lphc
, 0 );
937 /* nothing to do here since ComboLBox always resets the focus to its
938 * combo/edit counterpart */
945 /***********************************************************************
948 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
950 static LRESULT
COMBO_ItemOp( LPHEADCOMBO lphc
, UINT msg
,
951 WPARAM wParam
, LPARAM lParam
)
953 HWND hWnd
= lphc
->self
->hwndSelf
;
955 TRACE(combo
,"[%04x]: ownerdraw op %04x\n", CB_HWND(lphc
), msg
);
957 #define lpIS ((LPDELETEITEMSTRUCT)lParam)
959 /* two first items are the same in all 4 structs */
960 lpIS
->CtlType
= ODT_COMBOBOX
;
961 lpIS
->CtlID
= lphc
->self
->wIDmenu
;
963 switch( msg
) /* patch window handle */
966 lpIS
->hwndItem
= hWnd
;
970 #define lpIS ((LPDRAWITEMSTRUCT)lParam)
971 lpIS
->hwndItem
= hWnd
;
975 #define lpIS ((LPCOMPAREITEMSTRUCT)lParam)
976 lpIS
->hwndItem
= hWnd
;
981 return SendMessageA( lphc
->owner
, msg
, lphc
->self
->wIDmenu
, lParam
);
984 /***********************************************************************
987 static LRESULT
COMBO_GetText( LPHEADCOMBO lphc
, UINT N
, LPSTR lpText
)
989 if( lphc
->wState
& CBF_EDIT
)
990 return SendMessageA( lphc
->hWndEdit
, WM_GETTEXT
,
991 (WPARAM
)N
, (LPARAM
)lpText
);
993 /* get it from the listbox */
997 INT idx
= SendMessageA( lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0 );
1001 INT length
= SendMessageA( lphc
->hWndLBox
, LB_GETTEXTLEN
,
1004 /* 'length' is without the terminating character */
1006 lpBuffer
= (LPSTR
) HeapAlloc( GetProcessHeap(), 0, length
+ 1 );
1012 INT n
= SendMessageA( lphc
->hWndLBox
, LB_GETTEXT
,
1013 (WPARAM
)idx
, (LPARAM
)lpBuffer
);
1015 /* truncate if buffer is too short */
1020 if( n
!= LB_ERR
) memcpy( lpText
, lpBuffer
, (N
>n
) ? n
+1 : N
-1 );
1021 lpText
[N
- 1] = '\0';
1023 HeapFree( GetProcessHeap(), 0, lpBuffer
);
1033 /***********************************************************************
1036 * This function sets window positions according to the updated
1037 * component placement struct.
1039 static void CBResetPos( LPHEADCOMBO lphc
, LPRECT lbRect
, BOOL bRedraw
)
1041 BOOL bDrop
= (CB_GETTYPE(lphc
) != CBS_SIMPLE
);
1043 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1044 * sizing messages */
1046 if( lphc
->wState
& CBF_EDIT
)
1047 SetWindowPos( lphc
->hWndEdit
, 0, lphc
->RectEdit
.left
, lphc
->RectEdit
.top
,
1048 lphc
->RectEdit
.right
- lphc
->RectEdit
.left
,
1049 lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
,
1050 SWP_NOZORDER
| SWP_NOACTIVATE
| ((bDrop
) ? SWP_NOREDRAW
: 0) );
1053 OffsetRect( lbRect
, lphc
->RectCombo
.left
, lphc
->RectCombo
.top
);
1055 lbRect
->right
-= lbRect
->left
; /* convert to width */
1056 lbRect
->bottom
-= lbRect
->top
;
1057 SetWindowPos( lphc
->hWndLBox
, 0, lbRect
->left
, lbRect
->top
,
1058 lbRect
->right
, lbRect
->bottom
,
1059 SWP_NOACTIVATE
| SWP_NOZORDER
| ((bDrop
) ? SWP_NOREDRAW
: 0) );
1063 if( lphc
->wState
& CBF_DROPPED
)
1065 lphc
->wState
&= ~CBF_DROPPED
;
1066 ShowWindow( lphc
->hWndLBox
, SW_HIDE
);
1069 lphc
->wState
|= CBF_NORESIZE
;
1070 SetWindowPos( lphc
->self
->hwndSelf
, 0, 0, 0,
1071 lphc
->RectCombo
.right
- lphc
->RectCombo
.left
,
1072 lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
,
1073 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
);
1074 lphc
->wState
&= ~CBF_NORESIZE
;
1076 if( bRedraw
&& !(lphc
->wState
& CBF_NOREDRAW
) )
1077 RedrawWindow( lphc
->self
->hwndSelf
, NULL
, 0,
1078 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
);
1083 /***********************************************************************
1086 static void COMBO_Size( LPHEADCOMBO lphc
)
1091 GetWindowRect( lphc
->self
->hwndSelf
, &rect
);
1092 w
= rect
.right
- rect
.left
; h
= rect
.bottom
- rect
.top
;
1094 TRACE(combo
,"w = %i, h = %i\n", w
, h
);
1096 /* CreateWindow() may send a bogus WM_SIZE, ignore it */
1098 if( w
== (lphc
->RectCombo
.right
- lphc
->RectCombo
.left
) )
1100 if( (CB_GETTYPE(lphc
) == CBS_SIMPLE
) &&
1101 (h
== (lphc
->RectCombo
.bottom
- lphc
->RectCombo
.top
)) )
1103 else if( (lphc
->dwStyle
& CBS_DROPDOWN
) &&
1104 (h
== (lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
)) )
1107 lphc
->RectCombo
= rect
;
1108 CBCalcPlacement( lphc
, &lphc
->RectEdit
, &lphc
->RectButton
, &rect
);
1109 CBResetPos( lphc
, &rect
, TRUE
);
1113 /***********************************************************************
1116 static void COMBO_Font( LPHEADCOMBO lphc
, HFONT hFont
, BOOL bRedraw
)
1120 lphc
->hFont
= hFont
;
1122 if( lphc
->wState
& CBF_EDIT
)
1123 SendMessageA( lphc
->hWndEdit
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1124 SendMessageA( lphc
->hWndLBox
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1126 GetWindowRect( lphc
->self
->hwndSelf
, &rect
);
1127 OffsetRect( &lphc
->RectCombo
, rect
.left
- lphc
->RectCombo
.left
,
1128 rect
.top
- lphc
->RectCombo
.top
);
1129 CBCalcPlacement( lphc
, &lphc
->RectEdit
,
1130 &lphc
->RectButton
, &rect
);
1131 CBResetPos( lphc
, &rect
, bRedraw
);
1135 /***********************************************************************
1136 * COMBO_SetItemHeight
1138 static LRESULT
COMBO_SetItemHeight( LPHEADCOMBO lphc
, INT index
, INT height
)
1140 LRESULT lRet
= CB_ERR
;
1142 if( index
== -1 ) /* set text field height */
1144 if( height
< 32768 )
1148 lphc
->editHeight
= height
;
1149 GetWindowRect( lphc
->self
->hwndSelf
, &rect
);
1150 OffsetRect( &lphc
->RectCombo
, rect
.left
- lphc
->RectCombo
.left
,
1151 rect
.top
- lphc
->RectCombo
.top
);
1152 CBCalcPlacement( lphc
, &lphc
->RectEdit
,
1153 &lphc
->RectButton
, &rect
);
1154 CBResetPos( lphc
, &rect
, TRUE
);
1158 else if ( CB_OWNERDRAWN(lphc
) ) /* set listbox item height */
1159 lRet
= SendMessageA( lphc
->hWndLBox
, LB_SETITEMHEIGHT
,
1160 (WPARAM
)index
, (LPARAM
)height
);
1164 /***********************************************************************
1165 * COMBO_SelectString
1167 static LRESULT
COMBO_SelectString( LPHEADCOMBO lphc
, INT start
, LPCSTR pText
)
1169 INT index
= SendMessageA( lphc
->hWndLBox
, LB_SELECTSTRING
,
1170 (WPARAM
)start
, (LPARAM
)pText
);
1173 if( lphc
->wState
& CBF_EDIT
)
1174 CBUpdateEdit( lphc
, index
);
1176 CBPaintText( lphc
, 0 );
1178 return (LRESULT
)index
;
1181 /***********************************************************************
1184 static void COMBO_LButtonDown( LPHEADCOMBO lphc
, LPARAM lParam
)
1186 POINT pt
= { LOWORD(lParam
), HIWORD(lParam
) };
1187 BOOL bButton
= PtInRect(&lphc
->RectButton
, pt
);
1188 HWND hWnd
= lphc
->self
->hwndSelf
;
1190 if( (CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
) ||
1191 (bButton
&& (CB_GETTYPE(lphc
) == CBS_DROPDOWN
)) )
1193 lphc
->wState
|= CBF_BUTTONDOWN
;
1194 if( lphc
->wState
& CBF_DROPPED
)
1196 /* got a click to cancel selection */
1198 CBRollUp( lphc
, TRUE
, FALSE
);
1199 if( !IsWindow( hWnd
) ) return;
1201 if( lphc
->wState
& CBF_CAPTURE
)
1203 lphc
->wState
&= ~CBF_CAPTURE
;
1206 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1210 /* drop down the listbox and start tracking */
1212 lphc
->wState
|= CBF_CAPTURE
;
1216 if( bButton
) CBRepaintButton( lphc
);
1220 /***********************************************************************
1223 * Release capture and stop tracking if needed.
1225 static void COMBO_LButtonUp( LPHEADCOMBO lphc
, LPARAM lParam
)
1227 if( lphc
->wState
& CBF_CAPTURE
)
1229 lphc
->wState
&= ~CBF_CAPTURE
;
1230 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1232 INT index
= CBUpdateLBox( lphc
);
1233 CBUpdateEdit( lphc
, index
);
1238 if( lphc
->wState
& CBF_BUTTONDOWN
)
1240 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1241 CBRepaintButton( lphc
);
1245 /***********************************************************************
1248 * Two things to do - track combo button and release capture when
1249 * pointer goes into the listbox.
1251 static void COMBO_MouseMove( LPHEADCOMBO lphc
, WPARAM wParam
, LPARAM lParam
)
1253 POINT pt
= { LOWORD(lParam
), HIWORD(lParam
) };
1256 if( lphc
->wState
& CBF_BUTTONDOWN
)
1258 BOOL bButton
= PtInRect(&lphc
->RectButton
, pt
);
1262 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1263 CBRepaintButton( lphc
);
1267 GetClientRect( lphc
->hWndLBox
, &lbRect
);
1268 MapWindowPoints( lphc
->self
->hwndSelf
, lphc
->hWndLBox
, &pt
, 1 );
1269 if( PtInRect(&lbRect
, pt
) )
1271 lphc
->wState
&= ~CBF_CAPTURE
;
1273 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
) CBUpdateLBox( lphc
);
1275 /* hand over pointer tracking */
1276 SendMessageA( lphc
->hWndLBox
, WM_LBUTTONDOWN
, wParam
, lParam
);
1281 /***********************************************************************
1284 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
1286 LRESULT WINAPI
ComboWndProc( HWND hwnd
, UINT message
,
1287 WPARAM wParam
, LPARAM lParam
)
1289 WND
* pWnd
= WIN_FindWndPtr(hwnd
);
1293 LPHEADCOMBO lphc
= CB_GETPTR(pWnd
);
1295 TRACE(combo
, "[%04x]: msg %s wp %08x lp %08lx\n",
1296 pWnd
->hwndSelf
, SPY_GetMsgName(message
), wParam
, lParam
);
1298 if( lphc
|| message
== WM_NCCREATE
)
1302 /* System messages */
1305 return COMBO_NCCreate(pWnd
, lParam
);
1308 COMBO_NCDestroy(lphc
);
1312 return COMBO_Create(lphc
, pWnd
, lParam
);
1315 /* wParam may contain a valid HDC! */
1316 return COMBO_Paint(lphc
, wParam
);
1322 return (LRESULT
)(DLGC_WANTARROWS
| DLGC_WANTCHARS
);
1325 if( lphc
->hWndLBox
&&
1326 !(lphc
->wState
& CBF_NORESIZE
) ) COMBO_Size( lphc
);
1330 COMBO_Font( lphc
, (HFONT16
)wParam
, (BOOL
)lParam
);
1334 return (LRESULT
)lphc
->hFont
;
1337 if( lphc
->wState
& CBF_EDIT
)
1338 SetFocus( lphc
->hWndEdit
);
1340 COMBO_SetFocus( lphc
);
1344 #define hwndFocus ((HWND16)wParam)
1346 (hwndFocus
!= lphc
->hWndEdit
&& hwndFocus
!= lphc
->hWndLBox
))
1347 COMBO_KillFocus( lphc
);
1352 return COMBO_Command( lphc
, wParam
, (HWND
)lParam
);
1355 return COMBO_GetText( lphc
, (UINT
)wParam
, (LPSTR
)lParam
);
1358 case WM_GETTEXTLENGTH
:
1363 if( lphc
->wState
& CBF_EDIT
)
1364 return SendMessageA( lphc
->hWndEdit
, message
, wParam
, lParam
);
1369 case WM_COMPAREITEM
:
1370 case WM_MEASUREITEM
:
1371 return COMBO_ItemOp( lphc
, message
, wParam
, lParam
);
1374 if( lphc
->wState
& CBF_EDIT
)
1375 EnableWindow( lphc
->hWndEdit
, (BOOL
)wParam
);
1376 EnableWindow( lphc
->hWndLBox
, (BOOL
)wParam
);
1381 lphc
->wState
&= ~CBF_NOREDRAW
;
1383 lphc
->wState
|= CBF_NOREDRAW
;
1385 if( lphc
->wState
& CBF_EDIT
)
1386 SendMessageA( lphc
->hWndEdit
, message
, wParam
, lParam
);
1387 SendMessageA( lphc
->hWndLBox
, message
, wParam
, lParam
);
1391 if( KEYDATA_ALT
& HIWORD(lParam
) )
1392 if( wParam
== VK_UP
|| wParam
== VK_DOWN
)
1393 COMBO_FlipListbox( lphc
, TRUE
);
1398 if( lphc
->wState
& CBF_EDIT
)
1399 return SendMessageA( lphc
->hWndEdit
, message
, wParam
, lParam
);
1401 return SendMessageA( lphc
->hWndLBox
, message
, wParam
, lParam
);
1403 case WM_LBUTTONDOWN
:
1404 if( !(lphc
->wState
& CBF_FOCUSED
) ) SetFocus( lphc
->self
->hwndSelf
);
1405 if( lphc
->wState
& CBF_FOCUSED
) COMBO_LButtonDown( lphc
, lParam
);
1409 COMBO_LButtonUp( lphc
, lParam
);
1413 if( lphc
->wState
& CBF_CAPTURE
)
1414 COMBO_MouseMove( lphc
, wParam
, lParam
);
1417 /* Combo messages */
1419 case CB_ADDSTRING16
:
1420 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
1422 return SendMessageA( lphc
->hWndLBox
, LB_ADDSTRING
, 0, lParam
);
1424 case CB_INSERTSTRING16
:
1425 wParam
= (INT
)(INT16
)wParam
;
1426 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
1427 case CB_INSERTSTRING
:
1428 return SendMessageA( lphc
->hWndLBox
, LB_INSERTSTRING
, wParam
, lParam
);
1430 case CB_DELETESTRING16
:
1431 case CB_DELETESTRING
:
1432 return SendMessageA( lphc
->hWndLBox
, LB_DELETESTRING
, wParam
, 0);
1434 case CB_SELECTSTRING16
:
1435 wParam
= (INT
)(INT16
)wParam
;
1436 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
1437 case CB_SELECTSTRING
:
1438 return COMBO_SelectString( lphc
, (INT
)wParam
, (LPSTR
)lParam
);
1440 case CB_FINDSTRING16
:
1441 wParam
= (INT
)(INT16
)wParam
;
1442 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
1444 return SendMessageA( lphc
->hWndLBox
, LB_FINDSTRING
, wParam
, lParam
);
1446 case CB_FINDSTRINGEXACT16
:
1447 wParam
= (INT
)(INT16
)wParam
;
1448 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
1449 case CB_FINDSTRINGEXACT
:
1450 return SendMessageA( lphc
->hWndLBox
, LB_FINDSTRINGEXACT
,
1452 case CB_SETITEMHEIGHT16
:
1453 wParam
= (INT
)(INT16
)wParam
; /* signed integer */
1454 case CB_SETITEMHEIGHT
:
1455 return COMBO_SetItemHeight( lphc
, (INT
)wParam
, (INT
)lParam
);
1457 case CB_GETITEMHEIGHT16
:
1458 wParam
= (INT
)(INT16
)wParam
;
1459 case CB_GETITEMHEIGHT
:
1460 if( (INT
)wParam
>= 0 ) /* listbox item */
1461 return SendMessageA( lphc
->hWndLBox
, LB_GETITEMHEIGHT
, wParam
, 0);
1462 return (lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
);
1464 case CB_RESETCONTENT16
:
1465 case CB_RESETCONTENT
:
1466 SendMessageA( lphc
->hWndLBox
, LB_RESETCONTENT
, 0, 0 );
1467 CBPaintText( lphc
, 0 );
1470 case CB_INITSTORAGE
:
1471 return SendMessageA( lphc
->hWndLBox
, LB_INITSTORAGE
, wParam
, lParam
);
1473 case CB_GETHORIZONTALEXTENT
:
1474 return SendMessageA( lphc
->hWndLBox
, LB_GETHORIZONTALEXTENT
, 0, 0);
1476 case CB_SETHORIZONTALEXTENT
:
1477 return SendMessageA( lphc
->hWndLBox
, LB_SETHORIZONTALEXTENT
, wParam
, 0);
1479 case CB_GETTOPINDEX
:
1480 return SendMessageA( lphc
->hWndLBox
, LB_GETTOPINDEX
, 0, 0);
1483 return SendMessageA( lphc
->hWndLBox
, LB_GETLOCALE
, 0, 0);
1486 return SendMessageA( lphc
->hWndLBox
, LB_SETLOCALE
, wParam
, 0);
1488 case CB_GETDROPPEDWIDTH
:
1489 if( lphc
->droppedWidth
)
1490 return lphc
->droppedWidth
;
1491 return lphc
->RectCombo
.right
- lphc
->RectCombo
.left
-
1492 (lphc
->wState
& CBF_EDIT
) ? CBitOffset
: 0;
1494 case CB_SETDROPPEDWIDTH
:
1495 if( (CB_GETTYPE(lphc
) != CBS_SIMPLE
) &&
1496 (INT
)wParam
< 32768 ) lphc
->droppedWidth
= (INT
)wParam
;
1499 case CB_GETDROPPEDCONTROLRECT16
:
1500 lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
1504 CBGetDroppedControlRect( lphc
, &r
);
1505 CONV_RECT32TO16( &r
, (LPRECT16
)lParam
);
1509 case CB_GETDROPPEDCONTROLRECT
:
1510 if( lParam
) CBGetDroppedControlRect(lphc
, (LPRECT
)lParam
);
1513 case CB_GETDROPPEDSTATE16
:
1514 case CB_GETDROPPEDSTATE
:
1515 return (lphc
->wState
& CBF_DROPPED
) ? TRUE
: FALSE
;
1518 lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
1521 return COMBO_Directory( lphc
, (UINT
)wParam
,
1522 (LPSTR
)lParam
, (message
== CB_DIR
));
1523 case CB_SHOWDROPDOWN16
:
1524 case CB_SHOWDROPDOWN
:
1525 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
1529 if( !(lphc
->wState
& CBF_DROPPED
) )
1533 if( lphc
->wState
& CBF_DROPPED
)
1534 CBRollUp( lphc
, FALSE
, TRUE
);
1540 return SendMessageA( lphc
->hWndLBox
, LB_GETCOUNT
, 0, 0);
1542 case CB_GETCURSEL16
:
1544 return SendMessageA( lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1546 case CB_SETCURSEL16
:
1547 wParam
= (INT
)(INT16
)wParam
;
1549 lParam
= SendMessageA( lphc
->hWndLBox
, LB_SETCURSEL
, wParam
, 0);
1550 if( lphc
->wState
& CBF_SELCHANGE
)
1552 /* no LBN_SELCHANGE in this case, update manually */
1554 CBPaintText( lphc
, 0 );
1555 lphc
->wState
&= ~CBF_SELCHANGE
;
1559 case CB_GETLBTEXT16
:
1560 wParam
= (INT
)(INT16
)wParam
;
1561 lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
1563 return SendMessageA( lphc
->hWndLBox
, LB_GETTEXT
, wParam
, lParam
);
1565 case CB_GETLBTEXTLEN16
:
1566 wParam
= (INT
)(INT16
)wParam
;
1567 case CB_GETLBTEXTLEN
:
1568 return SendMessageA( lphc
->hWndLBox
, LB_GETTEXTLEN
, wParam
, 0);
1570 case CB_GETITEMDATA16
:
1571 wParam
= (INT
)(INT16
)wParam
;
1572 case CB_GETITEMDATA
:
1573 return SendMessageA( lphc
->hWndLBox
, LB_GETITEMDATA
, wParam
, 0);
1575 case CB_SETITEMDATA16
:
1576 wParam
= (INT
)(INT16
)wParam
;
1577 case CB_SETITEMDATA
:
1578 return SendMessageA( lphc
->hWndLBox
, LB_SETITEMDATA
, wParam
, lParam
);
1580 case CB_GETEDITSEL16
:
1581 wParam
= lParam
= 0; /* just in case */
1583 if( lphc
->wState
& CBF_EDIT
)
1587 return SendMessageA( lphc
->hWndEdit
, EM_GETSEL
,
1588 (wParam
) ? wParam
: (WPARAM
)&a
,
1589 (lParam
) ? lParam
: (LPARAM
)&b
);
1593 case CB_SETEDITSEL16
:
1595 if( lphc
->wState
& CBF_EDIT
)
1596 return SendMessageA( lphc
->hWndEdit
, EM_SETSEL
,
1597 (INT
)(INT16
)LOWORD(lParam
), (INT
)(INT16
)HIWORD(lParam
) );
1600 case CB_SETEXTENDEDUI16
:
1601 case CB_SETEXTENDEDUI
:
1602 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
) return CB_ERR
;
1605 lphc
->wState
|= CBF_EUI
;
1606 else lphc
->wState
&= ~CBF_EUI
;
1609 case CB_GETEXTENDEDUI16
:
1610 case CB_GETEXTENDEDUI
:
1611 return (lphc
->wState
& CBF_EUI
) ? TRUE
: FALSE
;
1613 case (WM_USER
+ 0x1B):
1614 WARN(combo
, "[%04x]: undocumented msg!\n", hwnd
);
1616 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);