4 * Copyright 1997 Alex Korobka
6 * FIXME: roll up in Netscape 3.01.
12 #include <user32/sysmetr.h>
13 #include <user32/win.h>
15 #include <user32/heapdup.h>
16 #include <user32/combo.h>
17 #include <user32/debug.h>
19 /* bits in the dwKeyData */
20 #define KEYDATA_ALT 0x2000
21 #define KEYDATA_PREVSTATE 0x4000
24 * Additional combo box definitions
27 #define CB_GETPTR( wnd ) (*(LPHEADCOMBO*)((wnd)->wExtra))
28 #define CB_NOTIFY( lphc, code ) \
29 (SendMessageA( (lphc)->owner, WM_COMMAND, \
30 MAKEWPARAM((lphc)->self->wIDmenu, (code)), (LPARAM)(lphc)->self->hwndSelf))
31 #define CB_GETEDITTEXTLENGTH( lphc ) \
32 (SendMessageA( (lphc)->hWndEdit, WM_GETTEXTLENGTH, 0, 0 ))
34 static HBITMAP hComboBmp
= 0;
35 static UINT CBitHeight
, CBitWidth
;
36 static UINT CBitOffset
= 8;
38 /***********************************************************************
41 * Load combo button bitmap.
43 WINBOOL
COMBO_Init(void)
47 if( hComboBmp
) return TRUE
;
48 if( (hDC
= CreateCompatibleDC(0)) )
51 if( (hComboBmp
= LoadBitmap(0, MAKEINTRESOURCE(OBM_COMBO
))) )
57 GetObjectA( hComboBmp
, sizeof(bm
), &bm
);
58 CBitHeight
= bm
.bmHeight
;
59 CBitWidth
= bm
.bmWidth
;
61 DPRINT( "combo bitmap [%i,%i]\n", CBitWidth
, CBitHeight
);
63 hPrevB
= SelectObject( hDC
, hComboBmp
);
64 SetRect( &r
, 0, 0, CBitWidth
, CBitHeight
);
65 InvertRect( hDC
, &r
);
66 SelectObject( hDC
, hPrevB
);
75 /***********************************************************************
78 static LRESULT
COMBO_NCCreate(WND
* wnd
, LPARAM lParam
)
82 if ( wnd
&& COMBO_Init() &&
83 (lphc
= HeapAlloc(GetProcessHeap(), 0, sizeof(HEADCOMBO
))) )
85 LPCREATESTRUCT lpcs
= (CREATESTRUCT
*)lParam
;
87 memset( lphc
, 0, sizeof(HEADCOMBO
) );
88 *(LPHEADCOMBO
*)wnd
->wExtra
= lphc
;
90 /* some braindead apps do try to use scrollbar/border flags */
92 lphc
->dwStyle
= (lpcs
->style
& ~(WS_BORDER
| WS_HSCROLL
| WS_VSCROLL
));
93 wnd
->dwStyle
&= ~(WS_BORDER
| WS_HSCROLL
| WS_VSCROLL
);
95 if( !(lpcs
->style
& (CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
)) )
96 lphc
->dwStyle
|= CBS_HASSTRINGS
;
97 if( !(wnd
->dwExStyle
& WS_EX_NOPARENTNOTIFY
) )
98 lphc
->wState
|= CBF_NOTIFY
;
100 DPRINT( "[0x%08x], style = %08x\n",
101 (UINT
)lphc
, lphc
->dwStyle
);
103 return (LRESULT
)(UINT
)wnd
->hwndSelf
;
105 return (LRESULT
)FALSE
;
108 /***********************************************************************
111 static LRESULT
COMBO_NCDestroy( LPHEADCOMBO lphc
)
116 WND
* wnd
= lphc
->self
;
118 DPRINT("[%04x]: freeing storage\n", CB_HWND(lphc
));
120 if( (CB_GETTYPE(lphc
) != CBS_SIMPLE
) && lphc
->hWndLBox
)
121 DestroyWindow( lphc
->hWndLBox
);
123 HeapFree( GetProcessHeap(), 0, lphc
);
129 /***********************************************************************
130 * CBGetDefaultTextHeight
132 static void CBGetDefaultTextHeight( LPHEADCOMBO lphc
, LPSIZE lpSize
)
134 if( lphc
->editHeight
) /* explicitly set height */
135 lpSize
->cy
= lphc
->editHeight
;
138 HDC hDC
= GetDC( lphc
->self
->hwndSelf
);
141 if( lphc
->hFont
) hPrevFont
= SelectObject( hDC
, lphc
->hFont
);
143 GetTextExtentPointA( hDC
, "0", 1, lpSize
);
145 lpSize
->cy
+= lpSize
->cy
/ 4 + 4 * SYSMETRICS_CYBORDER
;
147 if( hPrevFont
) SelectObject( hDC
, hPrevFont
);
148 ReleaseDC( lphc
->self
->hwndSelf
, hDC
);
150 lpSize
->cx
= lphc
->RectCombo
.right
- lphc
->RectCombo
.left
;
154 /***********************************************************************
157 * Set up component coordinates given valid lphc->RectCombo.
159 static void CBCalcPlacement( LPHEADCOMBO lphc
, LPRECT lprEdit
,
160 LPRECT lprButton
, LPRECT lprLB
)
162 RECT rect
= lphc
->RectCombo
;
165 /* get combo height and width */
167 if( CB_OWNERDRAWN(lphc
) )
169 UINT u
= lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
;
171 if( lphc
->wState
& CBF_MEASUREITEM
) /* first initialization */
173 MEASUREITEMSTRUCT mi
;
175 /* calculate defaults before sending WM_MEASUREITEM */
177 CBGetDefaultTextHeight( lphc
, &size
);
179 lphc
->wState
&= ~CBF_MEASUREITEM
;
181 mi
.CtlType
= ODT_COMBOBOX
;
182 mi
.CtlID
= lphc
->self
->wIDmenu
;
184 mi
.itemWidth
= size
.cx
;
185 mi
.itemHeight
= size
.cy
- 6; /* ownerdrawn cb is taller */
187 SendMessageA(lphc
->owner
, WM_MEASUREITEM
,
188 (WPARAM
)mi
.CtlID
, (LPARAM
)&mi
);
189 u
= 6 + (UINT
)mi
.itemHeight
;
192 size
.cx
= rect
.right
- rect
.left
;
196 CBGetDefaultTextHeight( lphc
, &size
);
198 /* calculate text and button placement */
200 lprEdit
->left
= lprEdit
->top
= lprButton
->top
= 0;
201 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
) /* no button */
202 lprButton
->left
= lprButton
->right
= lprButton
->bottom
= 0;
205 INT i
= size
.cx
- CBitWidth
- 10; /* seems ok */
207 lprButton
->right
= size
.cx
;
208 lprButton
->left
= (INT
)i
;
209 lprButton
->bottom
= lprButton
->top
+ size
.cy
;
211 if( i
< 0 ) size
.cx
= 0;
215 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
217 size
.cx
-= CBitOffset
;
218 if( size
.cx
< 0 ) size
.cx
= 0;
221 lprEdit
->right
= size
.cx
; lprEdit
->bottom
= size
.cy
;
223 /* listbox placement */
225 lprLB
->left
= ( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
) ? 0 : CBitOffset
;
226 lprLB
->top
= lprEdit
->bottom
- SYSMETRICS_CYBORDER
;
227 lprLB
->right
= rect
.right
- rect
.left
;
228 lprLB
->bottom
= rect
.bottom
- rect
.top
;
230 if( lphc
->droppedWidth
> (lprLB
->right
- lprLB
->left
) )
231 lprLB
->right
= lprLB
->left
+ lphc
->droppedWidth
;
233 DPRINT("[%04x]: (%i,%i-%i,%i) placement\n",
234 CB_HWND(lphc
), lphc
->RectCombo
.left
, lphc
->RectCombo
.top
,
235 lphc
->RectCombo
.right
, lphc
->RectCombo
.bottom
);
237 DPRINT("\ttext\t= (%i,%i-%i,%i)\n",
238 lprEdit
->left
, lprEdit
->top
, lprEdit
->right
, lprEdit
->bottom
);
240 DPRINT("\tbutton\t= (%i,%i-%i,%i)\n",
241 lprButton
->left
, lprButton
->top
, lprButton
->right
, lprButton
->bottom
);
243 DPRINT("\tlbox\t= (%i,%i-%i,%i)\n",
244 lprLB
->left
, lprLB
->top
, lprLB
->right
, lprLB
->bottom
);
247 /***********************************************************************
248 * CBGetDroppedControlRect
250 static void CBGetDroppedControlRect( LPHEADCOMBO lphc
, LPRECT lpRect
)
252 lpRect
->left
= lphc
->RectCombo
.left
+
253 (lphc
->wState
& CBF_EDIT
) ? CBitOffset
: 0;
254 lpRect
->top
= lphc
->RectCombo
.top
+ lphc
->RectEdit
.bottom
-
256 lpRect
->right
= lphc
->RectCombo
.right
;
257 lpRect
->bottom
= lphc
->RectCombo
.bottom
- SYSMETRICS_CYBORDER
;
260 /***********************************************************************
263 LRESULT
COMBO_Create( LPHEADCOMBO lphc
, WND
* wnd
, LPARAM lParam
)
265 static char clbName
[] = "ComboLBox";
266 static char editName
[] = "Edit";
268 LPCREATESTRUCT lpcs
= (CREATESTRUCT
*)lParam
;
270 if( !CB_GETTYPE(lphc
) ) lphc
->dwStyle
|= CBS_SIMPLE
;
271 else if( CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
) lphc
->wState
|= CBF_EDIT
;
274 lphc
->owner
= lpcs
->hwndParent
;
276 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
278 if( lphc
->owner
|| !(lpcs
->style
& WS_VISIBLE
) )
281 RECT editRect
, btnRect
, lbRect
;
283 GetWindowRect( wnd
->hwndSelf
, &lphc
->RectCombo
);
285 lphc
->wState
|= CBF_MEASUREITEM
;
286 CBCalcPlacement( lphc
, &editRect
, &btnRect
, &lbRect
);
287 lphc
->RectButton
= btnRect
;
288 lphc
->droppedWidth
= lphc
->editHeight
= 0;
290 /* create listbox popup */
292 lbeStyle
= (LBS_NOTIFY
| WS_BORDER
| WS_CLIPSIBLINGS
) |
293 (lpcs
->style
& (WS_VSCROLL
| CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
));
295 if( lphc
->dwStyle
& CBS_SORT
)
296 lbeStyle
|= LBS_SORT
;
297 if( lphc
->dwStyle
& CBS_HASSTRINGS
)
298 lbeStyle
|= LBS_HASSTRINGS
;
299 if( lphc
->dwStyle
& CBS_NOINTEGRALHEIGHT
)
300 lbeStyle
|= LBS_NOINTEGRALHEIGHT
;
301 if( lphc
->dwStyle
& CBS_DISABLENOSCROLL
)
302 lbeStyle
|= LBS_DISABLENOSCROLL
;
304 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
) /* child listbox */
305 lbeStyle
|= WS_CHILD
| WS_VISIBLE
;
306 else /* popup listbox */
308 lbeStyle
|= WS_POPUP
;
309 OffsetRect( &lbRect
, lphc
->RectCombo
.left
, lphc
->RectCombo
.top
);
312 /* Dropdown ComboLBox is not a child window and we cannot pass
313 * ID_CB_LISTBOX directly because it will be treated as a menu handle.
316 lphc
->hWndLBox
= CreateWindowExA( 0, clbName
, NULL
, lbeStyle
,
317 lbRect
.left
+ SYSMETRICS_CXBORDER
,
318 lbRect
.top
+ SYSMETRICS_CYBORDER
,
319 lbRect
.right
- lbRect
.left
- 2 * SYSMETRICS_CXBORDER
,
320 lbRect
.bottom
- lbRect
.top
- 2 * SYSMETRICS_CYBORDER
,
321 lphc
->self
->hwndSelf
,
322 (lphc
->dwStyle
& CBS_DROPDOWN
)? (HMENU
)0 : (HMENU
)ID_CB_LISTBOX
,
323 lphc
->self
->hInstance
, (LPVOID
)lphc
);
326 WINBOOL bEdit
= TRUE
;
327 lbeStyle
= WS_CHILD
| WS_VISIBLE
| WS_BORDER
| ES_NOHIDESEL
| ES_LEFT
;
328 if( lphc
->wState
& CBF_EDIT
)
330 if( lphc
->dwStyle
& CBS_OEMCONVERT
)
331 lbeStyle
|= ES_OEMCONVERT
;
332 if( lphc
->dwStyle
& CBS_AUTOHSCROLL
)
333 lbeStyle
|= ES_AUTOHSCROLL
;
334 if( lphc
->dwStyle
& CBS_LOWERCASE
)
335 lbeStyle
|= ES_LOWERCASE
;
336 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
337 lbeStyle
|= ES_UPPERCASE
;
338 lphc
->hWndEdit
= CreateWindowExA( 0, editName
, NULL
, lbeStyle
,
339 editRect
.left
, editRect
.top
, editRect
.right
- editRect
.left
,
340 editRect
.bottom
- editRect
.top
, lphc
->self
->hwndSelf
,
341 (HMENU
)ID_CB_EDIT
, lphc
->self
->hInstance
, NULL
);
342 if( !lphc
->hWndEdit
) bEdit
= FALSE
;
347 lphc
->RectEdit
= editRect
;
348 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
350 lphc
->wState
|= CBF_NORESIZE
;
351 SetWindowPos( wnd
->hwndSelf
, 0, 0, 0,
352 lphc
->RectCombo
.right
- lphc
->RectCombo
.left
,
353 lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
,
354 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
355 lphc
->wState
&= ~CBF_NORESIZE
;
357 DPRINT("init done\n");
358 return (LRESULT
)wnd
->hwndSelf
;
360 DPRINT("edit control failure.\n");
361 } else DPRINT("listbox failure.\n");
362 } else DPRINT("no owner for visible combo.\n");
364 /* CreateWindow() will send WM_NCDESTROY to cleanup */
369 /***********************************************************************
372 * Paint combo button (normal, pressed, and disabled states).
374 static void CBPaintButton(LPHEADCOMBO lphc
, HDC hdc
)
381 COLORREF oldTextColor
, oldBkColor
;
383 if( lphc
->wState
& CBF_NOREDRAW
) return;
385 hPrevBrush
= SelectObject(hdc
, GetSysColorBrush(COLOR_BTNFACE
));
386 r
= lphc
->RectButton
;
388 Rectangle(hdc
, r
.left
, r
.top
, r
.right
, r
.bottom
);
389 if( (bWINBOOL
= lphc
->wState
& CBF_BUTTONDOWN
) )
391 DrawEdge( hdc
, &r
, EDGE_SUNKEN
, BF_RECT
);
392 OffsetRect( &r
, 1, 1 );
395 DrawEdge( hdc
, &r
, EDGE_RAISED
, BF_RECT
);
399 InflateRect( &r
, -1, -1 );
401 x
= (r
.left
+ r
.right
- CBitWidth
) >> 1;
402 y
= (r
.top
+ r
.bottom
- CBitHeight
) >> 1;
404 InflateRect( &r
, -3, -3 );
406 hMemDC
= CreateCompatibleDC( hdc
);
407 SelectObject( hMemDC
, hComboBmp
);
408 oldTextColor
= SetTextColor( hdc
, GetSysColor(COLOR_BTNFACE
) );
409 oldBkColor
= SetBkColor( hdc
, CB_DISABLED(lphc
) ? RGB(128,128,128) :
411 BitBlt( hdc
, x
, y
, 8, 8, hMemDC
, 0, 0, SRCCOPY
);
412 SetBkColor( hdc
, oldBkColor
);
413 SetTextColor( hdc
, oldTextColor
);
415 SelectObject( hdc
, hPrevBrush
);
418 /***********************************************************************
421 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
423 static void CBPaintText(LPHEADCOMBO lphc
, HDC hdc
)
428 if( lphc
->wState
& CBF_NOREDRAW
) return;
430 /* follow Windows combobox that sends a bunch of text
431 * inquiries to its listbox while processing WM_PAINT. */
433 if( (id
= SendMessageA(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0) ) != LB_ERR
)
435 size
= SendMessageA( lphc
->hWndLBox
, LB_GETTEXTLEN
, id
, 0);
436 if( (pText
= HeapAlloc( GetProcessHeap(), 0, size
+ 1)) )
438 SendMessageA( lphc
->hWndLBox
, LB_GETTEXT
, (WPARAM
)id
, (LPARAM
)pText
);
439 pText
[size
] = '\0'; /* just in case */
443 if( lphc
->wState
& CBF_EDIT
)
445 if( CB_HASSTRINGS(lphc
) ) SetWindowTextA( lphc
->hWndEdit
, pText
? pText
: "" );
446 if( lphc
->wState
& CBF_FOCUSED
)
447 SendMessageA( lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1));
449 else /* paint text field ourselves */
451 HBRUSH hPrevBrush
= 0;
456 if ((hDC
= GetDC(lphc
->self
->hwndSelf
)))
458 HBRUSH hBrush
= (HBRUSH
)SendMessageA( lphc
->owner
,
460 (WPARAM
)hDC
, (LPARAM
)lphc
->self
->hwndSelf
);
461 hPrevBrush
= SelectObject( hDC
,
462 (hBrush
) ? hBrush
: GetStockObject(WHITE_BRUSH
) );
469 HFONT hPrevFont
= (lphc
->hFont
) ? SelectObject(hDC
, lphc
->hFont
) : 0;
471 PatBlt( hDC
, (rect
.left
= lphc
->RectEdit
.left
+ SYSMETRICS_CXBORDER
),
472 (rect
.top
= lphc
->RectEdit
.top
+ SYSMETRICS_CYBORDER
),
473 (rect
.right
= lphc
->RectEdit
.right
- SYSMETRICS_CXBORDER
),
474 (rect
.bottom
= lphc
->RectEdit
.bottom
- SYSMETRICS_CYBORDER
) - 1, PATCOPY
);
475 InflateRect( &rect
, -1, -1 );
477 if( lphc
->wState
& CBF_FOCUSED
&&
478 !(lphc
->wState
& CBF_DROPPED
) )
482 FillRect( hDC
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
483 SetBkColor( hDC
, GetSysColor( COLOR_HIGHLIGHT
) );
484 SetTextColor( hDC
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
485 itemState
= ODS_SELECTED
| ODS_FOCUS
;
486 } else itemState
= 0;
488 if( CB_OWNERDRAWN(lphc
) )
492 if( lphc
->self
->dwStyle
& WS_DISABLED
) itemState
|= ODS_DISABLED
;
494 dis
.CtlType
= ODT_COMBOBOX
;
495 dis
.CtlID
= lphc
->self
->wIDmenu
;
496 dis
.hwndItem
= lphc
->self
->hwndSelf
;
497 dis
.itemAction
= ODA_DRAWENTIRE
;
499 dis
.itemState
= itemState
;
502 dis
.itemData
= SendMessageA( lphc
->hWndLBox
, LB_GETITEMDATA
,
504 SendMessageA( lphc
->owner
, WM_DRAWITEM
,
505 lphc
->self
->wIDmenu
, (LPARAM
)&dis
);
509 ExtTextOutA( hDC
, rect
.left
+ 1, rect
.top
+ 1,
510 ETO_OPAQUE
| ETO_CLIPPED
, &rect
,
511 pText
? pText
: "" , size
, NULL
);
512 if(lphc
->wState
& CBF_FOCUSED
&& !(lphc
->wState
& CBF_DROPPED
))
513 DrawFocusRect( hDC
, &rect
);
516 if( hPrevFont
) SelectObject(hDC
, hPrevFont
);
519 if( hPrevBrush
) SelectObject( hDC
, hPrevBrush
);
520 ReleaseDC( lphc
->self
->hwndSelf
, hDC
);
525 HeapFree( GetProcessHeap(), 0, pText
);
528 /***********************************************************************
531 static LRESULT
COMBO_Paint(LPHEADCOMBO lphc
, HDC hParamDC
)
536 hDC
= (hParamDC
) ? hParamDC
537 : BeginPaint( lphc
->self
->hwndSelf
, &ps
);
538 if( hDC
&& !(lphc
->wState
& CBF_NOREDRAW
) )
540 HBRUSH hPrevBrush
, hBkgBrush
;
542 hBkgBrush
= (HBRUSH
)SendMessageA( lphc
->owner
, WM_CTLCOLORLISTBOX
,
543 (WPARAM
)hDC
, (LPARAM
)lphc
->self
->hwndSelf
);
544 if( !hBkgBrush
) hBkgBrush
= GetStockObject(WHITE_BRUSH
);
546 hPrevBrush
= SelectObject( hDC
, hBkgBrush
);
547 if( !IsRectEmpty(&lphc
->RectButton
) )
549 /* paint everything to the right of the text field */
551 PatBlt( hDC
, lphc
->RectEdit
.right
, lphc
->RectEdit
.top
,
552 lphc
->RectButton
.right
- lphc
->RectEdit
.right
,
553 lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
, PATCOPY
);
554 CBPaintButton( lphc
, hDC
);
557 if( !(lphc
->wState
& CBF_EDIT
) )
559 /* paint text field */
561 HPEN hPrevPen
= SelectObject( hDC
, GetSysColorPen(
562 COLOR_WINDOWFRAME
) );
564 Rectangle( hDC
, lphc
->RectEdit
.left
, lphc
->RectEdit
.top
,
565 lphc
->RectEdit
.right
, lphc
->RectButton
.bottom
);
566 SelectObject( hDC
, hPrevPen
);
567 CBPaintText( lphc
, hDC
);
569 if( hPrevBrush
) SelectObject( hDC
, hPrevBrush
);
571 if( !hParamDC
) EndPaint(lphc
->self
->hwndSelf
, &ps
);
575 /***********************************************************************
578 * Select listbox entry according to the contents of the edit control.
580 static INT
CBUpdateLBox( LPHEADCOMBO lphc
)
582 INT length
, idx
, ret
;
586 length
= CB_GETEDITTEXTLENGTH( lphc
);
589 pText
= (LPSTR
) HeapAlloc( GetProcessHeap(), 0, length
+ 1);
591 DPRINT("\t edit text length %i\n", length
);
595 if( length
) GetWindowTextA( lphc
->hWndEdit
, pText
, length
+ 1);
596 else pText
[0] = '\0';
597 idx
= SendMessageA( lphc
->hWndLBox
, LB_FINDSTRING
,
598 (WPARAM
)(-1), (LPARAM
)pText
);
599 if( idx
== LB_ERR
) idx
= 0; /* select first item */
601 HeapFree( GetProcessHeap(), 0, pText
);
606 SendMessageA( lphc
->hWndLBox
, LB_SETCURSEL
, (WPARAM
)idx
, 0 );
610 SendMessageA( lphc
->hWndLBox
, LB_SETTOPINDEX
, (WPARAM
)idx
, 0 );
611 /* probably superfluous but Windows sends this too */
612 SendMessageA( lphc
->hWndLBox
, LB_SETCARETINDEX
, (WPARAM
)idx
, 0 );
617 /***********************************************************************
620 * Copy a listbox entry to the edit control.
622 static void CBUpdateEdit( LPHEADCOMBO lphc
, INT index
)
627 DPRINT("\t %i\n", index
);
631 length
= CB_GETEDITTEXTLENGTH( lphc
);
634 if( (pText
= (LPSTR
) HeapAlloc( GetProcessHeap(), 0, length
+ 1)) )
636 GetWindowTextA( lphc
->hWndEdit
, pText
, length
+ 1 );
637 index
= SendMessageA( lphc
->hWndLBox
, LB_FINDSTRING
,
638 (WPARAM
)(-1), (LPARAM
)pText
);
639 HeapFree( GetProcessHeap(), 0, pText
);
644 if( index
>= 0 ) /* got an entry */
646 length
= SendMessageA( lphc
->hWndLBox
, LB_GETTEXTLEN
, (WPARAM
)index
, 0);
649 if( (pText
= (LPSTR
) HeapAlloc( GetProcessHeap(), 0, length
+ 1)) )
651 SendMessageA( lphc
->hWndLBox
, LB_GETTEXT
,
652 (WPARAM
)index
, (LPARAM
)pText
);
653 SendMessageA( lphc
->hWndEdit
, WM_SETTEXT
, 0, (LPARAM
)pText
);
654 SendMessageA( lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1) );
655 HeapFree( GetProcessHeap(), 0, pText
);
661 /***********************************************************************
664 * Show listbox popup.
666 static void CBDropDown( LPHEADCOMBO lphc
)
672 DPRINT("[%04x]: drop down\n", CB_HWND(lphc
));
674 CB_NOTIFY( lphc
, CBN_DROPDOWN
);
678 lphc
->wState
|= CBF_DROPPED
;
679 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
681 index
= CBUpdateLBox( lphc
);
682 if( !(lphc
->wState
& CBF_CAPTURE
) ) CBUpdateEdit( lphc
, index
);
686 index
= SendMessageA( lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0 );
687 if( index
== LB_ERR
) index
= 0;
688 SendMessageA( lphc
->hWndLBox
, LB_SETTOPINDEX
, (WPARAM
)index
, 0 );
689 SendMessageA( lphc
->hWndLBox
, LB_CARETON
, 0, 0 );
690 pRect
= &lphc
->RectEdit
;
693 /* now set popup position */
695 GetWindowRect( lphc
->self
->hwndSelf
, &rect
);
697 rect
.top
+= lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
- SYSMETRICS_CYBORDER
;
698 rect
.bottom
= rect
.top
+ lphc
->RectCombo
.bottom
-
699 lphc
->RectCombo
.top
- SYSMETRICS_CYBORDER
;
700 rect
.right
= rect
.left
+ lphc
->RectCombo
.right
- lphc
->RectCombo
.left
;
701 rect
.left
+= ( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
) ? 0 : CBitOffset
;
703 SetWindowPos( lphc
->hWndLBox
, HWND_TOP
, rect
.left
, rect
.top
,
704 rect
.right
- rect
.left
, rect
.bottom
- rect
.top
,
705 SWP_NOACTIVATE
| SWP_NOSIZE
| SWP_NOREDRAW
);
707 if( !(lphc
->wState
& CBF_NOREDRAW
) )
709 RedrawWindow( lphc
->self
->hwndSelf
, pRect
, 0, RDW_INVALIDATE
|
710 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
711 ShowWindow( lphc
->hWndLBox
, SW_SHOWNA
);
714 /***********************************************************************
717 * Hide listbox popup.
719 static void CBRollUp( LPHEADCOMBO lphc
, WINBOOL ok
, WINBOOL bButton
)
721 HWND hWnd
= lphc
->self
->hwndSelf
;
723 CB_NOTIFY( lphc
, (ok
) ? CBN_SELENDOK
: CBN_SELENDCANCEL
);
725 if( IsWindow( hWnd
) && CB_GETTYPE(lphc
) != CBS_SIMPLE
)
728 DPRINT("[%04x]: roll up [%i]\n", CB_HWND(lphc
), (INT
)ok
);
730 /* always send WM_LBUTTONUP? */
731 SendMessageA( lphc
->hWndLBox
, WM_LBUTTONUP
, 0, (LPARAM
)(-1) );
733 if( lphc
->wState
& CBF_DROPPED
)
737 lphc
->wState
&= ~CBF_DROPPED
;
738 ShowWindow( lphc
->hWndLBox
, SW_HIDE
);
740 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
742 INT index
= SendMessageA( lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0 );
743 CBUpdateEdit( lphc
, index
);
744 rect
= lphc
->RectButton
;
749 UnionRect( &rect
, &lphc
->RectButton
,
752 rect
= lphc
->RectEdit
;
756 if( bButton
&& !(lphc
->wState
& CBF_NOREDRAW
) )
757 RedrawWindow( hWnd
, &rect
, 0, RDW_INVALIDATE
|
758 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
759 CB_NOTIFY( lphc
, CBN_CLOSEUP
);
764 /***********************************************************************
767 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
769 WINBOOL
COMBO_FlipListbox( LPHEADCOMBO lphc
, WINBOOL bRedrawButton
)
771 if( lphc
->wState
& CBF_DROPPED
)
773 CBRollUp( lphc
, TRUE
, bRedrawButton
);
781 /***********************************************************************
784 * Edit control helper.
786 HWND
COMBO_GetLBWindow( WND
* pWnd
)
788 LPHEADCOMBO lphc
= CB_GETPTR(pWnd
);
789 if( lphc
) return lphc
->hWndLBox
;
794 /***********************************************************************
797 static void CBRepaintButton( LPHEADCOMBO lphc
)
799 HDC hDC
= GetDC( lphc
->self
->hwndSelf
);
803 CBPaintButton( lphc
, hDC
);
804 ReleaseDC( lphc
->self
->hwndSelf
, hDC
);
808 /***********************************************************************
811 static void COMBO_SetFocus( LPHEADCOMBO lphc
)
813 if( !(lphc
->wState
& CBF_FOCUSED
) )
815 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
816 SendMessageA( lphc
->hWndLBox
, LB_CARETON
, 0, 0 );
818 if( lphc
->wState
& CBF_EDIT
)
819 SendMessageA( lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1) );
820 lphc
->wState
|= CBF_FOCUSED
;
821 if( !(lphc
->wState
& CBF_EDIT
) ) CBPaintText( lphc
, 0 );
823 CB_NOTIFY( lphc
, CBN_SETFOCUS
);
827 /***********************************************************************
830 static void COMBO_KillFocus( LPHEADCOMBO lphc
)
832 HWND hWnd
= lphc
->self
->hwndSelf
;
834 if( lphc
->wState
& CBF_FOCUSED
)
836 SendMessageA( hWnd
, WM_LBUTTONUP
, 0, (LPARAM
)(-1) );
838 CBRollUp( lphc
, FALSE
, TRUE
);
839 if( IsWindow( hWnd
) )
841 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
842 SendMessageA( lphc
->hWndLBox
, LB_CARETOFF
, 0, 0 );
844 lphc
->wState
&= ~CBF_FOCUSED
;
847 if( lphc
->wState
& CBF_EDIT
)
848 SendMessageA( lphc
->hWndEdit
, EM_SETSEL
, (WPARAM
)(-1), 0 );
849 else CBPaintText( lphc
, 0 );
851 CB_NOTIFY( lphc
, CBN_KILLFOCUS
);
856 /***********************************************************************
859 static LRESULT
COMBO_Command( LPHEADCOMBO lphc
, WPARAM wParam
, HWND hWnd
)
861 if( lphc
->wState
& CBF_EDIT
&& lphc
->hWndEdit
== hWnd
)
863 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
865 switch( HIWORD(wParam
) >> 8 )
867 case (EN_SETFOCUS
>> 8):
869 DPRINT("[%04x]: edit [%04x] got focus\n",
870 CB_HWND(lphc
), lphc
->hWndEdit
);
872 if( !(lphc
->wState
& CBF_FOCUSED
) ) COMBO_SetFocus( lphc
);
875 case (EN_KILLFOCUS
>> 8):
877 DPRINT("[%04x]: edit [%04x] lost focus\n",
878 CB_HWND(lphc
), lphc
->hWndEdit
);
880 /* NOTE: it seems that Windows' edit control sends an
881 * undocumented message WM_USER + 0x1B instead of this
882 * notification (only when it happens to be a part of
883 * the combo). ?? - AK.
886 COMBO_KillFocus( lphc
);
890 case (EN_CHANGE
>> 8):
891 CB_NOTIFY( lphc
, CBN_EDITCHANGE
);
892 CBUpdateLBox( lphc
);
895 case (EN_UPDATE
>> 8):
896 CB_NOTIFY( lphc
, CBN_EDITUPDATE
);
899 case (EN_ERRSPACE
>> 8):
900 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
903 else if( lphc
->hWndLBox
== hWnd
)
905 switch( HIWORD(wParam
) )
908 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
912 CB_NOTIFY( lphc
, CBN_DBLCLK
);
918 DPRINT("[%04x]: lbox selection change [%04x]\n",
919 CB_HWND(lphc
), lphc
->wState
);
921 /* do not roll up if selection is being tracked
922 * by arrowkeys in the dropdown listbox */
924 if( (lphc
->wState
& CBF_DROPPED
) && !(lphc
->wState
& CBF_NOROLLUP
) )
925 CBRollUp( lphc
, (HIWORD(wParam
) == LBN_SELCHANGE
), TRUE
);
926 else lphc
->wState
&= ~CBF_NOROLLUP
;
928 CB_NOTIFY( lphc
, CBN_SELCHANGE
);
929 CBPaintText( lphc
, 0 );
934 /* nothing to do here since ComboLBox always resets the focus to its
935 * combo/edit counterpart */
942 /***********************************************************************
945 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
947 static LRESULT
COMBO_ItemOp( LPHEADCOMBO lphc
, UINT msg
,
948 WPARAM wParam
, LPARAM lParam
)
950 HWND hWnd
= lphc
->self
->hwndSelf
;
952 DPRINT("[%04x]: ownerdraw op %04x\n", CB_HWND(lphc
), msg
);
954 #define lpIS ((LPDELETEITEMSTRUCT)lParam)
956 /* two first items are the same in all 4 structs */
957 lpIS
->CtlType
= ODT_COMBOBOX
;
958 lpIS
->CtlID
= lphc
->self
->wIDmenu
;
960 switch( msg
) /* patch window handle */
963 lpIS
->hwndItem
= hWnd
;
967 #define lpIS ((LPDRAWITEMSTRUCT)lParam)
968 lpIS
->hwndItem
= hWnd
;
972 #define lpIS ((LPCOMPAREITEMSTRUCT)lParam)
973 lpIS
->hwndItem
= hWnd
;
978 return SendMessageA( lphc
->owner
, msg
, lphc
->self
->wIDmenu
, lParam
);
981 /***********************************************************************
984 static LRESULT
COMBO_GetText( LPHEADCOMBO lphc
, UINT N
, LPSTR lpText
)
986 if( lphc
->wState
& CBF_EDIT
)
987 return SendMessageA( lphc
->hWndEdit
, WM_GETTEXT
,
988 (WPARAM
)N
, (LPARAM
)lpText
);
990 /* get it from the listbox */
994 INT idx
= SendMessageA( lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0 );
998 INT length
= SendMessageA( lphc
->hWndLBox
, LB_GETTEXTLEN
,
1001 /* 'length' is without the terminating character */
1003 lpBuffer
= (LPSTR
) HeapAlloc( GetProcessHeap(), 0, length
+ 1 );
1009 INT n
= SendMessageA( lphc
->hWndLBox
, LB_GETTEXT
,
1010 (WPARAM
)idx
, (LPARAM
)lpBuffer
);
1012 /* truncate if buffer is too short */
1017 if( n
!= LB_ERR
) memcpy( lpText
, lpBuffer
, (N
>n
) ? n
+1 : N
-1 );
1018 lpText
[N
- 1] = '\0';
1020 HeapFree( GetProcessHeap(), 0, lpBuffer
);
1030 /***********************************************************************
1033 * This function sets window positions according to the updated
1034 * component placement struct.
1036 static void CBResetPos( LPHEADCOMBO lphc
, LPRECT lbRect
, WINBOOL bRedraw
)
1038 WINBOOL bDrop
= (CB_GETTYPE(lphc
) != CBS_SIMPLE
);
1040 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1041 * sizing messages */
1043 if( lphc
->wState
& CBF_EDIT
)
1044 SetWindowPos( lphc
->hWndEdit
, 0, lphc
->RectEdit
.left
, lphc
->RectEdit
.top
,
1045 lphc
->RectEdit
.right
- lphc
->RectEdit
.left
,
1046 lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
,
1047 SWP_NOZORDER
| SWP_NOACTIVATE
| ((bDrop
) ? SWP_NOREDRAW
: 0) );
1050 OffsetRect( lbRect
, lphc
->RectCombo
.left
, lphc
->RectCombo
.top
);
1052 lbRect
->right
-= lbRect
->left
; /* convert to width */
1053 lbRect
->bottom
-= lbRect
->top
;
1054 SetWindowPos( lphc
->hWndLBox
, 0, lbRect
->left
, lbRect
->top
,
1055 lbRect
->right
, lbRect
->bottom
,
1056 SWP_NOACTIVATE
| SWP_NOZORDER
| ((bDrop
) ? SWP_NOREDRAW
: 0) );
1060 if( lphc
->wState
& CBF_DROPPED
)
1062 lphc
->wState
&= ~CBF_DROPPED
;
1063 ShowWindow( lphc
->hWndLBox
, SW_HIDE
);
1066 lphc
->wState
|= CBF_NORESIZE
;
1067 SetWindowPos( lphc
->self
->hwndSelf
, 0, 0, 0,
1068 lphc
->RectCombo
.right
- lphc
->RectCombo
.left
,
1069 lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
,
1070 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
);
1071 lphc
->wState
&= ~CBF_NORESIZE
;
1073 if( bRedraw
&& !(lphc
->wState
& CBF_NOREDRAW
) )
1074 RedrawWindow( lphc
->self
->hwndSelf
, NULL
, 0,
1075 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
);
1080 /***********************************************************************
1083 static void COMBO_Size( LPHEADCOMBO lphc
)
1088 GetWindowRect( lphc
->self
->hwndSelf
, &rect
);
1089 w
= rect
.right
- rect
.left
; h
= rect
.bottom
- rect
.top
;
1091 DPRINT("w = %i, h = %i\n", w
, h
);
1093 /* CreateWindow() may send a bogus WM_SIZE, ignore it */
1095 if( w
== (lphc
->RectCombo
.right
- lphc
->RectCombo
.left
) )
1097 if( (CB_GETTYPE(lphc
) == CBS_SIMPLE
) &&
1098 (h
== (lphc
->RectCombo
.bottom
- lphc
->RectCombo
.top
)) )
1100 else if( (lphc
->dwStyle
& CBS_DROPDOWN
) &&
1101 (h
== (lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
)) )
1104 lphc
->RectCombo
= rect
;
1105 CBCalcPlacement( lphc
, &lphc
->RectEdit
, &lphc
->RectButton
, &rect
);
1106 CBResetPos( lphc
, &rect
, TRUE
);
1110 /***********************************************************************
1113 static void COMBO_Font( LPHEADCOMBO lphc
, HFONT hFont
, WINBOOL bRedraw
)
1117 lphc
->hFont
= hFont
;
1119 if( lphc
->wState
& CBF_EDIT
)
1120 SendMessageA( lphc
->hWndEdit
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1121 SendMessageA( lphc
->hWndLBox
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1123 GetWindowRect( lphc
->self
->hwndSelf
, &rect
);
1124 OffsetRect( &lphc
->RectCombo
, rect
.left
- lphc
->RectCombo
.left
,
1125 rect
.top
- lphc
->RectCombo
.top
);
1126 CBCalcPlacement( lphc
, &lphc
->RectEdit
,
1127 &lphc
->RectButton
, &rect
);
1128 CBResetPos( lphc
, &rect
, bRedraw
);
1132 /***********************************************************************
1133 * COMBO_SetItemHeight
1135 static LRESULT
COMBO_SetItemHeight( LPHEADCOMBO lphc
, INT index
, INT height
)
1137 LRESULT lRet
= CB_ERR
;
1139 if( index
== -1 ) /* set text field height */
1145 lphc
->editHeight
= height
;
1146 GetWindowRect( lphc
->self
->hwndSelf
, &rect
);
1147 OffsetRect( &lphc
->RectCombo
, rect
.left
- lphc
->RectCombo
.left
,
1148 rect
.top
- lphc
->RectCombo
.top
);
1149 CBCalcPlacement( lphc
, &lphc
->RectEdit
,
1150 &lphc
->RectButton
, &rect
);
1151 CBResetPos( lphc
, &rect
, TRUE
);
1155 else if ( CB_OWNERDRAWN(lphc
) ) /* set listbox item height */
1156 lRet
= SendMessageA( lphc
->hWndLBox
, LB_SETITEMHEIGHT
,
1157 (WPARAM
)index
, (LPARAM
)height
);
1161 /***********************************************************************
1162 * COMBO_SelectString
1164 static LRESULT
COMBO_SelectString( LPHEADCOMBO lphc
, INT start
, LPCSTR pText
)
1166 INT index
= SendMessageA( lphc
->hWndLBox
, LB_SELECTSTRING
,
1167 (WPARAM
)start
, (LPARAM
)pText
);
1170 if( lphc
->wState
& CBF_EDIT
)
1171 CBUpdateEdit( lphc
, index
);
1173 CBPaintText( lphc
, 0 );
1175 return (LRESULT
)index
;
1178 /***********************************************************************
1181 static void COMBO_LButtonDown( LPHEADCOMBO lphc
, LPARAM lParam
)
1183 POINT pt
= { LOWORD(lParam
), HIWORD(lParam
) };
1184 WINBOOL bButton
= PtInRect(&lphc
->RectButton
, pt
);
1185 HWND hWnd
= lphc
->self
->hwndSelf
;
1187 if( (CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
) ||
1188 (bButton
&& (CB_GETTYPE(lphc
) == CBS_DROPDOWN
)) )
1190 lphc
->wState
|= CBF_BUTTONDOWN
;
1191 if( lphc
->wState
& CBF_DROPPED
)
1193 /* got a click to cancel selection */
1195 CBRollUp( lphc
, TRUE
, FALSE
);
1196 if( !IsWindow( hWnd
) ) return;
1198 if( lphc
->wState
& CBF_CAPTURE
)
1200 lphc
->wState
&= ~CBF_CAPTURE
;
1203 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1207 /* drop down the listbox and start tracking */
1209 lphc
->wState
|= CBF_CAPTURE
;
1213 if( bButton
) CBRepaintButton( lphc
);
1217 /***********************************************************************
1220 * Release capture and stop tracking if needed.
1222 static void COMBO_LButtonUp( LPHEADCOMBO lphc
, LPARAM lParam
)
1224 if( lphc
->wState
& CBF_CAPTURE
)
1226 lphc
->wState
&= ~CBF_CAPTURE
;
1227 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1229 INT index
= CBUpdateLBox( lphc
);
1230 CBUpdateEdit( lphc
, index
);
1235 if( lphc
->wState
& CBF_BUTTONDOWN
)
1237 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1238 CBRepaintButton( lphc
);
1242 /***********************************************************************
1245 * Two things to do - track combo button and release capture when
1246 * pointer goes into the listbox.
1248 static void COMBO_MouseMove( LPHEADCOMBO lphc
, WPARAM wParam
, LPARAM lParam
)
1250 POINT pt
= { LOWORD(lParam
), HIWORD(lParam
) };
1253 if( lphc
->wState
& CBF_BUTTONDOWN
)
1255 WINBOOL bButton
= PtInRect(&lphc
->RectButton
, pt
);
1259 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1260 CBRepaintButton( lphc
);
1264 GetClientRect( lphc
->hWndLBox
, &lbRect
);
1265 MapWindowPoints( lphc
->self
->hwndSelf
, lphc
->hWndLBox
, &pt
, 1 );
1266 if( PtInRect(&lbRect
, pt
) )
1268 lphc
->wState
&= ~CBF_CAPTURE
;
1270 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
) CBUpdateLBox( lphc
);
1272 /* hand over pointer tracking */
1273 SendMessageA( lphc
->hWndLBox
, WM_LBUTTONDOWN
, wParam
, lParam
);
1278 /***********************************************************************
1281 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win/ctrl/src/combobox_15.htm
1283 LRESULT WINAPI
ComboWndProc( HWND hwnd
, UINT message
,
1284 WPARAM wParam
, LPARAM lParam
)
1286 WND
* pWnd
= WIN_FindWndPtr(hwnd
);
1290 LPHEADCOMBO lphc
= CB_GETPTR(pWnd
);
1292 DPRINT( "[%04x]: msg %s wp %08x lp %08lx\n",
1293 pWnd
->hwndSelf
, SPY_GetMsgName(message
), wParam
, lParam
);
1295 if( lphc
|| message
== WM_NCCREATE
)
1299 /* System messages */
1302 return COMBO_NCCreate(pWnd
, lParam
);
1305 COMBO_NCDestroy(lphc
);
1309 return COMBO_Create(lphc
, pWnd
, lParam
);
1312 /* wParam may contain a valid HDC! */
1313 return COMBO_Paint(lphc
, wParam
);
1319 return (LRESULT
)(DLGC_WANTARROWS
| DLGC_WANTCHARS
);
1322 if( lphc
->hWndLBox
&&
1323 !(lphc
->wState
& CBF_NORESIZE
) ) COMBO_Size( lphc
);
1327 COMBO_Font( lphc
, (HFONT
)wParam
, (WINBOOL
)lParam
);
1331 return (LRESULT
)lphc
->hFont
;
1334 if( lphc
->wState
& CBF_EDIT
)
1335 SetFocus( lphc
->hWndEdit
);
1337 COMBO_SetFocus( lphc
);
1341 #define hwndFocus ((HWND)wParam)
1343 (hwndFocus
!= lphc
->hWndEdit
&& hwndFocus
!= lphc
->hWndLBox
))
1344 COMBO_KillFocus( lphc
);
1349 return COMBO_Command( lphc
, wParam
, (HWND
)lParam
);
1352 return COMBO_GetText( lphc
, (UINT
)wParam
, (LPSTR
)lParam
);
1355 case WM_GETTEXTLENGTH
:
1360 if( lphc
->wState
& CBF_EDIT
)
1361 return SendMessageA( lphc
->hWndEdit
, message
, wParam
, lParam
);
1366 case WM_COMPAREITEM
:
1367 case WM_MEASUREITEM
:
1368 return COMBO_ItemOp( lphc
, message
, wParam
, lParam
);
1371 if( lphc
->wState
& CBF_EDIT
)
1372 EnableWindow( lphc
->hWndEdit
, (WINBOOL
)wParam
);
1373 EnableWindow( lphc
->hWndLBox
, (WINBOOL
)wParam
);
1378 lphc
->wState
&= ~CBF_NOREDRAW
;
1380 lphc
->wState
|= CBF_NOREDRAW
;
1382 if( lphc
->wState
& CBF_EDIT
)
1383 SendMessageA( lphc
->hWndEdit
, message
, wParam
, lParam
);
1384 SendMessageA( lphc
->hWndLBox
, message
, wParam
, lParam
);
1388 if( KEYDATA_ALT
& HIWORD(lParam
) )
1389 if( wParam
== VK_UP
|| wParam
== VK_DOWN
)
1390 COMBO_FlipListbox( lphc
, TRUE
);
1395 if( lphc
->wState
& CBF_EDIT
)
1396 return SendMessageA( lphc
->hWndEdit
, message
, wParam
, lParam
);
1398 return SendMessageA( lphc
->hWndLBox
, message
, wParam
, lParam
);
1400 case WM_LBUTTONDOWN
:
1401 if( !(lphc
->wState
& CBF_FOCUSED
) ) SetFocus( lphc
->self
->hwndSelf
);
1402 if( lphc
->wState
& CBF_FOCUSED
) COMBO_LButtonDown( lphc
, lParam
);
1406 COMBO_LButtonUp( lphc
, lParam
);
1410 if( lphc
->wState
& CBF_CAPTURE
)
1411 COMBO_MouseMove( lphc
, wParam
, lParam
);
1414 /* Combo messages */
1417 return SendMessageA( lphc
->hWndLBox
, LB_ADDSTRING
, 0, lParam
);
1419 case CB_INSERTSTRING
:
1420 return SendMessageA( lphc
->hWndLBox
, LB_INSERTSTRING
, wParam
, lParam
);
1422 case CB_DELETESTRING
:
1423 return SendMessageA( lphc
->hWndLBox
, LB_DELETESTRING
, wParam
, 0);
1425 case CB_SELECTSTRING
:
1426 return COMBO_SelectString( lphc
, (INT
)wParam
, (LPSTR
)lParam
);
1429 return SendMessageA( lphc
->hWndLBox
, LB_FINDSTRING
, wParam
, lParam
);
1431 case CB_FINDSTRINGEXACT
:
1432 return SendMessageA( lphc
->hWndLBox
, LB_FINDSTRINGEXACT
,
1435 case CB_SETITEMHEIGHT
:
1436 return COMBO_SetItemHeight( lphc
, (INT
)wParam
, (INT
)lParam
);
1438 case CB_GETITEMHEIGHT
:
1439 if( (INT
)wParam
>= 0 ) /* listbox item */
1440 return SendMessageA( lphc
->hWndLBox
, LB_GETITEMHEIGHT
, wParam
, 0);
1441 return (lphc
->RectEdit
.bottom
- lphc
->RectEdit
.top
);
1443 case CB_RESETCONTENT
:
1444 SendMessageA( lphc
->hWndLBox
, LB_RESETCONTENT
, 0, 0 );
1445 CBPaintText( lphc
, 0 );
1448 case CB_INITSTORAGE
:
1449 return SendMessageA( lphc
->hWndLBox
, LB_INITSTORAGE
, wParam
, lParam
);
1451 case CB_GETHORIZONTALEXTENT
:
1452 return SendMessageA( lphc
->hWndLBox
, LB_GETHORIZONTALEXTENT
, 0, 0);
1454 case CB_SETHORIZONTALEXTENT
:
1455 return SendMessageA( lphc
->hWndLBox
, LB_SETHORIZONTALEXTENT
, wParam
, 0);
1457 case CB_GETTOPINDEX
:
1458 return SendMessageA( lphc
->hWndLBox
, LB_GETTOPINDEX
, 0, 0);
1461 return SendMessageA( lphc
->hWndLBox
, LB_GETLOCALE
, 0, 0);
1464 return SendMessageA( lphc
->hWndLBox
, LB_SETLOCALE
, wParam
, 0);
1466 case CB_GETDROPPEDWIDTH
:
1467 if( lphc
->droppedWidth
)
1468 return lphc
->droppedWidth
;
1469 return lphc
->RectCombo
.right
- lphc
->RectCombo
.left
-
1470 (lphc
->wState
& CBF_EDIT
) ? CBitOffset
: 0;
1472 case CB_SETDROPPEDWIDTH
:
1473 if( (CB_GETTYPE(lphc
) != CBS_SIMPLE
) &&
1474 (INT
)wParam
< 768 ) lphc
->droppedWidth
= (INT
)wParam
;
1477 case CB_GETDROPPEDCONTROLRECT
:
1478 if( lParam
) CBGetDroppedControlRect(lphc
, (LPRECT
)lParam
);
1481 case CB_GETDROPPEDSTATE
:
1482 return (lphc
->wState
& CBF_DROPPED
) ? TRUE
: FALSE
;
1486 return COMBO_Directory( lphc
, (UINT
)wParam
,
1487 (LPSTR
)lParam
, (message
== CB_DIR
));
1488 case CB_SHOWDROPDOWN
:
1489 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
1493 if( !(lphc
->wState
& CBF_DROPPED
) )
1497 if( lphc
->wState
& CBF_DROPPED
)
1498 CBRollUp( lphc
, FALSE
, TRUE
);
1503 return SendMessageA( lphc
->hWndLBox
, LB_GETCOUNT
, 0, 0);
1506 return SendMessageA( lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1509 lParam
= SendMessageA( lphc
->hWndLBox
, LB_SETCURSEL
, wParam
, 0);
1510 if( lphc
->wState
& CBF_SELCHANGE
)
1512 /* no LBN_SELCHANGE in this case, update manually */
1514 CBPaintText( lphc
, 0 );
1515 lphc
->wState
&= ~CBF_SELCHANGE
;
1521 return SendMessageA( lphc
->hWndLBox
, LB_GETTEXT
, wParam
, lParam
);
1523 case CB_GETLBTEXTLEN
:
1524 return SendMessageA( lphc
->hWndLBox
, LB_GETTEXTLEN
, wParam
, 0);
1526 case CB_GETITEMDATA
:
1527 return SendMessageA( lphc
->hWndLBox
, LB_GETITEMDATA
, wParam
, 0);
1529 case CB_SETITEMDATA
:
1530 return SendMessageA( lphc
->hWndLBox
, LB_SETITEMDATA
, wParam
, lParam
);
1533 if( lphc
->wState
& CBF_EDIT
)
1537 return SendMessageA( lphc
->hWndEdit
, EM_GETSEL
,
1538 (wParam
) ? wParam
: (WPARAM
)&a
,
1539 (lParam
) ? lParam
: (LPARAM
)&b
);
1545 if( lphc
->wState
& CBF_EDIT
)
1546 return SendMessageA( lphc
->hWndEdit
, EM_SETSEL
,
1547 (INT
)(INT
)LOWORD(lParam
), (INT
)(INT
)HIWORD(lParam
) );
1551 case CB_SETEXTENDEDUI
:
1552 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
) return CB_ERR
;
1555 lphc
->wState
|= CBF_EUI
;
1556 else lphc
->wState
&= ~CBF_EUI
;
1560 case CB_GETEXTENDEDUI
:
1561 return (lphc
->wState
& CBF_EUI
) ? TRUE
: FALSE
;
1563 case (WM_USER
+ 0x1B):
1564 DPRINT( "[%04x]: undocumented msg!\n", hwnd
);
1566 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);