4 * Copyright 1997 Alex Korobka
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "user_private.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(combo
);
33 /* bits in the dwKeyData */
34 #define KEYDATA_ALT 0x2000
35 #define KEYDATA_PREVSTATE 0x4000
38 * Additional combo box definitions
41 #define CB_NOTIFY( lphc, code ) \
42 (SendMessageW((lphc)->owner, WM_COMMAND, \
43 MAKEWPARAM(GetWindowLongPtrW((lphc)->self,GWLP_ID), (code)), (LPARAM)(lphc)->self))
45 #define CB_DISABLED( lphc ) (!IsWindowEnabled((lphc)->self))
46 #define CB_OWNERDRAWN( lphc ) ((lphc)->dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE))
47 #define CB_HASSTRINGS( lphc ) ((lphc)->dwStyle & CBS_HASSTRINGS)
48 #define CB_HWND( lphc ) ((lphc)->self)
49 #define CB_GETTYPE( lphc ) ((lphc)->dwStyle & (CBS_DROPDOWNLIST))
51 #define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
56 static HBITMAP hComboBmp
= 0;
57 static UINT CBitHeight
, CBitWidth
;
60 * Look and feel dependent "constants"
63 #define COMBO_YBORDERGAP 5
64 #define COMBO_XBORDERSIZE() 2
65 #define COMBO_YBORDERSIZE() 2
66 #define COMBO_EDITBUTTONSPACE() 0
67 #define EDIT_CONTROL_PADDING() 1
69 static void CBCalcPlacement(HEADCOMBO
*combo
);
70 static void CBResetPos(HEADCOMBO
*combo
, BOOL redraw
);
72 /***********************************************************************
75 * Load combo button bitmap.
77 static BOOL
COMBO_Init(void)
81 if( hComboBmp
) return TRUE
;
82 if( (hDC
= CreateCompatibleDC(0)) )
85 if( (hComboBmp
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_COMBO
))) )
91 GetObjectW( hComboBmp
, sizeof(bm
), &bm
);
92 CBitHeight
= bm
.bmHeight
;
93 CBitWidth
= bm
.bmWidth
;
95 TRACE("combo bitmap [%i,%i]\n", CBitWidth
, CBitHeight
);
97 hPrevB
= SelectObject( hDC
, hComboBmp
);
98 SetRect( &r
, 0, 0, CBitWidth
, CBitHeight
);
99 InvertRect( hDC
, &r
);
100 SelectObject( hDC
, hPrevB
);
109 /***********************************************************************
112 static LRESULT
COMBO_NCCreate(HWND hwnd
, LONG style
)
116 if( COMBO_Init() && (lphc
= calloc( 1, sizeof(HEADCOMBO
) )) )
119 SetWindowLongPtrW( hwnd
, 0, (LONG_PTR
)lphc
);
121 /* some braindead apps do try to use scrollbar/border flags */
123 lphc
->dwStyle
= style
& ~(WS_BORDER
| WS_HSCROLL
| WS_VSCROLL
);
124 SetWindowLongW( hwnd
, GWL_STYLE
, style
& ~(WS_BORDER
| WS_HSCROLL
| WS_VSCROLL
) );
127 * We also have to remove the client edge style to make sure
128 * we don't end-up with a non client area.
130 SetWindowLongW( hwnd
, GWL_EXSTYLE
,
131 GetWindowLongW( hwnd
, GWL_EXSTYLE
) & ~WS_EX_CLIENTEDGE
);
133 if( !(style
& (CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
)) )
134 lphc
->dwStyle
|= CBS_HASSTRINGS
;
135 if( !(GetWindowLongW( hwnd
, GWL_EXSTYLE
) & WS_EX_NOPARENTNOTIFY
) )
136 lphc
->wState
|= CBF_NOTIFY
;
138 TRACE("[%p], style = %08x\n", lphc
, lphc
->dwStyle
);
144 /***********************************************************************
147 static LRESULT
COMBO_NCDestroy( LPHEADCOMBO lphc
)
152 TRACE("[%p]: freeing storage\n", lphc
->self
);
154 if( (CB_GETTYPE(lphc
) != CBS_SIMPLE
) && lphc
->hWndLBox
)
155 NtUserDestroyWindow( lphc
->hWndLBox
);
157 SetWindowLongPtrW( lphc
->self
, 0, 0 );
163 static INT
combo_get_text_height(const HEADCOMBO
*combo
)
165 HDC hdc
= NtUserGetDC(combo
->self
);
170 prev_font
= SelectObject(hdc
, combo
->hFont
);
172 GetTextMetricsW(hdc
, &tm
);
175 SelectObject(hdc
, prev_font
);
177 NtUserReleaseDC( combo
->self
, hdc
);
179 return tm
.tmHeight
+ 4;
182 /***********************************************************************
183 * CBGetTextAreaHeight
185 * This method will calculate the height of the text area of the
187 * The height of the text area is set in two ways.
188 * It can be set explicitly through a combobox message or through a
189 * WM_MEASUREITEM callback.
190 * If this is not the case, the height is set to font height + 4px
191 * This height was determined through experimentation.
192 * CBCalcPlacement will add 2*COMBO_YBORDERSIZE pixels for the border
194 static INT
CBGetTextAreaHeight(HEADCOMBO
*lphc
, BOOL clip_item_height
)
196 INT item_height
, text_height
;
198 if (clip_item_height
&& !CB_OWNERDRAWN(lphc
))
200 text_height
= combo_get_text_height(lphc
);
201 if (lphc
->item_height
< text_height
)
202 lphc
->item_height
= text_height
;
205 item_height
= lphc
->item_height
;
208 * Check the ownerdraw case if we haven't asked the parent the size
211 if ( CB_OWNERDRAWN(lphc
) &&
212 (lphc
->wState
& CBF_MEASUREITEM
) )
214 MEASUREITEMSTRUCT measureItem
;
216 INT originalItemHeight
= item_height
;
217 UINT id
= (UINT
)GetWindowLongPtrW( lphc
->self
, GWLP_ID
);
220 * We use the client rect for the width of the item.
222 GetClientRect(lphc
->self
, &clientRect
);
224 lphc
->wState
&= ~CBF_MEASUREITEM
;
227 * Send a first one to measure the size of the text area
229 measureItem
.CtlType
= ODT_COMBOBOX
;
230 measureItem
.CtlID
= id
;
231 measureItem
.itemID
= -1;
232 measureItem
.itemWidth
= clientRect
.right
;
233 measureItem
.itemHeight
= item_height
- 6; /* ownerdrawn cb is taller */
234 measureItem
.itemData
= 0;
235 SendMessageW(lphc
->owner
, WM_MEASUREITEM
, id
, (LPARAM
)&measureItem
);
236 item_height
= 6 + measureItem
.itemHeight
;
239 * Send a second one in the case of a fixed ownerdraw list to calculate the
240 * size of the list items. (we basically do this on behalf of the listbox)
242 if (lphc
->dwStyle
& CBS_OWNERDRAWFIXED
)
244 measureItem
.CtlType
= ODT_COMBOBOX
;
245 measureItem
.CtlID
= id
;
246 measureItem
.itemID
= 0;
247 measureItem
.itemWidth
= clientRect
.right
;
248 measureItem
.itemHeight
= originalItemHeight
;
249 measureItem
.itemData
= 0;
250 SendMessageW(lphc
->owner
, WM_MEASUREITEM
, id
, (LPARAM
)&measureItem
);
251 lphc
->fixedOwnerDrawHeight
= measureItem
.itemHeight
;
255 * Keep the size for the next time
257 lphc
->item_height
= item_height
;
263 /***********************************************************************
266 * The dummy resize is used for listboxes that have a popup to trigger
267 * a re-arranging of the contents of the combobox and the recalculation
268 * of the size of the "real" control window.
270 static void CBForceDummyResize(LPHEADCOMBO lphc
)
275 newComboHeight
= CBGetTextAreaHeight(lphc
, FALSE
) + 2*COMBO_YBORDERSIZE();
277 GetWindowRect(lphc
->self
, &windowRect
);
280 * We have to be careful, resizing a combobox also has the meaning that the
281 * dropped rect will be resized. In this case, we want to trigger a resize
282 * to recalculate layout but we don't want to change the dropped rectangle
283 * So, we pass the height of text area of control as the height.
284 * this will cancel-out in the processing of the WM_WINDOWPOSCHANGING
287 lphc
->wState
|= CBF_NORESIZE
;
288 NtUserSetWindowPos( lphc
->self
,
291 windowRect
.right
- windowRect
.left
,
293 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
294 lphc
->wState
&= ~CBF_NORESIZE
;
296 CBCalcPlacement(lphc
);
297 CBResetPos(lphc
, FALSE
);
300 /***********************************************************************
303 * Set up component coordinates given valid lphc->RectCombo.
305 static void CBCalcPlacement(HEADCOMBO
*combo
)
307 /* Start with the client rectangle. */
308 GetClientRect(combo
->self
, &combo
->textRect
);
310 /* Remove the borders */
311 InflateRect(&combo
->textRect
, -COMBO_XBORDERSIZE(), -COMBO_YBORDERSIZE());
313 /* Chop off the bottom part to fit with the height of the text area. */
314 combo
->textRect
.bottom
= combo
->textRect
.top
+ CBGetTextAreaHeight(combo
, FALSE
);
316 /* The button starts the same vertical position as the text area. */
317 combo
->buttonRect
= combo
->textRect
;
319 /* If the combobox is "simple" there is no button. */
320 if (CB_GETTYPE(combo
) == CBS_SIMPLE
)
321 combo
->buttonRect
.left
= combo
->buttonRect
.right
= combo
->buttonRect
.bottom
= 0;
325 * Let's assume the combobox button is the same width as the
327 * size the button horizontally and cut-off the text area.
329 combo
->buttonRect
.left
= combo
->buttonRect
.right
- GetSystemMetrics(SM_CXVSCROLL
);
330 combo
->textRect
.right
= combo
->buttonRect
.left
;
333 /* In the case of a dropdown, there is an additional spacing between the text area and the button. */
334 if (CB_GETTYPE(combo
) == CBS_DROPDOWN
)
335 combo
->textRect
.right
-= COMBO_EDITBUTTONSPACE();
337 /* If we have an edit control, we space it away from the borders slightly. */
338 if (CB_GETTYPE(combo
) != CBS_DROPDOWNLIST
)
339 InflateRect(&combo
->textRect
, -EDIT_CONTROL_PADDING(), -EDIT_CONTROL_PADDING());
341 /* Adjust the size of the listbox popup. */
342 if (CB_GETTYPE(combo
) == CBS_SIMPLE
)
344 GetClientRect(combo
->self
, &combo
->droppedRect
);
345 combo
->droppedRect
.top
= combo
->textRect
.bottom
+ COMBO_YBORDERSIZE();
349 /* Make sure the dropped width is as large as the combobox itself. */
350 if (combo
->droppedWidth
< (combo
->buttonRect
.right
+ COMBO_XBORDERSIZE()))
352 combo
->droppedRect
.right
= combo
->droppedRect
.left
+ (combo
->buttonRect
.right
+ COMBO_XBORDERSIZE());
354 /* In the case of a dropdown, the popup listbox is offset to the right. We want to make sure it's flush
355 with the right side of the combobox. */
356 if (CB_GETTYPE(combo
) == CBS_DROPDOWN
)
357 combo
->droppedRect
.right
-= COMBO_EDITBUTTONSPACE();
360 combo
->droppedRect
.right
= combo
->droppedRect
.left
+ combo
->droppedWidth
;
363 /* Disallow negative window width */
364 if (combo
->textRect
.right
< combo
->textRect
.left
)
365 combo
->textRect
.right
= combo
->textRect
.left
;
367 TRACE("text %s, button %s, lbox %s.\n", wine_dbgstr_rect(&combo
->textRect
), wine_dbgstr_rect(&combo
->buttonRect
),
368 wine_dbgstr_rect(&combo
->droppedRect
));
371 /***********************************************************************
372 * CBGetDroppedControlRect
374 static void CBGetDroppedControlRect( LPHEADCOMBO lphc
, LPRECT lpRect
)
376 /* In windows, CB_GETDROPPEDCONTROLRECT returns the upper left corner
377 of the combo box and the lower right corner of the listbox */
379 GetWindowRect(lphc
->self
, lpRect
);
381 lpRect
->right
= lpRect
->left
+ lphc
->droppedRect
.right
- lphc
->droppedRect
.left
;
382 lpRect
->bottom
= lpRect
->top
+ lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
;
386 /***********************************************************************
389 static LRESULT
COMBO_Create( HWND hwnd
, LPHEADCOMBO lphc
, HWND hwndParent
, LONG style
,
392 if( !CB_GETTYPE(lphc
) ) lphc
->dwStyle
|= CBS_SIMPLE
;
393 if( CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
) lphc
->wState
|= CBF_EDIT
;
395 lphc
->owner
= hwndParent
;
397 lphc
->droppedWidth
= 0;
399 lphc
->item_height
= combo_get_text_height(lphc
);
402 * The first time we go through, we want to measure the ownerdraw item
404 lphc
->wState
|= CBF_MEASUREITEM
;
406 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
408 if( lphc
->owner
|| !(style
& WS_VISIBLE
) )
414 * Initialize the dropped rect to the size of the client area of the
415 * control and then, force all the areas of the combobox to be
418 GetClientRect( hwnd
, &lphc
->droppedRect
);
419 CBCalcPlacement(lphc
);
422 * Adjust the position of the popup listbox if it's necessary
424 if ( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
426 lphc
->droppedRect
.top
= lphc
->textRect
.bottom
+ COMBO_YBORDERSIZE();
429 * If it's a dropdown, the listbox is offset
431 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
432 lphc
->droppedRect
.left
+= COMBO_EDITBUTTONSPACE();
434 if (lphc
->droppedRect
.bottom
< lphc
->droppedRect
.top
)
435 lphc
->droppedRect
.bottom
= lphc
->droppedRect
.top
;
436 if (lphc
->droppedRect
.right
< lphc
->droppedRect
.left
)
437 lphc
->droppedRect
.right
= lphc
->droppedRect
.left
;
438 MapWindowPoints( hwnd
, 0, (LPPOINT
)&lphc
->droppedRect
, 2 );
441 /* create listbox popup */
443 lbeStyle
= (LBS_NOTIFY
| LBS_COMBOBOX
| WS_BORDER
| WS_CLIPSIBLINGS
| WS_CHILD
) |
444 (style
& (WS_VSCROLL
| CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
));
446 if( lphc
->dwStyle
& CBS_SORT
)
447 lbeStyle
|= LBS_SORT
;
448 if( lphc
->dwStyle
& CBS_HASSTRINGS
)
449 lbeStyle
|= LBS_HASSTRINGS
;
450 if( lphc
->dwStyle
& CBS_NOINTEGRALHEIGHT
)
451 lbeStyle
|= LBS_NOINTEGRALHEIGHT
;
452 if( lphc
->dwStyle
& CBS_DISABLENOSCROLL
)
453 lbeStyle
|= LBS_DISABLENOSCROLL
;
455 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
) /* child listbox */
457 lbeStyle
|= WS_VISIBLE
;
460 * In win 95 look n feel, the listbox in the simple combobox has
461 * the WS_EXCLIENTEDGE style instead of the WS_BORDER style.
463 lbeStyle
&= ~WS_BORDER
;
464 lbeExStyle
|= WS_EX_CLIENTEDGE
;
468 lbeExStyle
|= (WS_EX_TOPMOST
| WS_EX_TOOLWINDOW
);
472 lphc
->hWndLBox
= CreateWindowExW(lbeExStyle
, L
"ComboLBox", NULL
, lbeStyle
,
473 lphc
->droppedRect
.left
,
474 lphc
->droppedRect
.top
,
475 lphc
->droppedRect
.right
- lphc
->droppedRect
.left
,
476 lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
,
477 hwnd
, (HMENU
)ID_CB_LISTBOX
,
478 (HINSTANCE
)GetWindowLongPtrW( hwnd
, GWLP_HINSTANCE
), lphc
);
480 lphc
->hWndLBox
= CreateWindowExA(lbeExStyle
, "ComboLBox", NULL
, lbeStyle
,
481 lphc
->droppedRect
.left
,
482 lphc
->droppedRect
.top
,
483 lphc
->droppedRect
.right
- lphc
->droppedRect
.left
,
484 lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
,
485 hwnd
, (HMENU
)ID_CB_LISTBOX
,
486 (HINSTANCE
)GetWindowLongPtrW( hwnd
, GWLP_HINSTANCE
), lphc
);
491 lbeStyle
= WS_CHILD
| WS_VISIBLE
| ES_NOHIDESEL
| ES_LEFT
| ES_COMBO
;
493 if( lphc
->wState
& CBF_EDIT
)
495 if( lphc
->dwStyle
& CBS_OEMCONVERT
)
496 lbeStyle
|= ES_OEMCONVERT
;
497 if( lphc
->dwStyle
& CBS_AUTOHSCROLL
)
498 lbeStyle
|= ES_AUTOHSCROLL
;
499 if( lphc
->dwStyle
& CBS_LOWERCASE
)
500 lbeStyle
|= ES_LOWERCASE
;
501 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
502 lbeStyle
|= ES_UPPERCASE
;
504 if (!IsWindowEnabled(hwnd
)) lbeStyle
|= WS_DISABLED
;
507 lphc
->hWndEdit
= CreateWindowExW(0, L
"Edit", NULL
, lbeStyle
,
508 lphc
->textRect
.left
, lphc
->textRect
.top
,
509 lphc
->textRect
.right
- lphc
->textRect
.left
,
510 lphc
->textRect
.bottom
- lphc
->textRect
.top
,
511 hwnd
, (HMENU
)ID_CB_EDIT
,
512 (HINSTANCE
)GetWindowLongPtrW( hwnd
, GWLP_HINSTANCE
), NULL
);
514 lphc
->hWndEdit
= CreateWindowExA(0, "Edit", NULL
, lbeStyle
,
515 lphc
->textRect
.left
, lphc
->textRect
.top
,
516 lphc
->textRect
.right
- lphc
->textRect
.left
,
517 lphc
->textRect
.bottom
- lphc
->textRect
.top
,
518 hwnd
, (HMENU
)ID_CB_EDIT
,
519 (HINSTANCE
)GetWindowLongPtrW( hwnd
, GWLP_HINSTANCE
), NULL
);
521 if( !lphc
->hWndEdit
)
527 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
529 /* Now do the trick with parent */
530 NtUserSetParent( lphc
->hWndLBox
, HWND_DESKTOP
);
532 * If the combo is a dropdown, we must resize the control
533 * to fit only the text area and button. To do this,
534 * we send a dummy resize and the WM_WINDOWPOSCHANGING message
535 * will take care of setting the height for us.
537 CBForceDummyResize(lphc
);
540 TRACE("init done\n");
543 ERR("edit control failure.\n");
544 } else ERR("listbox failure.\n");
545 } else ERR("no owner for visible combo.\n");
547 /* CreateWindow() will send WM_NCDESTROY to cleanup */
552 /***********************************************************************
555 * Paint combo button (normal, pressed, and disabled states).
557 static void CBPaintButton(HEADCOMBO
*lphc
, HDC hdc
)
559 UINT buttonState
= DFCS_SCROLLCOMBOBOX
;
561 if (IsRectEmpty(&lphc
->buttonRect
))
564 if( lphc
->wState
& CBF_NOREDRAW
)
568 if (lphc
->wState
& CBF_BUTTONDOWN
)
569 buttonState
|= DFCS_PUSHED
;
571 if (CB_DISABLED(lphc
))
572 buttonState
|= DFCS_INACTIVE
;
574 DrawFrameControl(hdc
, &lphc
->buttonRect
, DFC_SCROLL
, buttonState
);
577 /***********************************************************************
578 * COMBO_PrepareColors
580 * This method will sent the appropriate WM_CTLCOLOR message to
581 * prepare and setup the colors for the combo's DC.
583 * It also returns the brush to use for the background.
585 static HBRUSH
COMBO_PrepareColors(
592 * Get the background brush for this control.
594 if (CB_DISABLED(lphc
))
596 hBkgBrush
= (HBRUSH
)SendMessageW(lphc
->owner
, WM_CTLCOLORSTATIC
,
597 (WPARAM
)hDC
, (LPARAM
)lphc
->self
);
600 * We have to change the text color since WM_CTLCOLORSTATIC will
601 * set it to the "enabled" color. This is the same behavior as the
604 SetTextColor(hDC
, GetSysColor(COLOR_GRAYTEXT
));
608 /* FIXME: In which cases WM_CTLCOLORLISTBOX should be sent? */
609 hBkgBrush
= (HBRUSH
)SendMessageW(lphc
->owner
, WM_CTLCOLOREDIT
,
610 (WPARAM
)hDC
, (LPARAM
)lphc
->self
);
617 hBkgBrush
= GetSysColorBrush(COLOR_WINDOW
);
622 /***********************************************************************
625 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
627 static void CBPaintText(
631 RECT rectEdit
= lphc
->textRect
;
637 /* follow Windows combobox that sends a bunch of text
638 * inquiries to its listbox while processing WM_PAINT. */
640 if( (id
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0) ) != LB_ERR
)
642 size
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, id
, 0);
644 FIXME("LB_ERR probably not handled yet\n");
645 if( (pText
= malloc((size
+ 1) * sizeof(WCHAR
))) )
647 /* size from LB_GETTEXTLEN may be too large, from LB_GETTEXT is accurate */
648 size
=SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, id
, (LPARAM
)pText
);
649 pText
[size
] = '\0'; /* just in case */
653 if( lphc
->wState
& CBF_EDIT
)
655 if( CB_HASSTRINGS(lphc
) ) SetWindowTextW( lphc
->hWndEdit
, pText
? pText
: L
"" );
656 if( lphc
->wState
& CBF_FOCUSED
)
657 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, MAXLONG
);
659 else if(!(lphc
->wState
& CBF_NOREDRAW
) && IsWindowVisible( lphc
->self
))
661 /* paint text field ourselves */
662 HDC hdc
= hdc_paint
? hdc_paint
: NtUserGetDC(lphc
->self
);
663 UINT itemState
= ODS_COMBOBOXEDIT
;
664 HFONT hPrevFont
= (lphc
->hFont
) ? SelectObject(hdc
, lphc
->hFont
) : 0;
665 HBRUSH hPrevBrush
, hBkgBrush
;
668 * Give ourselves some space.
670 InflateRect( &rectEdit
, -1, -1 );
672 hBkgBrush
= COMBO_PrepareColors( lphc
, hdc
);
673 hPrevBrush
= SelectObject( hdc
, hBkgBrush
);
674 FillRect( hdc
, &rectEdit
, hBkgBrush
);
676 if( CB_OWNERDRAWN(lphc
) )
680 UINT ctlid
= (UINT
)GetWindowLongPtrW( lphc
->self
, GWLP_ID
);
682 /* setup state for DRAWITEM message. Owner will highlight */
683 if ( (lphc
->wState
& CBF_FOCUSED
) &&
684 !(lphc
->wState
& CBF_DROPPED
) )
685 itemState
|= ODS_SELECTED
| ODS_FOCUS
;
687 if (!IsWindowEnabled(lphc
->self
)) itemState
|= ODS_DISABLED
;
689 dis
.CtlType
= ODT_COMBOBOX
;
691 dis
.hwndItem
= lphc
->self
;
692 dis
.itemAction
= ODA_DRAWENTIRE
;
694 dis
.itemState
= itemState
;
696 dis
.rcItem
= rectEdit
;
697 dis
.itemData
= SendMessageW(lphc
->hWndLBox
, LB_GETITEMDATA
, id
, 0);
700 * Clip the DC and have the parent draw the item.
702 clipRegion
= set_control_clipping( hdc
, &rectEdit
);
704 SendMessageW(lphc
->owner
, WM_DRAWITEM
, ctlid
, (LPARAM
)&dis
);
706 SelectClipRgn( hdc
, clipRegion
);
707 if (clipRegion
) DeleteObject( clipRegion
);
711 if ( (lphc
->wState
& CBF_FOCUSED
) &&
712 !(lphc
->wState
& CBF_DROPPED
) ) {
715 FillRect( hdc
, &rectEdit
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
716 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
717 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
723 ETO_OPAQUE
| ETO_CLIPPED
,
725 pText
? pText
: L
"" , size
, NULL
);
727 if(lphc
->wState
& CBF_FOCUSED
&& !(lphc
->wState
& CBF_DROPPED
))
728 DrawFocusRect( hdc
, &rectEdit
);
732 SelectObject(hdc
, hPrevFont
);
735 SelectObject( hdc
, hPrevBrush
);
738 NtUserReleaseDC( lphc
->self
, hdc
);
743 /***********************************************************************
746 static void CBPaintBorder(const HEADCOMBO
*lphc
, HDC hdc
)
750 if (CB_GETTYPE(lphc
) != CBS_SIMPLE
)
752 GetClientRect(lphc
->self
, &clientRect
);
756 clientRect
= lphc
->textRect
;
758 InflateRect(&clientRect
, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
759 InflateRect(&clientRect
, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
762 DrawEdge(hdc
, &clientRect
, EDGE_SUNKEN
, BF_RECT
);
765 /***********************************************************************
768 static LRESULT
COMBO_Paint(LPHEADCOMBO lphc
, HDC hParamDC
)
773 hDC
= hParamDC
? hParamDC
: NtUserBeginPaint( lphc
->self
, &ps
);
775 TRACE("hdc=%p\n", hDC
);
777 if( hDC
&& !(lphc
->wState
& CBF_NOREDRAW
) )
779 HBRUSH hPrevBrush
, hBkgBrush
;
782 * Retrieve the background brush and select it in the
785 hBkgBrush
= COMBO_PrepareColors(lphc
, hDC
);
787 hPrevBrush
= SelectObject( hDC
, hBkgBrush
);
788 if (!(lphc
->wState
& CBF_EDIT
))
789 FillRect(hDC
, &lphc
->textRect
, hBkgBrush
);
792 * In non 3.1 look, there is a sunken border on the combobox
794 CBPaintBorder(lphc
, hDC
);
795 CBPaintButton(lphc
, hDC
);
797 /* paint the edit control padding area */
798 if (CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
)
800 RECT rPadEdit
= lphc
->textRect
;
802 InflateRect(&rPadEdit
, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
804 FrameRect( hDC
, &rPadEdit
, GetSysColorBrush(COLOR_WINDOW
) );
807 if( !(lphc
->wState
& CBF_EDIT
) )
808 CBPaintText( lphc
, hDC
);
811 SelectObject( hDC
, hPrevBrush
);
815 NtUserEndPaint( lphc
->self
, &ps
);
820 /***********************************************************************
823 * Select listbox entry according to the contents of the edit control.
825 static INT
CBUpdateLBox( LPHEADCOMBO lphc
, BOOL bSelect
)
831 length
= SendMessageW( lphc
->hWndEdit
, WM_GETTEXTLENGTH
, 0, 0 );
834 pText
= malloc((length
+ 1) * sizeof(WCHAR
));
836 TRACE("\t edit text length %i\n", length
);
840 GetWindowTextW( lphc
->hWndEdit
, pText
, length
+ 1);
841 idx
= SendMessageW(lphc
->hWndLBox
, LB_FINDSTRING
, -1, (LPARAM
)pText
);
845 SendMessageW(lphc
->hWndLBox
, LB_SETCURSEL
, bSelect
? idx
: -1, 0);
847 /* probably superfluous but Windows sends this too */
848 SendMessageW(lphc
->hWndLBox
, LB_SETCARETINDEX
, idx
< 0 ? 0 : idx
, 0);
849 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
, idx
< 0 ? 0 : idx
, 0);
854 /***********************************************************************
857 * Copy a listbox entry to the edit control.
859 static void CBUpdateEdit( LPHEADCOMBO lphc
, INT index
)
864 TRACE("\t %i\n", index
);
866 if( index
>= 0 ) /* got an entry */
868 length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, index
, 0);
869 if( length
!= LB_ERR
)
871 if( (pText
= malloc((length
+ 1) * sizeof(WCHAR
))) )
873 SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, index
, (LPARAM
)pText
);
878 if( CB_HASSTRINGS(lphc
) )
880 lphc
->wState
|= (CBF_NOEDITNOTIFY
| CBF_NOLBSELECT
);
881 SendMessageW(lphc
->hWndEdit
, WM_SETTEXT
, 0, pText
? (LPARAM
)pText
: (LPARAM
)L
"");
882 lphc
->wState
&= ~(CBF_NOEDITNOTIFY
| CBF_NOLBSELECT
);
885 if( lphc
->wState
& CBF_FOCUSED
)
886 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, -1);
891 /***********************************************************************
894 * Show listbox popup.
896 static void CBDropDown( LPHEADCOMBO lphc
)
899 MONITORINFO mon_info
;
904 TRACE("[%p]: drop down\n", lphc
->self
);
906 CB_NOTIFY( lphc
, CBN_DROPDOWN
);
910 lphc
->wState
|= CBF_DROPPED
;
911 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
913 lphc
->droppedIndex
= CBUpdateLBox( lphc
, TRUE
);
915 /* Update edit only if item is in the list */
916 if( !(lphc
->wState
& CBF_CAPTURE
) && lphc
->droppedIndex
>= 0)
917 CBUpdateEdit( lphc
, lphc
->droppedIndex
);
921 lphc
->droppedIndex
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
923 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
,
924 lphc
->droppedIndex
== LB_ERR
? 0 : lphc
->droppedIndex
, 0);
925 SendMessageW(lphc
->hWndLBox
, LB_CARETON
, 0, 0);
928 /* now set popup position */
929 GetWindowRect( lphc
->self
, &rect
);
932 * If it's a dropdown, the listbox is offset
934 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
935 rect
.left
+= COMBO_EDITBUTTONSPACE();
937 /* if the dropped height is greater than the total height of the dropped
938 items list, then force the drop down list height to be the total height
939 of the items in the dropped list */
941 /* And Remove any extra space (Best Fit) */
942 nDroppedHeight
= lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
;
943 /* if listbox length has been set directly by its handle */
944 GetWindowRect(lphc
->hWndLBox
, &r
);
945 if (nDroppedHeight
< r
.bottom
- r
.top
)
946 nDroppedHeight
= r
.bottom
- r
.top
;
947 nItems
= (int)SendMessageW(lphc
->hWndLBox
, LB_GETCOUNT
, 0, 0);
954 nIHeight
= (int)SendMessageW(lphc
->hWndLBox
, LB_GETITEMHEIGHT
, 0, 0);
956 nHeight
= nIHeight
*nItems
;
958 if (nHeight
< nDroppedHeight
- COMBO_YBORDERSIZE())
959 nDroppedHeight
= nHeight
+ COMBO_YBORDERSIZE();
964 r
.right
= r
.left
+ lphc
->droppedRect
.right
- lphc
->droppedRect
.left
;
965 r
.bottom
= r
.top
+ nDroppedHeight
;
967 /*If height of dropped rectangle gets beyond a screen size it should go up, otherwise down.*/
968 monitor
= MonitorFromRect( &rect
, MONITOR_DEFAULTTOPRIMARY
);
969 mon_info
.cbSize
= sizeof(mon_info
);
970 GetMonitorInfoW( monitor
, &mon_info
);
972 if (r
.bottom
> mon_info
.rcWork
.bottom
)
974 r
.top
= max( rect
.top
- nDroppedHeight
, mon_info
.rcWork
.top
);
975 r
.bottom
= min( r
.top
+ nDroppedHeight
, mon_info
.rcWork
.bottom
);
978 NtUserSetWindowPos( lphc
->hWndLBox
, HWND_TOPMOST
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
,
979 SWP_NOACTIVATE
| SWP_SHOWWINDOW
);
982 if( !(lphc
->wState
& CBF_NOREDRAW
) )
983 NtUserRedrawWindow( lphc
->self
, NULL
, 0, RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
);
985 EnableWindow( lphc
->hWndLBox
, TRUE
);
986 if (GetCapture() != lphc
->self
)
987 NtUserSetCapture(lphc
->hWndLBox
);
990 /***********************************************************************
993 * Hide listbox popup.
995 static void CBRollUp( LPHEADCOMBO lphc
, BOOL ok
, BOOL bButton
)
997 HWND hWnd
= lphc
->self
;
999 TRACE("[%p]: sel ok? [%i] dropped? [%i]\n",
1000 lphc
->self
, ok
, (INT
)(lphc
->wState
& CBF_DROPPED
));
1002 CB_NOTIFY( lphc
, (ok
) ? CBN_SELENDOK
: CBN_SELENDCANCEL
);
1004 if( IsWindow( hWnd
) && CB_GETTYPE(lphc
) != CBS_SIMPLE
)
1007 if( lphc
->wState
& CBF_DROPPED
)
1011 lphc
->wState
&= ~CBF_DROPPED
;
1012 NtUserShowWindow( lphc
->hWndLBox
, SW_HIDE
);
1014 if(GetCapture() == lphc
->hWndLBox
)
1019 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1021 rect
= lphc
->buttonRect
;
1032 rect
= lphc
->textRect
;
1037 if( bButton
&& !(lphc
->wState
& CBF_NOREDRAW
) )
1038 NtUserRedrawWindow( hWnd
, &rect
, 0, RDW_INVALIDATE
|
1039 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1040 CB_NOTIFY( lphc
, CBN_CLOSEUP
);
1045 /***********************************************************************
1048 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
1050 BOOL
COMBO_FlipListbox( LPHEADCOMBO lphc
, BOOL ok
, BOOL bRedrawButton
)
1052 if( lphc
->wState
& CBF_DROPPED
)
1054 CBRollUp( lphc
, ok
, bRedrawButton
);
1062 /***********************************************************************
1065 static void CBRepaintButton( LPHEADCOMBO lphc
)
1067 NtUserInvalidateRect(lphc
->self
, &lphc
->buttonRect
, TRUE
);
1068 UpdateWindow(lphc
->self
);
1071 /***********************************************************************
1074 static void COMBO_SetFocus( LPHEADCOMBO lphc
)
1076 if( !(lphc
->wState
& CBF_FOCUSED
) )
1078 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
1079 SendMessageW(lphc
->hWndLBox
, LB_CARETON
, 0, 0);
1081 /* This is wrong. Message sequences seem to indicate that this
1082 is set *after* the notify. */
1083 /* lphc->wState |= CBF_FOCUSED; */
1085 if( !(lphc
->wState
& CBF_EDIT
) )
1086 NtUserInvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1088 CB_NOTIFY( lphc
, CBN_SETFOCUS
);
1089 lphc
->wState
|= CBF_FOCUSED
;
1093 /***********************************************************************
1096 static void COMBO_KillFocus( LPHEADCOMBO lphc
)
1098 HWND hWnd
= lphc
->self
;
1100 if( lphc
->wState
& CBF_FOCUSED
)
1102 CBRollUp( lphc
, FALSE
, TRUE
);
1103 if( IsWindow( hWnd
) )
1105 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
1106 SendMessageW(lphc
->hWndLBox
, LB_CARETOFF
, 0, 0);
1108 lphc
->wState
&= ~CBF_FOCUSED
;
1111 if( !(lphc
->wState
& CBF_EDIT
) )
1112 NtUserInvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1114 CB_NOTIFY( lphc
, CBN_KILLFOCUS
);
1119 /***********************************************************************
1122 static LRESULT
COMBO_Command( LPHEADCOMBO lphc
, WPARAM wParam
, HWND hWnd
)
1124 if ( lphc
->wState
& CBF_EDIT
&& lphc
->hWndEdit
== hWnd
)
1126 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
1128 switch( HIWORD(wParam
) >> 8 )
1130 case (EN_SETFOCUS
>> 8):
1132 TRACE("[%p]: edit [%p] got focus\n", lphc
->self
, lphc
->hWndEdit
);
1134 COMBO_SetFocus( lphc
);
1137 case (EN_KILLFOCUS
>> 8):
1139 TRACE("[%p]: edit [%p] lost focus\n", lphc
->self
, lphc
->hWndEdit
);
1141 /* NOTE: it seems that Windows' edit control sends an
1142 * undocumented message WM_USER + 0x1B instead of this
1143 * notification (only when it happens to be a part of
1144 * the combo). ?? - AK.
1147 COMBO_KillFocus( lphc
);
1151 case (EN_CHANGE
>> 8):
1153 * In some circumstances (when the selection of the combobox
1154 * is changed for example) we don't want the EN_CHANGE notification
1155 * to be forwarded to the parent of the combobox. This code
1156 * checks a flag that is set in these occasions and ignores the
1159 if (lphc
->wState
& CBF_NOLBSELECT
)
1161 lphc
->wState
&= ~CBF_NOLBSELECT
;
1165 CBUpdateLBox( lphc
, lphc
->wState
& CBF_DROPPED
);
1168 if (!(lphc
->wState
& CBF_NOEDITNOTIFY
))
1169 CB_NOTIFY( lphc
, CBN_EDITCHANGE
);
1172 case (EN_UPDATE
>> 8):
1173 if (!(lphc
->wState
& CBF_NOEDITNOTIFY
))
1174 CB_NOTIFY( lphc
, CBN_EDITUPDATE
);
1177 case (EN_ERRSPACE
>> 8):
1178 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
1181 else if( lphc
->hWndLBox
== hWnd
)
1183 switch( (short)HIWORD(wParam
) )
1186 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
1190 CB_NOTIFY( lphc
, CBN_DBLCLK
);
1196 TRACE("[%p]: lbox selection change [%x]\n", lphc
->self
, lphc
->wState
);
1198 /* do not roll up if selection is being tracked
1199 * by arrow keys in the dropdown listbox */
1200 if (!(lphc
->wState
& CBF_NOROLLUP
))
1202 CBRollUp( lphc
, (HIWORD(wParam
) == LBN_SELCHANGE
), TRUE
);
1204 else lphc
->wState
&= ~CBF_NOROLLUP
;
1206 CB_NOTIFY( lphc
, CBN_SELCHANGE
);
1208 if( HIWORD(wParam
) == LBN_SELCHANGE
)
1210 if( lphc
->wState
& CBF_EDIT
)
1211 lphc
->wState
|= CBF_NOLBSELECT
;
1212 CBPaintText( lphc
, NULL
);
1218 /* nothing to do here since ComboLBox always resets the focus to its
1219 * combo/edit counterpart */
1226 /***********************************************************************
1229 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
1231 static LRESULT
COMBO_ItemOp( LPHEADCOMBO lphc
, UINT msg
, LPARAM lParam
)
1233 HWND hWnd
= lphc
->self
;
1234 UINT id
= (UINT
)GetWindowLongPtrW( hWnd
, GWLP_ID
);
1236 TRACE("[%p]: ownerdraw op %04x\n", lphc
->self
, msg
);
1242 DELETEITEMSTRUCT
*lpIS
= (DELETEITEMSTRUCT
*)lParam
;
1243 lpIS
->CtlType
= ODT_COMBOBOX
;
1245 lpIS
->hwndItem
= hWnd
;
1250 DRAWITEMSTRUCT
*lpIS
= (DRAWITEMSTRUCT
*)lParam
;
1251 lpIS
->CtlType
= ODT_COMBOBOX
;
1253 lpIS
->hwndItem
= hWnd
;
1256 case WM_COMPAREITEM
:
1258 COMPAREITEMSTRUCT
*lpIS
= (COMPAREITEMSTRUCT
*)lParam
;
1259 lpIS
->CtlType
= ODT_COMBOBOX
;
1261 lpIS
->hwndItem
= hWnd
;
1264 case WM_MEASUREITEM
:
1266 MEASUREITEMSTRUCT
*lpIS
= (MEASUREITEMSTRUCT
*)lParam
;
1267 lpIS
->CtlType
= ODT_COMBOBOX
;
1272 return SendMessageW(lphc
->owner
, msg
, id
, lParam
);
1276 /***********************************************************************
1279 static LRESULT
COMBO_GetTextW( LPHEADCOMBO lphc
, INT count
, LPWSTR buf
)
1283 if( lphc
->wState
& CBF_EDIT
)
1284 return SendMessageW( lphc
->hWndEdit
, WM_GETTEXT
, count
, (LPARAM
)buf
);
1286 /* get it from the listbox */
1288 if (!count
|| !buf
) return 0;
1289 if( lphc
->hWndLBox
)
1291 INT idx
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1292 if (idx
== LB_ERR
) goto error
;
1293 length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, idx
, 0 );
1294 if (length
== LB_ERR
) goto error
;
1296 /* 'length' is without the terminating character */
1297 if (length
>= count
)
1299 WCHAR
*lpBuffer
= malloc((length
+ 1) * sizeof(WCHAR
));
1300 if (!lpBuffer
) goto error
;
1301 length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)lpBuffer
);
1303 /* truncate if buffer is too short */
1304 if (length
!= LB_ERR
)
1306 lstrcpynW( buf
, lpBuffer
, count
);
1311 else length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)buf
);
1313 if (length
== LB_ERR
) return 0;
1317 error
: /* error - truncate string, return zero */
1323 /***********************************************************************
1326 * NOTE! LB_GETTEXT does not count terminating \0, WM_GETTEXT does.
1327 * also LB_GETTEXT might return values < 0, WM_GETTEXT doesn't.
1329 static LRESULT
COMBO_GetTextA( LPHEADCOMBO lphc
, INT count
, LPSTR buf
)
1333 if( lphc
->wState
& CBF_EDIT
)
1334 return SendMessageA( lphc
->hWndEdit
, WM_GETTEXT
, count
, (LPARAM
)buf
);
1336 /* get it from the listbox */
1338 if (!count
|| !buf
) return 0;
1339 if( lphc
->hWndLBox
)
1341 INT idx
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1342 if (idx
== LB_ERR
) goto error
;
1343 length
= SendMessageA(lphc
->hWndLBox
, LB_GETTEXTLEN
, idx
, 0 );
1344 if (length
== LB_ERR
) goto error
;
1346 /* 'length' is without the terminating character */
1347 if (length
>= count
)
1349 char *lpBuffer
= malloc(length
+ 1);
1350 if (!lpBuffer
) goto error
;
1351 length
= SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)lpBuffer
);
1353 /* truncate if buffer is too short */
1354 if (length
!= LB_ERR
)
1356 lstrcpynA( buf
, lpBuffer
, count
);
1361 else length
= SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)buf
);
1363 if (length
== LB_ERR
) return 0;
1367 error
: /* error - truncate string, return zero */
1373 /***********************************************************************
1376 * This function sets window positions according to the updated
1377 * component placement struct.
1379 static void CBResetPos(HEADCOMBO
*combo
, BOOL redraw
)
1381 BOOL drop
= CB_GETTYPE(combo
) != CBS_SIMPLE
;
1383 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1384 * sizing messages */
1385 if (combo
->wState
& CBF_EDIT
)
1386 NtUserSetWindowPos( combo
->hWndEdit
, 0, combo
->textRect
.left
, combo
->textRect
.top
,
1387 combo
->textRect
.right
- combo
->textRect
.left
,
1388 combo
->textRect
.bottom
- combo
->textRect
.top
,
1389 SWP_NOZORDER
| SWP_NOACTIVATE
| (drop
? SWP_NOREDRAW
: 0) );
1391 NtUserSetWindowPos( combo
->hWndLBox
, 0, combo
->droppedRect
.left
, combo
->droppedRect
.top
,
1392 combo
->droppedRect
.right
- combo
->droppedRect
.left
,
1393 combo
->droppedRect
.bottom
- combo
->droppedRect
.top
,
1394 SWP_NOACTIVATE
| SWP_NOZORDER
| (drop
? SWP_NOREDRAW
: 0) );
1398 if (combo
->wState
& CBF_DROPPED
)
1400 combo
->wState
&= ~CBF_DROPPED
;
1401 NtUserShowWindow( combo
->hWndLBox
, SW_HIDE
);
1404 if (redraw
&& !(combo
->wState
& CBF_NOREDRAW
))
1405 NtUserRedrawWindow( combo
->self
, NULL
, 0, RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
);
1409 /***********************************************************************
1412 static void COMBO_Size( HEADCOMBO
*lphc
)
1414 if (!lphc
->hWndLBox
|| (lphc
->wState
& CBF_NORESIZE
))
1418 * Those controls are always the same height. So we have to make sure
1419 * they are not resized to another value.
1421 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
1423 int newComboHeight
, curComboHeight
, curComboWidth
;
1426 GetWindowRect(lphc
->self
, &rc
);
1427 curComboHeight
= rc
.bottom
- rc
.top
;
1428 curComboWidth
= rc
.right
- rc
.left
;
1429 newComboHeight
= CBGetTextAreaHeight(lphc
, TRUE
) + 2*COMBO_YBORDERSIZE();
1432 * Resizing a combobox has another side effect, it resizes the dropped
1433 * rectangle as well. However, it does it only if the new height for the
1434 * combobox is more than the height it should have. In other words,
1435 * if the application resizing the combobox only had the intention to resize
1436 * the actual control, for example, to do the layout of a dialog that is
1437 * resized, the height of the dropdown is not changed.
1439 if( curComboHeight
> newComboHeight
)
1441 TRACE("oldComboHeight=%d, newComboHeight=%d, oldDropBottom=%ld, oldDropTop=%ld\n",
1442 curComboHeight
, newComboHeight
, lphc
->droppedRect
.bottom
,
1443 lphc
->droppedRect
.top
);
1444 lphc
->droppedRect
.bottom
= lphc
->droppedRect
.top
+ curComboHeight
- newComboHeight
;
1447 * Restore original height
1449 if (curComboHeight
!= newComboHeight
)
1451 lphc
->wState
|= CBF_NORESIZE
;
1452 NtUserSetWindowPos( lphc
->self
, 0, 0, 0, curComboWidth
, newComboHeight
,
1453 SWP_NOZORDER
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOREDRAW
);
1454 lphc
->wState
&= ~CBF_NORESIZE
;
1458 CBCalcPlacement(lphc
);
1460 CBResetPos(lphc
, FALSE
);
1464 /***********************************************************************
1467 static void COMBO_Font( LPHEADCOMBO lphc
, HFONT hFont
, BOOL bRedraw
)
1469 lphc
->hFont
= hFont
;
1470 lphc
->item_height
= combo_get_text_height(lphc
);
1473 * Propagate to owned windows.
1475 if( lphc
->wState
& CBF_EDIT
)
1476 SendMessageW(lphc
->hWndEdit
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1477 SendMessageW(lphc
->hWndLBox
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1480 * Redo the layout of the control.
1482 if ( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
1484 CBCalcPlacement(lphc
);
1486 CBResetPos(lphc
, TRUE
);
1490 CBForceDummyResize(lphc
);
1495 /***********************************************************************
1496 * COMBO_SetItemHeight
1498 static LRESULT
COMBO_SetItemHeight( LPHEADCOMBO lphc
, INT index
, INT height
)
1500 LRESULT lRet
= CB_ERR
;
1502 if( index
== -1 ) /* set text field height */
1504 if( height
< 32768 )
1506 lphc
->item_height
= height
+ 2; /* Is the 2 for 2*EDIT_CONTROL_PADDING? */
1509 * Redo the layout of the control.
1511 if ( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
1513 CBCalcPlacement(lphc
);
1515 CBResetPos(lphc
, TRUE
);
1519 CBForceDummyResize(lphc
);
1525 else if ( CB_OWNERDRAWN(lphc
) ) /* set listbox item height */
1526 lRet
= SendMessageW(lphc
->hWndLBox
, LB_SETITEMHEIGHT
, index
, height
);
1530 /***********************************************************************
1531 * COMBO_SelectString
1533 static LRESULT
COMBO_SelectString( LPHEADCOMBO lphc
, INT start
, LPARAM pText
, BOOL unicode
)
1535 INT index
= unicode
? SendMessageW(lphc
->hWndLBox
, LB_SELECTSTRING
, start
, pText
) :
1536 SendMessageA(lphc
->hWndLBox
, LB_SELECTSTRING
, start
, pText
);
1539 if( lphc
->wState
& CBF_EDIT
)
1540 CBUpdateEdit( lphc
, index
);
1543 NtUserInvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1546 return (LRESULT
)index
;
1549 /***********************************************************************
1552 static void COMBO_LButtonDown( LPHEADCOMBO lphc
, LPARAM lParam
)
1556 HWND hWnd
= lphc
->self
;
1558 pt
.x
= (short)LOWORD(lParam
);
1559 pt
.y
= (short)HIWORD(lParam
);
1560 bButton
= PtInRect(&lphc
->buttonRect
, pt
);
1562 if( (CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
) ||
1563 (bButton
&& (CB_GETTYPE(lphc
) == CBS_DROPDOWN
)) )
1565 lphc
->wState
|= CBF_BUTTONDOWN
;
1566 if( lphc
->wState
& CBF_DROPPED
)
1568 /* got a click to cancel selection */
1570 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1571 CBRollUp( lphc
, TRUE
, FALSE
);
1572 if( !IsWindow( hWnd
) ) return;
1574 if( lphc
->wState
& CBF_CAPTURE
)
1576 lphc
->wState
&= ~CBF_CAPTURE
;
1582 /* drop down the listbox and start tracking */
1584 lphc
->wState
|= CBF_CAPTURE
;
1585 NtUserSetCapture( hWnd
);
1588 if( bButton
) CBRepaintButton( lphc
);
1592 /***********************************************************************
1595 * Release capture and stop tracking if needed.
1597 static void COMBO_LButtonUp( LPHEADCOMBO lphc
)
1599 if( lphc
->wState
& CBF_CAPTURE
)
1601 lphc
->wState
&= ~CBF_CAPTURE
;
1602 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1604 INT index
= CBUpdateLBox( lphc
, TRUE
);
1605 /* Update edit only if item is in the list */
1608 lphc
->wState
|= CBF_NOLBSELECT
;
1609 CBUpdateEdit( lphc
, index
);
1610 lphc
->wState
&= ~CBF_NOLBSELECT
;
1614 NtUserSetCapture(lphc
->hWndLBox
);
1617 if( lphc
->wState
& CBF_BUTTONDOWN
)
1619 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1620 CBRepaintButton( lphc
);
1624 /***********************************************************************
1627 * Two things to do - track combo button and release capture when
1628 * pointer goes into the listbox.
1630 static void COMBO_MouseMove( LPHEADCOMBO lphc
, WPARAM wParam
, LPARAM lParam
)
1635 pt
.x
= (short)LOWORD(lParam
);
1636 pt
.y
= (short)HIWORD(lParam
);
1638 if( lphc
->wState
& CBF_BUTTONDOWN
)
1642 bButton
= PtInRect(&lphc
->buttonRect
, pt
);
1646 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1647 CBRepaintButton( lphc
);
1651 GetClientRect( lphc
->hWndLBox
, &lbRect
);
1652 MapWindowPoints( lphc
->self
, lphc
->hWndLBox
, &pt
, 1 );
1653 if( PtInRect(&lbRect
, pt
) )
1655 lphc
->wState
&= ~CBF_CAPTURE
;
1657 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
) CBUpdateLBox( lphc
, TRUE
);
1659 /* hand over pointer tracking */
1660 SendMessageW(lphc
->hWndLBox
, WM_LBUTTONDOWN
, wParam
, lParam
);
1664 static LRESULT
COMBO_GetComboBoxInfo(const HEADCOMBO
*lphc
, COMBOBOXINFO
*pcbi
)
1666 if (!pcbi
|| (pcbi
->cbSize
< sizeof(COMBOBOXINFO
)))
1669 pcbi
->rcItem
= lphc
->textRect
;
1670 pcbi
->rcButton
= lphc
->buttonRect
;
1671 pcbi
->stateButton
= 0;
1672 if (lphc
->wState
& CBF_BUTTONDOWN
)
1673 pcbi
->stateButton
|= STATE_SYSTEM_PRESSED
;
1674 if (IsRectEmpty(&lphc
->buttonRect
))
1675 pcbi
->stateButton
|= STATE_SYSTEM_INVISIBLE
;
1676 pcbi
->hwndCombo
= lphc
->self
;
1677 pcbi
->hwndItem
= lphc
->hWndEdit
;
1678 pcbi
->hwndList
= lphc
->hWndLBox
;
1682 /***********************************************************************
1683 * ComboWndProc_common
1685 LRESULT
ComboWndProc_common( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL unicode
)
1687 LPHEADCOMBO lphc
= (LPHEADCOMBO
)GetWindowLongPtrW( hwnd
, 0 );
1689 TRACE("[%p]: msg %s wp %08Ix lp %08Ix\n",
1690 hwnd
, SPY_GetMsgName(message
, hwnd
), wParam
, lParam
);
1692 if (!IsWindow(hwnd
)) return 0;
1694 if( lphc
|| message
== WM_NCCREATE
)
1698 /* System messages */
1702 LONG style
= unicode
? ((LPCREATESTRUCTW
)lParam
)->style
:
1703 ((LPCREATESTRUCTA
)lParam
)->style
;
1704 return COMBO_NCCreate(hwnd
, style
);
1707 COMBO_NCDestroy(lphc
);
1708 break;/* -> DefWindowProc */
1716 hwndParent
= ((LPCREATESTRUCTW
)lParam
)->hwndParent
;
1717 style
= ((LPCREATESTRUCTW
)lParam
)->style
;
1721 hwndParent
= ((LPCREATESTRUCTA
)lParam
)->hwndParent
;
1722 style
= ((LPCREATESTRUCTA
)lParam
)->style
;
1724 return COMBO_Create(hwnd
, lphc
, hwndParent
, style
, unicode
);
1727 case WM_PRINTCLIENT
:
1730 /* wParam may contain a valid HDC! */
1731 return COMBO_Paint(lphc
, (HDC
)wParam
);
1734 /* do all painting in WM_PAINT like Windows does */
1739 LRESULT result
= DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1740 if (lParam
&& (((LPMSG
)lParam
)->message
== WM_KEYDOWN
))
1742 int vk
= (int)((LPMSG
)lParam
)->wParam
;
1744 if ((vk
== VK_RETURN
|| vk
== VK_ESCAPE
) && (lphc
->wState
& CBF_DROPPED
))
1745 result
|= DLGC_WANTMESSAGE
;
1753 COMBO_Font( lphc
, (HFONT
)wParam
, (BOOL
)lParam
);
1756 return (LRESULT
)lphc
->hFont
;
1758 if( lphc
->wState
& CBF_EDIT
) {
1759 NtUserSetFocus( lphc
->hWndEdit
);
1760 /* The first time focus is received, select all the text */
1761 if( !(lphc
->wState
& CBF_BEENFOCUSED
) ) {
1762 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, -1);
1763 lphc
->wState
|= CBF_BEENFOCUSED
;
1767 COMBO_SetFocus( lphc
);
1771 HWND hwndFocus
= WIN_GetFullHandle( (HWND
)wParam
);
1773 (hwndFocus
!= lphc
->hWndEdit
&& hwndFocus
!= lphc
->hWndLBox
))
1774 COMBO_KillFocus( lphc
);
1778 return COMBO_Command( lphc
, wParam
, WIN_GetFullHandle( (HWND
)lParam
) );
1780 return unicode
? COMBO_GetTextW( lphc
, wParam
, (LPWSTR
)lParam
)
1781 : COMBO_GetTextA( lphc
, wParam
, (LPSTR
)lParam
);
1783 case WM_GETTEXTLENGTH
:
1785 if ((message
== WM_GETTEXTLENGTH
) && !ISWIN31
&& !(lphc
->wState
& CBF_EDIT
))
1787 int j
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1788 if (j
== -1) return 0;
1789 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, j
, 0) :
1790 SendMessageA(lphc
->hWndLBox
, LB_GETTEXTLEN
, j
, 0);
1792 else if( lphc
->wState
& CBF_EDIT
)
1795 lphc
->wState
|= CBF_NOEDITNOTIFY
;
1796 ret
= unicode
? SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
) :
1797 SendMessageA(lphc
->hWndEdit
, message
, wParam
, lParam
);
1798 lphc
->wState
&= ~CBF_NOEDITNOTIFY
;
1805 if( lphc
->wState
& CBF_EDIT
)
1807 return unicode
? SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
) :
1808 SendMessageA(lphc
->hWndEdit
, message
, wParam
, lParam
);
1814 case WM_COMPAREITEM
:
1815 case WM_MEASUREITEM
:
1816 return COMBO_ItemOp(lphc
, message
, lParam
);
1818 if( lphc
->wState
& CBF_EDIT
)
1819 EnableWindow( lphc
->hWndEdit
, (BOOL
)wParam
);
1820 EnableWindow( lphc
->hWndLBox
, (BOOL
)wParam
);
1822 /* Force the control to repaint when the enabled state changes. */
1823 NtUserInvalidateRect(lphc
->self
, NULL
, TRUE
);
1827 lphc
->wState
&= ~CBF_NOREDRAW
;
1829 lphc
->wState
|= CBF_NOREDRAW
;
1831 if( lphc
->wState
& CBF_EDIT
)
1832 SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
);
1833 SendMessageW(lphc
->hWndLBox
, message
, wParam
, lParam
);
1836 if( KEYDATA_ALT
& HIWORD(lParam
) )
1837 if( wParam
== VK_UP
|| wParam
== VK_DOWN
)
1838 COMBO_FlipListbox( lphc
, FALSE
, FALSE
);
1842 if ((wParam
== VK_RETURN
|| wParam
== VK_ESCAPE
) &&
1843 (lphc
->wState
& CBF_DROPPED
))
1845 CBRollUp( lphc
, wParam
== VK_RETURN
, FALSE
);
1848 else if ((wParam
== VK_F4
) && !(lphc
->wState
& CBF_EUI
))
1850 COMBO_FlipListbox( lphc
, FALSE
, FALSE
);
1859 if( lphc
->wState
& CBF_EDIT
)
1860 hwndTarget
= lphc
->hWndEdit
;
1862 hwndTarget
= lphc
->hWndLBox
;
1864 return unicode
? SendMessageW(hwndTarget
, message
, wParam
, lParam
) :
1865 SendMessageA(hwndTarget
, message
, wParam
, lParam
);
1867 case WM_LBUTTONDOWN
:
1868 if (!(lphc
->wState
& CBF_FOCUSED
)) NtUserSetFocus( lphc
->self
);
1869 if (lphc
->wState
& CBF_FOCUSED
) COMBO_LButtonDown( lphc
, lParam
);
1872 COMBO_LButtonUp( lphc
);
1875 if( lphc
->wState
& CBF_CAPTURE
)
1876 COMBO_MouseMove( lphc
, wParam
, lParam
);
1880 if (wParam
& (MK_SHIFT
| MK_CONTROL
))
1881 return unicode
? DefWindowProcW(hwnd
, message
, wParam
, lParam
) :
1882 DefWindowProcA(hwnd
, message
, wParam
, lParam
);
1884 if (GET_WHEEL_DELTA_WPARAM(wParam
) > 0) return SendMessageW(hwnd
, WM_KEYDOWN
, VK_UP
, 0);
1885 if (GET_WHEEL_DELTA_WPARAM(wParam
) < 0) return SendMessageW(hwnd
, WM_KEYDOWN
, VK_DOWN
, 0);
1889 case WM_CTLCOLORMSGBOX
:
1890 case WM_CTLCOLOREDIT
:
1891 case WM_CTLCOLORLISTBOX
:
1892 case WM_CTLCOLORBTN
:
1893 case WM_CTLCOLORDLG
:
1894 case WM_CTLCOLORSCROLLBAR
:
1895 case WM_CTLCOLORSTATIC
:
1897 return SendMessageW(lphc
->owner
, message
, wParam
, lParam
);
1900 /* Combo messages */
1905 if( lphc
->dwStyle
& CBS_LOWERCASE
)
1906 CharLowerW((LPWSTR
)lParam
);
1907 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
1908 CharUpperW((LPWSTR
)lParam
);
1909 return SendMessageW(lphc
->hWndLBox
, LB_ADDSTRING
, 0, lParam
);
1911 else /* unlike the unicode version, the ansi version does not overwrite
1912 the string if converting case */
1914 char *string
= NULL
;
1916 if( lphc
->dwStyle
& CBS_LOWERCASE
)
1918 string
= strdup((char *)lParam
);
1922 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
1924 string
= strdup((char *)lParam
);
1928 ret
= SendMessageA(lphc
->hWndLBox
, LB_ADDSTRING
, 0, string
? (LPARAM
)string
: lParam
);
1932 case CB_INSERTSTRING
:
1935 if( lphc
->dwStyle
& CBS_LOWERCASE
)
1936 CharLowerW((LPWSTR
)lParam
);
1937 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
1938 CharUpperW((LPWSTR
)lParam
);
1939 return SendMessageW(lphc
->hWndLBox
, LB_INSERTSTRING
, wParam
, lParam
);
1943 if( lphc
->dwStyle
& CBS_LOWERCASE
)
1944 CharLowerA((LPSTR
)lParam
);
1945 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
1946 CharUpperA((LPSTR
)lParam
);
1948 return SendMessageA(lphc
->hWndLBox
, LB_INSERTSTRING
, wParam
, lParam
);
1950 case CB_DELETESTRING
:
1951 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_DELETESTRING
, wParam
, 0) :
1952 SendMessageA(lphc
->hWndLBox
, LB_DELETESTRING
, wParam
, 0);
1953 case CB_SELECTSTRING
:
1954 return COMBO_SelectString(lphc
, (INT
)wParam
, lParam
, unicode
);
1956 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_FINDSTRING
, wParam
, lParam
) :
1957 SendMessageA(lphc
->hWndLBox
, LB_FINDSTRING
, wParam
, lParam
);
1958 case CB_FINDSTRINGEXACT
:
1959 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_FINDSTRINGEXACT
, wParam
, lParam
) :
1960 SendMessageA(lphc
->hWndLBox
, LB_FINDSTRINGEXACT
, wParam
, lParam
);
1961 case CB_SETITEMHEIGHT
:
1962 return COMBO_SetItemHeight( lphc
, (INT
)wParam
, (INT
)lParam
);
1963 case CB_GETITEMHEIGHT
:
1964 if( (INT
)wParam
>= 0 ) /* listbox item */
1965 return SendMessageW(lphc
->hWndLBox
, LB_GETITEMHEIGHT
, wParam
, 0);
1966 return CBGetTextAreaHeight(lphc
, FALSE
);
1967 case CB_RESETCONTENT
:
1968 SendMessageW(lphc
->hWndLBox
, LB_RESETCONTENT
, 0, 0);
1969 if( (lphc
->wState
& CBF_EDIT
) && CB_HASSTRINGS(lphc
) )
1970 SendMessageW(lphc
->hWndEdit
, WM_SETTEXT
, 0, (LPARAM
)L
"");
1972 NtUserInvalidateRect(lphc
->self
, NULL
, TRUE
);
1974 case CB_INITSTORAGE
:
1975 return SendMessageW(lphc
->hWndLBox
, LB_INITSTORAGE
, wParam
, lParam
);
1976 case CB_GETHORIZONTALEXTENT
:
1977 return SendMessageW(lphc
->hWndLBox
, LB_GETHORIZONTALEXTENT
, 0, 0);
1978 case CB_SETHORIZONTALEXTENT
:
1979 return SendMessageW(lphc
->hWndLBox
, LB_SETHORIZONTALEXTENT
, wParam
, 0);
1980 case CB_GETTOPINDEX
:
1981 return SendMessageW(lphc
->hWndLBox
, LB_GETTOPINDEX
, 0, 0);
1983 return SendMessageW(lphc
->hWndLBox
, LB_GETLOCALE
, 0, 0);
1985 return SendMessageW(lphc
->hWndLBox
, LB_SETLOCALE
, wParam
, 0);
1986 case CB_SETDROPPEDWIDTH
:
1987 if( (CB_GETTYPE(lphc
) == CBS_SIMPLE
) ||
1988 (INT
)wParam
>= 32768 )
1990 /* new value must be higher than combobox width */
1991 if((INT
)wParam
>= lphc
->droppedRect
.right
- lphc
->droppedRect
.left
)
1992 lphc
->droppedWidth
= wParam
;
1994 lphc
->droppedWidth
= 0;
1996 /* recalculate the combobox area */
1997 CBCalcPlacement(lphc
);
2000 case CB_GETDROPPEDWIDTH
:
2001 if( lphc
->droppedWidth
)
2002 return lphc
->droppedWidth
;
2003 return lphc
->droppedRect
.right
- lphc
->droppedRect
.left
;
2004 case CB_GETDROPPEDCONTROLRECT
:
2005 if( lParam
) CBGetDroppedControlRect(lphc
, (LPRECT
)lParam
);
2007 case CB_GETDROPPEDSTATE
:
2008 return (lphc
->wState
& CBF_DROPPED
) != 0;
2010 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_DIR
, wParam
, lParam
) :
2011 SendMessageA(lphc
->hWndLBox
, LB_DIR
, wParam
, lParam
);
2013 case CB_SHOWDROPDOWN
:
2014 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
2018 if( !(lphc
->wState
& CBF_DROPPED
) )
2022 if( lphc
->wState
& CBF_DROPPED
)
2023 CBRollUp( lphc
, FALSE
, TRUE
);
2027 return SendMessageW(lphc
->hWndLBox
, LB_GETCOUNT
, 0, 0);
2029 return SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
2031 lParam
= SendMessageW(lphc
->hWndLBox
, LB_SETCURSEL
, wParam
, 0);
2033 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
, wParam
, 0);
2035 /* no LBN_SELCHANGE in this case, update manually */
2036 CBPaintText( lphc
, NULL
);
2037 lphc
->wState
&= ~CBF_SELCHANGE
;
2040 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, wParam
, lParam
) :
2041 SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, wParam
, lParam
);
2042 case CB_GETLBTEXTLEN
:
2043 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, wParam
, 0) :
2044 SendMessageA(lphc
->hWndLBox
, LB_GETTEXTLEN
, wParam
, 0);
2045 case CB_GETITEMDATA
:
2046 return SendMessageW(lphc
->hWndLBox
, LB_GETITEMDATA
, wParam
, 0);
2047 case CB_SETITEMDATA
:
2048 return SendMessageW(lphc
->hWndLBox
, LB_SETITEMDATA
, wParam
, lParam
);
2050 /* Edit checks passed parameters itself */
2051 if( lphc
->wState
& CBF_EDIT
)
2052 return SendMessageW(lphc
->hWndEdit
, EM_GETSEL
, wParam
, lParam
);
2055 if( lphc
->wState
& CBF_EDIT
)
2056 return SendMessageW(lphc
->hWndEdit
, EM_SETSEL
,
2057 (INT
)(SHORT
)LOWORD(lParam
), (INT
)(SHORT
)HIWORD(lParam
) );
2059 case CB_SETEXTENDEDUI
:
2060 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
2063 lphc
->wState
|= CBF_EUI
;
2064 else lphc
->wState
&= ~CBF_EUI
;
2066 case CB_GETEXTENDEDUI
:
2067 return (lphc
->wState
& CBF_EUI
) != 0;
2068 case CB_GETCOMBOBOXINFO
:
2069 return COMBO_GetComboBoxInfo(lphc
, (COMBOBOXINFO
*)lParam
);
2071 if( lphc
->wState
& CBF_EDIT
)
2072 return SendMessageW(lphc
->hWndEdit
, EM_LIMITTEXT
, wParam
, lParam
);
2075 if (message
>= WM_USER
)
2076 WARN("unknown msg WM_USER+%04x wp=%04Ix lp=%08Ix\n",
2077 message
- WM_USER
, wParam
, lParam
);
2080 return unicode
? DefWindowProcW(hwnd
, message
, wParam
, lParam
) :
2081 DefWindowProcA(hwnd
, message
, wParam
, lParam
);
2084 /*************************************************************************
2085 * GetComboBoxInfo (USER32.@)
2087 BOOL WINAPI
GetComboBoxInfo(HWND hwndCombo
, /* [in] handle to combo box */
2088 PCOMBOBOXINFO pcbi
/* [in/out] combo box information */)
2090 TRACE("(%p, %p)\n", hwndCombo
, pcbi
);
2091 return SendMessageW(hwndCombo
, CB_GETCOMBOBOXINFO
, 0, (LPARAM
)pcbi
);