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
33 #include "user_private.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(combo
);
41 /* bits in the dwKeyData */
42 #define KEYDATA_ALT 0x2000
43 #define KEYDATA_PREVSTATE 0x4000
46 * Additional combo box definitions
49 #define CB_NOTIFY( lphc, code ) \
50 (SendMessageW((lphc)->owner, WM_COMMAND, \
51 MAKEWPARAM(GetWindowLongPtrW((lphc)->self,GWLP_ID), (code)), (LPARAM)(lphc)->self))
53 #define CB_DISABLED( lphc ) (!IsWindowEnabled((lphc)->self))
54 #define CB_OWNERDRAWN( lphc ) ((lphc)->dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE))
55 #define CB_HASSTRINGS( lphc ) ((lphc)->dwStyle & CBS_HASSTRINGS)
56 #define CB_HWND( lphc ) ((lphc)->self)
57 #define CB_GETTYPE( lphc ) ((lphc)->dwStyle & (CBS_DROPDOWNLIST))
59 #define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
64 static HBITMAP hComboBmp
= 0;
65 static UINT CBitHeight
, CBitWidth
;
68 * Look and feel dependent "constants"
71 #define COMBO_YBORDERGAP 5
72 #define COMBO_XBORDERSIZE() 2
73 #define COMBO_YBORDERSIZE() 2
74 #define COMBO_EDITBUTTONSPACE() 0
75 #define EDIT_CONTROL_PADDING() 1
77 static void CBCalcPlacement(HEADCOMBO
*combo
);
78 static void CBResetPos(HEADCOMBO
*combo
, BOOL redraw
);
80 /*********************************************************************
81 * combo class descriptor
83 const struct builtin_class_descr COMBO_builtin_class
=
85 L
"ComboBox", /* name */
86 CS_PARENTDC
| CS_DBLCLKS
| CS_HREDRAW
| CS_VREDRAW
, /* style */
87 WINPROC_COMBO
, /* proc */
88 sizeof(HEADCOMBO
*), /* extra */
89 IDC_ARROW
, /* cursor */
94 /***********************************************************************
97 * Load combo button bitmap.
99 static BOOL
COMBO_Init(void)
103 if( hComboBmp
) return TRUE
;
104 if( (hDC
= CreateCompatibleDC(0)) )
107 if( (hComboBmp
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_COMBO
))) )
113 GetObjectW( hComboBmp
, sizeof(bm
), &bm
);
114 CBitHeight
= bm
.bmHeight
;
115 CBitWidth
= bm
.bmWidth
;
117 TRACE("combo bitmap [%i,%i]\n", CBitWidth
, CBitHeight
);
119 hPrevB
= SelectObject( hDC
, hComboBmp
);
120 SetRect( &r
, 0, 0, CBitWidth
, CBitHeight
);
121 InvertRect( hDC
, &r
);
122 SelectObject( hDC
, hPrevB
);
131 /***********************************************************************
134 static LRESULT
COMBO_NCCreate(HWND hwnd
, LONG style
)
138 if (COMBO_Init() && (lphc
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HEADCOMBO
))) )
141 SetWindowLongPtrW( hwnd
, 0, (LONG_PTR
)lphc
);
143 /* some braindead apps do try to use scrollbar/border flags */
145 lphc
->dwStyle
= style
& ~(WS_BORDER
| WS_HSCROLL
| WS_VSCROLL
);
146 SetWindowLongW( hwnd
, GWL_STYLE
, style
& ~(WS_BORDER
| WS_HSCROLL
| WS_VSCROLL
) );
149 * We also have to remove the client edge style to make sure
150 * we don't end-up with a non client area.
152 SetWindowLongW( hwnd
, GWL_EXSTYLE
,
153 GetWindowLongW( hwnd
, GWL_EXSTYLE
) & ~WS_EX_CLIENTEDGE
);
155 if( !(style
& (CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
)) )
156 lphc
->dwStyle
|= CBS_HASSTRINGS
;
157 if( !(GetWindowLongW( hwnd
, GWL_EXSTYLE
) & WS_EX_NOPARENTNOTIFY
) )
158 lphc
->wState
|= CBF_NOTIFY
;
160 TRACE("[%p], style = %08x\n", lphc
, lphc
->dwStyle
);
166 /***********************************************************************
169 static LRESULT
COMBO_NCDestroy( LPHEADCOMBO lphc
)
174 TRACE("[%p]: freeing storage\n", lphc
->self
);
176 if( (CB_GETTYPE(lphc
) != CBS_SIMPLE
) && lphc
->hWndLBox
)
177 DestroyWindow( lphc
->hWndLBox
);
179 SetWindowLongPtrW( lphc
->self
, 0, 0 );
180 HeapFree( GetProcessHeap(), 0, lphc
);
185 static INT
combo_get_text_height(const HEADCOMBO
*combo
)
187 HDC hdc
= GetDC(combo
->self
);
192 prev_font
= SelectObject(hdc
, combo
->hFont
);
194 GetTextMetricsW(hdc
, &tm
);
197 SelectObject(hdc
, prev_font
);
199 ReleaseDC(combo
->self
, hdc
);
201 return tm
.tmHeight
+ 4;
204 /***********************************************************************
205 * CBGetTextAreaHeight
207 * This method will calculate the height of the text area of the
209 * The height of the text area is set in two ways.
210 * It can be set explicitly through a combobox message or through a
211 * WM_MEASUREITEM callback.
212 * If this is not the case, the height is set to font height + 4px
213 * This height was determined through experimentation.
214 * CBCalcPlacement will add 2*COMBO_YBORDERSIZE pixels for the border
216 static INT
CBGetTextAreaHeight(HEADCOMBO
*lphc
, BOOL clip_item_height
)
218 INT item_height
, text_height
;
220 if (clip_item_height
&& !CB_OWNERDRAWN(lphc
))
222 text_height
= combo_get_text_height(lphc
);
223 if (lphc
->item_height
< text_height
)
224 lphc
->item_height
= text_height
;
227 item_height
= lphc
->item_height
;
230 * Check the ownerdraw case if we haven't asked the parent the size
233 if ( CB_OWNERDRAWN(lphc
) &&
234 (lphc
->wState
& CBF_MEASUREITEM
) )
236 MEASUREITEMSTRUCT measureItem
;
238 INT originalItemHeight
= item_height
;
239 UINT id
= (UINT
)GetWindowLongPtrW( lphc
->self
, GWLP_ID
);
242 * We use the client rect for the width of the item.
244 GetClientRect(lphc
->self
, &clientRect
);
246 lphc
->wState
&= ~CBF_MEASUREITEM
;
249 * Send a first one to measure the size of the text area
251 measureItem
.CtlType
= ODT_COMBOBOX
;
252 measureItem
.CtlID
= id
;
253 measureItem
.itemID
= -1;
254 measureItem
.itemWidth
= clientRect
.right
;
255 measureItem
.itemHeight
= item_height
- 6; /* ownerdrawn cb is taller */
256 measureItem
.itemData
= 0;
257 SendMessageW(lphc
->owner
, WM_MEASUREITEM
, id
, (LPARAM
)&measureItem
);
258 item_height
= 6 + measureItem
.itemHeight
;
261 * Send a second one in the case of a fixed ownerdraw list to calculate the
262 * size of the list items. (we basically do this on behalf of the listbox)
264 if (lphc
->dwStyle
& CBS_OWNERDRAWFIXED
)
266 measureItem
.CtlType
= ODT_COMBOBOX
;
267 measureItem
.CtlID
= id
;
268 measureItem
.itemID
= 0;
269 measureItem
.itemWidth
= clientRect
.right
;
270 measureItem
.itemHeight
= originalItemHeight
;
271 measureItem
.itemData
= 0;
272 SendMessageW(lphc
->owner
, WM_MEASUREITEM
, id
, (LPARAM
)&measureItem
);
273 lphc
->fixedOwnerDrawHeight
= measureItem
.itemHeight
;
277 * Keep the size for the next time
279 lphc
->item_height
= item_height
;
285 /***********************************************************************
288 * The dummy resize is used for listboxes that have a popup to trigger
289 * a re-arranging of the contents of the combobox and the recalculation
290 * of the size of the "real" control window.
292 static void CBForceDummyResize(LPHEADCOMBO lphc
)
297 newComboHeight
= CBGetTextAreaHeight(lphc
, FALSE
) + 2*COMBO_YBORDERSIZE();
299 GetWindowRect(lphc
->self
, &windowRect
);
302 * We have to be careful, resizing a combobox also has the meaning that the
303 * dropped rect will be resized. In this case, we want to trigger a resize
304 * to recalculate layout but we don't want to change the dropped rectangle
305 * So, we pass the height of text area of control as the height.
306 * this will cancel-out in the processing of the WM_WINDOWPOSCHANGING
309 lphc
->wState
|= CBF_NORESIZE
;
310 SetWindowPos( lphc
->self
,
313 windowRect
.right
- windowRect
.left
,
315 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
316 lphc
->wState
&= ~CBF_NORESIZE
;
318 CBCalcPlacement(lphc
);
319 CBResetPos(lphc
, FALSE
);
322 /***********************************************************************
325 * Set up component coordinates given valid lphc->RectCombo.
327 static void CBCalcPlacement(HEADCOMBO
*combo
)
329 /* Start with the client rectangle. */
330 GetClientRect(combo
->self
, &combo
->textRect
);
332 /* Remove the borders */
333 InflateRect(&combo
->textRect
, -COMBO_XBORDERSIZE(), -COMBO_YBORDERSIZE());
335 /* Chop off the bottom part to fit with the height of the text area. */
336 combo
->textRect
.bottom
= combo
->textRect
.top
+ CBGetTextAreaHeight(combo
, FALSE
);
338 /* The button starts the same vertical position as the text area. */
339 combo
->buttonRect
= combo
->textRect
;
341 /* If the combobox is "simple" there is no button. */
342 if (CB_GETTYPE(combo
) == CBS_SIMPLE
)
343 combo
->buttonRect
.left
= combo
->buttonRect
.right
= combo
->buttonRect
.bottom
= 0;
347 * Let's assume the combobox button is the same width as the
349 * size the button horizontally and cut-off the text area.
351 combo
->buttonRect
.left
= combo
->buttonRect
.right
- GetSystemMetrics(SM_CXVSCROLL
);
352 combo
->textRect
.right
= combo
->buttonRect
.left
;
355 /* In the case of a dropdown, there is an additional spacing between the text area and the button. */
356 if (CB_GETTYPE(combo
) == CBS_DROPDOWN
)
357 combo
->textRect
.right
-= COMBO_EDITBUTTONSPACE();
359 /* If we have an edit control, we space it away from the borders slightly. */
360 if (CB_GETTYPE(combo
) != CBS_DROPDOWNLIST
)
361 InflateRect(&combo
->textRect
, -EDIT_CONTROL_PADDING(), -EDIT_CONTROL_PADDING());
363 /* Adjust the size of the listbox popup. */
364 if (CB_GETTYPE(combo
) == CBS_SIMPLE
)
366 GetClientRect(combo
->self
, &combo
->droppedRect
);
367 combo
->droppedRect
.top
= combo
->textRect
.bottom
+ COMBO_YBORDERSIZE();
371 /* Make sure the dropped width is as large as the combobox itself. */
372 if (combo
->droppedWidth
< (combo
->buttonRect
.right
+ COMBO_XBORDERSIZE()))
374 combo
->droppedRect
.right
= combo
->droppedRect
.left
+ (combo
->buttonRect
.right
+ COMBO_XBORDERSIZE());
376 /* In the case of a dropdown, the popup listbox is offset to the right. We want to make sure it's flush
377 with the right side of the combobox. */
378 if (CB_GETTYPE(combo
) == CBS_DROPDOWN
)
379 combo
->droppedRect
.right
-= COMBO_EDITBUTTONSPACE();
382 combo
->droppedRect
.right
= combo
->droppedRect
.left
+ combo
->droppedWidth
;
385 /* Disallow negative window width */
386 if (combo
->textRect
.right
< combo
->textRect
.left
)
387 combo
->textRect
.right
= combo
->textRect
.left
;
389 TRACE("text %s, button %s, lbox %s.\n", wine_dbgstr_rect(&combo
->textRect
), wine_dbgstr_rect(&combo
->buttonRect
),
390 wine_dbgstr_rect(&combo
->droppedRect
));
393 /***********************************************************************
394 * CBGetDroppedControlRect
396 static void CBGetDroppedControlRect( LPHEADCOMBO lphc
, LPRECT lpRect
)
398 /* In windows, CB_GETDROPPEDCONTROLRECT returns the upper left corner
399 of the combo box and the lower right corner of the listbox */
401 GetWindowRect(lphc
->self
, lpRect
);
403 lpRect
->right
= lpRect
->left
+ lphc
->droppedRect
.right
- lphc
->droppedRect
.left
;
404 lpRect
->bottom
= lpRect
->top
+ lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
;
408 /***********************************************************************
411 static LRESULT
COMBO_Create( HWND hwnd
, LPHEADCOMBO lphc
, HWND hwndParent
, LONG style
,
414 if( !CB_GETTYPE(lphc
) ) lphc
->dwStyle
|= CBS_SIMPLE
;
415 if( CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
) lphc
->wState
|= CBF_EDIT
;
417 lphc
->owner
= hwndParent
;
419 lphc
->droppedWidth
= 0;
421 lphc
->item_height
= combo_get_text_height(lphc
);
424 * The first time we go through, we want to measure the ownerdraw item
426 lphc
->wState
|= CBF_MEASUREITEM
;
428 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
430 if( lphc
->owner
|| !(style
& WS_VISIBLE
) )
436 * Initialize the dropped rect to the size of the client area of the
437 * control and then, force all the areas of the combobox to be
440 GetClientRect( hwnd
, &lphc
->droppedRect
);
441 CBCalcPlacement(lphc
);
444 * Adjust the position of the popup listbox if it's necessary
446 if ( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
448 lphc
->droppedRect
.top
= lphc
->textRect
.bottom
+ COMBO_YBORDERSIZE();
451 * If it's a dropdown, the listbox is offset
453 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
454 lphc
->droppedRect
.left
+= COMBO_EDITBUTTONSPACE();
456 if (lphc
->droppedRect
.bottom
< lphc
->droppedRect
.top
)
457 lphc
->droppedRect
.bottom
= lphc
->droppedRect
.top
;
458 if (lphc
->droppedRect
.right
< lphc
->droppedRect
.left
)
459 lphc
->droppedRect
.right
= lphc
->droppedRect
.left
;
460 MapWindowPoints( hwnd
, 0, (LPPOINT
)&lphc
->droppedRect
, 2 );
463 /* create listbox popup */
465 lbeStyle
= (LBS_NOTIFY
| LBS_COMBOBOX
| WS_BORDER
| WS_CLIPSIBLINGS
| WS_CHILD
) |
466 (style
& (WS_VSCROLL
| CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
));
468 if( lphc
->dwStyle
& CBS_SORT
)
469 lbeStyle
|= LBS_SORT
;
470 if( lphc
->dwStyle
& CBS_HASSTRINGS
)
471 lbeStyle
|= LBS_HASSTRINGS
;
472 if( lphc
->dwStyle
& CBS_NOINTEGRALHEIGHT
)
473 lbeStyle
|= LBS_NOINTEGRALHEIGHT
;
474 if( lphc
->dwStyle
& CBS_DISABLENOSCROLL
)
475 lbeStyle
|= LBS_DISABLENOSCROLL
;
477 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
) /* child listbox */
479 lbeStyle
|= WS_VISIBLE
;
482 * In win 95 look n feel, the listbox in the simple combobox has
483 * the WS_EXCLIENTEDGE style instead of the WS_BORDER style.
485 lbeStyle
&= ~WS_BORDER
;
486 lbeExStyle
|= WS_EX_CLIENTEDGE
;
490 lbeExStyle
|= (WS_EX_TOPMOST
| WS_EX_TOOLWINDOW
);
494 lphc
->hWndLBox
= CreateWindowExW(lbeExStyle
, L
"ComboLBox", NULL
, lbeStyle
,
495 lphc
->droppedRect
.left
,
496 lphc
->droppedRect
.top
,
497 lphc
->droppedRect
.right
- lphc
->droppedRect
.left
,
498 lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
,
499 hwnd
, (HMENU
)ID_CB_LISTBOX
,
500 (HINSTANCE
)GetWindowLongPtrW( hwnd
, GWLP_HINSTANCE
), lphc
);
502 lphc
->hWndLBox
= CreateWindowExA(lbeExStyle
, "ComboLBox", NULL
, lbeStyle
,
503 lphc
->droppedRect
.left
,
504 lphc
->droppedRect
.top
,
505 lphc
->droppedRect
.right
- lphc
->droppedRect
.left
,
506 lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
,
507 hwnd
, (HMENU
)ID_CB_LISTBOX
,
508 (HINSTANCE
)GetWindowLongPtrW( hwnd
, GWLP_HINSTANCE
), lphc
);
513 lbeStyle
= WS_CHILD
| WS_VISIBLE
| ES_NOHIDESEL
| ES_LEFT
| ES_COMBO
;
515 if( lphc
->wState
& CBF_EDIT
)
517 if( lphc
->dwStyle
& CBS_OEMCONVERT
)
518 lbeStyle
|= ES_OEMCONVERT
;
519 if( lphc
->dwStyle
& CBS_AUTOHSCROLL
)
520 lbeStyle
|= ES_AUTOHSCROLL
;
521 if( lphc
->dwStyle
& CBS_LOWERCASE
)
522 lbeStyle
|= ES_LOWERCASE
;
523 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
524 lbeStyle
|= ES_UPPERCASE
;
526 if (!IsWindowEnabled(hwnd
)) lbeStyle
|= WS_DISABLED
;
529 lphc
->hWndEdit
= CreateWindowExW(0, L
"Edit", NULL
, lbeStyle
,
530 lphc
->textRect
.left
, lphc
->textRect
.top
,
531 lphc
->textRect
.right
- lphc
->textRect
.left
,
532 lphc
->textRect
.bottom
- lphc
->textRect
.top
,
533 hwnd
, (HMENU
)ID_CB_EDIT
,
534 (HINSTANCE
)GetWindowLongPtrW( hwnd
, GWLP_HINSTANCE
), NULL
);
536 lphc
->hWndEdit
= CreateWindowExA(0, "Edit", NULL
, lbeStyle
,
537 lphc
->textRect
.left
, lphc
->textRect
.top
,
538 lphc
->textRect
.right
- lphc
->textRect
.left
,
539 lphc
->textRect
.bottom
- lphc
->textRect
.top
,
540 hwnd
, (HMENU
)ID_CB_EDIT
,
541 (HINSTANCE
)GetWindowLongPtrW( hwnd
, GWLP_HINSTANCE
), NULL
);
543 if( !lphc
->hWndEdit
)
549 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
551 /* Now do the trick with parent */
552 SetParent(lphc
->hWndLBox
, HWND_DESKTOP
);
554 * If the combo is a dropdown, we must resize the control
555 * to fit only the text area and button. To do this,
556 * we send a dummy resize and the WM_WINDOWPOSCHANGING message
557 * will take care of setting the height for us.
559 CBForceDummyResize(lphc
);
562 TRACE("init done\n");
565 ERR("edit control failure.\n");
566 } else ERR("listbox failure.\n");
567 } else ERR("no owner for visible combo.\n");
569 /* CreateWindow() will send WM_NCDESTROY to cleanup */
574 /***********************************************************************
577 * Paint combo button (normal, pressed, and disabled states).
579 static void CBPaintButton(HEADCOMBO
*lphc
, HDC hdc
)
581 UINT buttonState
= DFCS_SCROLLCOMBOBOX
;
583 if (IsRectEmpty(&lphc
->buttonRect
))
586 if( lphc
->wState
& CBF_NOREDRAW
)
590 if (lphc
->wState
& CBF_BUTTONDOWN
)
591 buttonState
|= DFCS_PUSHED
;
593 if (CB_DISABLED(lphc
))
594 buttonState
|= DFCS_INACTIVE
;
596 DrawFrameControl(hdc
, &lphc
->buttonRect
, DFC_SCROLL
, buttonState
);
599 /***********************************************************************
600 * COMBO_PrepareColors
602 * This method will sent the appropriate WM_CTLCOLOR message to
603 * prepare and setup the colors for the combo's DC.
605 * It also returns the brush to use for the background.
607 static HBRUSH
COMBO_PrepareColors(
614 * Get the background brush for this control.
616 if (CB_DISABLED(lphc
))
618 hBkgBrush
= (HBRUSH
)SendMessageW(lphc
->owner
, WM_CTLCOLORSTATIC
,
619 (WPARAM
)hDC
, (LPARAM
)lphc
->self
);
622 * We have to change the text color since WM_CTLCOLORSTATIC will
623 * set it to the "enabled" color. This is the same behavior as the
626 SetTextColor(hDC
, GetSysColor(COLOR_GRAYTEXT
));
630 /* FIXME: In which cases WM_CTLCOLORLISTBOX should be sent? */
631 hBkgBrush
= (HBRUSH
)SendMessageW(lphc
->owner
, WM_CTLCOLOREDIT
,
632 (WPARAM
)hDC
, (LPARAM
)lphc
->self
);
639 hBkgBrush
= GetSysColorBrush(COLOR_WINDOW
);
644 /***********************************************************************
647 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
649 static void CBPaintText(
653 RECT rectEdit
= lphc
->textRect
;
659 /* follow Windows combobox that sends a bunch of text
660 * inquiries to its listbox while processing WM_PAINT. */
662 if( (id
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0) ) != LB_ERR
)
664 size
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, id
, 0);
666 FIXME("LB_ERR probably not handled yet\n");
667 if( (pText
= HeapAlloc( GetProcessHeap(), 0, (size
+ 1) * sizeof(WCHAR
))) )
669 /* size from LB_GETTEXTLEN may be too large, from LB_GETTEXT is accurate */
670 size
=SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, id
, (LPARAM
)pText
);
671 pText
[size
] = '\0'; /* just in case */
675 if( lphc
->wState
& CBF_EDIT
)
677 if( CB_HASSTRINGS(lphc
) ) SetWindowTextW( lphc
->hWndEdit
, pText
? pText
: L
"" );
678 if( lphc
->wState
& CBF_FOCUSED
)
679 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, MAXLONG
);
681 else if(!(lphc
->wState
& CBF_NOREDRAW
) && IsWindowVisible( lphc
->self
))
683 /* paint text field ourselves */
684 HDC hdc
= hdc_paint
? hdc_paint
: GetDC(lphc
->self
);
685 UINT itemState
= ODS_COMBOBOXEDIT
;
686 HFONT hPrevFont
= (lphc
->hFont
) ? SelectObject(hdc
, lphc
->hFont
) : 0;
687 HBRUSH hPrevBrush
, hBkgBrush
;
690 * Give ourselves some space.
692 InflateRect( &rectEdit
, -1, -1 );
694 hBkgBrush
= COMBO_PrepareColors( lphc
, hdc
);
695 hPrevBrush
= SelectObject( hdc
, hBkgBrush
);
696 FillRect( hdc
, &rectEdit
, hBkgBrush
);
698 if( CB_OWNERDRAWN(lphc
) )
702 UINT ctlid
= (UINT
)GetWindowLongPtrW( lphc
->self
, GWLP_ID
);
704 /* setup state for DRAWITEM message. Owner will highlight */
705 if ( (lphc
->wState
& CBF_FOCUSED
) &&
706 !(lphc
->wState
& CBF_DROPPED
) )
707 itemState
|= ODS_SELECTED
| ODS_FOCUS
;
709 if (!IsWindowEnabled(lphc
->self
)) itemState
|= ODS_DISABLED
;
711 dis
.CtlType
= ODT_COMBOBOX
;
713 dis
.hwndItem
= lphc
->self
;
714 dis
.itemAction
= ODA_DRAWENTIRE
;
716 dis
.itemState
= itemState
;
718 dis
.rcItem
= rectEdit
;
719 dis
.itemData
= SendMessageW(lphc
->hWndLBox
, LB_GETITEMDATA
, id
, 0);
722 * Clip the DC and have the parent draw the item.
724 clipRegion
= set_control_clipping( hdc
, &rectEdit
);
726 SendMessageW(lphc
->owner
, WM_DRAWITEM
, ctlid
, (LPARAM
)&dis
);
728 SelectClipRgn( hdc
, clipRegion
);
729 if (clipRegion
) DeleteObject( clipRegion
);
733 if ( (lphc
->wState
& CBF_FOCUSED
) &&
734 !(lphc
->wState
& CBF_DROPPED
) ) {
737 FillRect( hdc
, &rectEdit
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
738 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
739 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
745 ETO_OPAQUE
| ETO_CLIPPED
,
747 pText
? pText
: L
"" , size
, NULL
);
749 if(lphc
->wState
& CBF_FOCUSED
&& !(lphc
->wState
& CBF_DROPPED
))
750 DrawFocusRect( hdc
, &rectEdit
);
754 SelectObject(hdc
, hPrevFont
);
757 SelectObject( hdc
, hPrevBrush
);
760 ReleaseDC( lphc
->self
, hdc
);
762 HeapFree( GetProcessHeap(), 0, pText
);
765 /***********************************************************************
768 static void CBPaintBorder(const HEADCOMBO
*lphc
, HDC hdc
)
772 if (CB_GETTYPE(lphc
) != CBS_SIMPLE
)
774 GetClientRect(lphc
->self
, &clientRect
);
778 clientRect
= lphc
->textRect
;
780 InflateRect(&clientRect
, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
781 InflateRect(&clientRect
, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
784 DrawEdge(hdc
, &clientRect
, EDGE_SUNKEN
, BF_RECT
);
787 /***********************************************************************
790 static LRESULT
COMBO_Paint(LPHEADCOMBO lphc
, HDC hParamDC
)
795 hDC
= (hParamDC
) ? hParamDC
796 : BeginPaint( lphc
->self
, &ps
);
798 TRACE("hdc=%p\n", hDC
);
800 if( hDC
&& !(lphc
->wState
& CBF_NOREDRAW
) )
802 HBRUSH hPrevBrush
, hBkgBrush
;
805 * Retrieve the background brush and select it in the
808 hBkgBrush
= COMBO_PrepareColors(lphc
, hDC
);
810 hPrevBrush
= SelectObject( hDC
, hBkgBrush
);
811 if (!(lphc
->wState
& CBF_EDIT
))
812 FillRect(hDC
, &lphc
->textRect
, hBkgBrush
);
815 * In non 3.1 look, there is a sunken border on the combobox
817 CBPaintBorder(lphc
, hDC
);
818 CBPaintButton(lphc
, hDC
);
820 /* paint the edit control padding area */
821 if (CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
)
823 RECT rPadEdit
= lphc
->textRect
;
825 InflateRect(&rPadEdit
, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
827 FrameRect( hDC
, &rPadEdit
, GetSysColorBrush(COLOR_WINDOW
) );
830 if( !(lphc
->wState
& CBF_EDIT
) )
831 CBPaintText( lphc
, hDC
);
834 SelectObject( hDC
, hPrevBrush
);
838 EndPaint(lphc
->self
, &ps
);
843 /***********************************************************************
846 * Select listbox entry according to the contents of the edit control.
848 static INT
CBUpdateLBox( LPHEADCOMBO lphc
, BOOL bSelect
)
854 length
= SendMessageW( lphc
->hWndEdit
, WM_GETTEXTLENGTH
, 0, 0 );
857 pText
= HeapAlloc( GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
));
859 TRACE("\t edit text length %i\n", length
);
863 GetWindowTextW( lphc
->hWndEdit
, pText
, length
+ 1);
864 idx
= SendMessageW(lphc
->hWndLBox
, LB_FINDSTRING
, -1, (LPARAM
)pText
);
865 HeapFree( GetProcessHeap(), 0, pText
);
868 SendMessageW(lphc
->hWndLBox
, LB_SETCURSEL
, bSelect
? idx
: -1, 0);
870 /* probably superfluous but Windows sends this too */
871 SendMessageW(lphc
->hWndLBox
, LB_SETCARETINDEX
, idx
< 0 ? 0 : idx
, 0);
872 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
, idx
< 0 ? 0 : idx
, 0);
877 /***********************************************************************
880 * Copy a listbox entry to the edit control.
882 static void CBUpdateEdit( LPHEADCOMBO lphc
, INT index
)
887 TRACE("\t %i\n", index
);
889 if( index
>= 0 ) /* got an entry */
891 length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, index
, 0);
892 if( length
!= LB_ERR
)
894 if( (pText
= HeapAlloc( GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
))) )
896 SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, index
, (LPARAM
)pText
);
901 if( CB_HASSTRINGS(lphc
) )
903 lphc
->wState
|= (CBF_NOEDITNOTIFY
| CBF_NOLBSELECT
);
904 SendMessageW(lphc
->hWndEdit
, WM_SETTEXT
, 0, pText
? (LPARAM
)pText
: (LPARAM
)L
"");
905 lphc
->wState
&= ~(CBF_NOEDITNOTIFY
| CBF_NOLBSELECT
);
908 if( lphc
->wState
& CBF_FOCUSED
)
909 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, -1);
911 HeapFree( GetProcessHeap(), 0, pText
);
914 /***********************************************************************
917 * Show listbox popup.
919 static void CBDropDown( LPHEADCOMBO lphc
)
922 MONITORINFO mon_info
;
927 TRACE("[%p]: drop down\n", lphc
->self
);
929 CB_NOTIFY( lphc
, CBN_DROPDOWN
);
933 lphc
->wState
|= CBF_DROPPED
;
934 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
936 lphc
->droppedIndex
= CBUpdateLBox( lphc
, TRUE
);
938 /* Update edit only if item is in the list */
939 if( !(lphc
->wState
& CBF_CAPTURE
) && lphc
->droppedIndex
>= 0)
940 CBUpdateEdit( lphc
, lphc
->droppedIndex
);
944 lphc
->droppedIndex
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
946 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
,
947 lphc
->droppedIndex
== LB_ERR
? 0 : lphc
->droppedIndex
, 0);
948 SendMessageW(lphc
->hWndLBox
, LB_CARETON
, 0, 0);
951 /* now set popup position */
952 GetWindowRect( lphc
->self
, &rect
);
955 * If it's a dropdown, the listbox is offset
957 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
958 rect
.left
+= COMBO_EDITBUTTONSPACE();
960 /* if the dropped height is greater than the total height of the dropped
961 items list, then force the drop down list height to be the total height
962 of the items in the dropped list */
964 /* And Remove any extra space (Best Fit) */
965 nDroppedHeight
= lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
;
966 /* if listbox length has been set directly by its handle */
967 GetWindowRect(lphc
->hWndLBox
, &r
);
968 if (nDroppedHeight
< r
.bottom
- r
.top
)
969 nDroppedHeight
= r
.bottom
- r
.top
;
970 nItems
= (int)SendMessageW(lphc
->hWndLBox
, LB_GETCOUNT
, 0, 0);
977 nIHeight
= (int)SendMessageW(lphc
->hWndLBox
, LB_GETITEMHEIGHT
, 0, 0);
979 nHeight
= nIHeight
*nItems
;
981 if (nHeight
< nDroppedHeight
- COMBO_YBORDERSIZE())
982 nDroppedHeight
= nHeight
+ COMBO_YBORDERSIZE();
987 r
.right
= r
.left
+ lphc
->droppedRect
.right
- lphc
->droppedRect
.left
;
988 r
.bottom
= r
.top
+ nDroppedHeight
;
990 /*If height of dropped rectangle gets beyond a screen size it should go up, otherwise down.*/
991 monitor
= MonitorFromRect( &rect
, MONITOR_DEFAULTTOPRIMARY
);
992 mon_info
.cbSize
= sizeof(mon_info
);
993 GetMonitorInfoW( monitor
, &mon_info
);
995 if (r
.bottom
> mon_info
.rcWork
.bottom
)
997 r
.top
= max( rect
.top
- nDroppedHeight
, mon_info
.rcWork
.top
);
998 r
.bottom
= min( r
.top
+ nDroppedHeight
, mon_info
.rcWork
.bottom
);
1001 SetWindowPos( lphc
->hWndLBox
, HWND_TOPMOST
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
,
1002 SWP_NOACTIVATE
| SWP_SHOWWINDOW
);
1005 if( !(lphc
->wState
& CBF_NOREDRAW
) )
1006 RedrawWindow( lphc
->self
, NULL
, 0, RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
);
1008 EnableWindow( lphc
->hWndLBox
, TRUE
);
1009 if (GetCapture() != lphc
->self
)
1010 SetCapture(lphc
->hWndLBox
);
1013 /***********************************************************************
1016 * Hide listbox popup.
1018 static void CBRollUp( LPHEADCOMBO lphc
, BOOL ok
, BOOL bButton
)
1020 HWND hWnd
= lphc
->self
;
1022 TRACE("[%p]: sel ok? [%i] dropped? [%i]\n",
1023 lphc
->self
, ok
, (INT
)(lphc
->wState
& CBF_DROPPED
));
1025 CB_NOTIFY( lphc
, (ok
) ? CBN_SELENDOK
: CBN_SELENDCANCEL
);
1027 if( IsWindow( hWnd
) && CB_GETTYPE(lphc
) != CBS_SIMPLE
)
1030 if( lphc
->wState
& CBF_DROPPED
)
1034 lphc
->wState
&= ~CBF_DROPPED
;
1035 ShowWindow( lphc
->hWndLBox
, SW_HIDE
);
1037 if(GetCapture() == lphc
->hWndLBox
)
1042 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1044 rect
= lphc
->buttonRect
;
1055 rect
= lphc
->textRect
;
1060 if( bButton
&& !(lphc
->wState
& CBF_NOREDRAW
) )
1061 RedrawWindow( hWnd
, &rect
, 0, RDW_INVALIDATE
|
1062 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1063 CB_NOTIFY( lphc
, CBN_CLOSEUP
);
1068 /***********************************************************************
1071 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
1073 BOOL
COMBO_FlipListbox( LPHEADCOMBO lphc
, BOOL ok
, BOOL bRedrawButton
)
1075 if( lphc
->wState
& CBF_DROPPED
)
1077 CBRollUp( lphc
, ok
, bRedrawButton
);
1085 /***********************************************************************
1088 static void CBRepaintButton( LPHEADCOMBO lphc
)
1090 InvalidateRect(lphc
->self
, &lphc
->buttonRect
, TRUE
);
1091 UpdateWindow(lphc
->self
);
1094 /***********************************************************************
1097 static void COMBO_SetFocus( LPHEADCOMBO lphc
)
1099 if( !(lphc
->wState
& CBF_FOCUSED
) )
1101 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
1102 SendMessageW(lphc
->hWndLBox
, LB_CARETON
, 0, 0);
1104 /* This is wrong. Message sequences seem to indicate that this
1105 is set *after* the notify. */
1106 /* lphc->wState |= CBF_FOCUSED; */
1108 if( !(lphc
->wState
& CBF_EDIT
) )
1109 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1111 CB_NOTIFY( lphc
, CBN_SETFOCUS
);
1112 lphc
->wState
|= CBF_FOCUSED
;
1116 /***********************************************************************
1119 static void COMBO_KillFocus( LPHEADCOMBO lphc
)
1121 HWND hWnd
= lphc
->self
;
1123 if( lphc
->wState
& CBF_FOCUSED
)
1125 CBRollUp( lphc
, FALSE
, TRUE
);
1126 if( IsWindow( hWnd
) )
1128 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
1129 SendMessageW(lphc
->hWndLBox
, LB_CARETOFF
, 0, 0);
1131 lphc
->wState
&= ~CBF_FOCUSED
;
1134 if( !(lphc
->wState
& CBF_EDIT
) )
1135 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1137 CB_NOTIFY( lphc
, CBN_KILLFOCUS
);
1142 /***********************************************************************
1145 static LRESULT
COMBO_Command( LPHEADCOMBO lphc
, WPARAM wParam
, HWND hWnd
)
1147 if ( lphc
->wState
& CBF_EDIT
&& lphc
->hWndEdit
== hWnd
)
1149 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
1151 switch( HIWORD(wParam
) >> 8 )
1153 case (EN_SETFOCUS
>> 8):
1155 TRACE("[%p]: edit [%p] got focus\n", lphc
->self
, lphc
->hWndEdit
);
1157 COMBO_SetFocus( lphc
);
1160 case (EN_KILLFOCUS
>> 8):
1162 TRACE("[%p]: edit [%p] lost focus\n", lphc
->self
, lphc
->hWndEdit
);
1164 /* NOTE: it seems that Windows' edit control sends an
1165 * undocumented message WM_USER + 0x1B instead of this
1166 * notification (only when it happens to be a part of
1167 * the combo). ?? - AK.
1170 COMBO_KillFocus( lphc
);
1174 case (EN_CHANGE
>> 8):
1176 * In some circumstances (when the selection of the combobox
1177 * is changed for example) we don't want the EN_CHANGE notification
1178 * to be forwarded to the parent of the combobox. This code
1179 * checks a flag that is set in these occasions and ignores the
1182 if (lphc
->wState
& CBF_NOLBSELECT
)
1184 lphc
->wState
&= ~CBF_NOLBSELECT
;
1188 CBUpdateLBox( lphc
, lphc
->wState
& CBF_DROPPED
);
1191 if (!(lphc
->wState
& CBF_NOEDITNOTIFY
))
1192 CB_NOTIFY( lphc
, CBN_EDITCHANGE
);
1195 case (EN_UPDATE
>> 8):
1196 if (!(lphc
->wState
& CBF_NOEDITNOTIFY
))
1197 CB_NOTIFY( lphc
, CBN_EDITUPDATE
);
1200 case (EN_ERRSPACE
>> 8):
1201 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
1204 else if( lphc
->hWndLBox
== hWnd
)
1206 switch( (short)HIWORD(wParam
) )
1209 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
1213 CB_NOTIFY( lphc
, CBN_DBLCLK
);
1219 TRACE("[%p]: lbox selection change [%x]\n", lphc
->self
, lphc
->wState
);
1221 /* do not roll up if selection is being tracked
1222 * by arrow keys in the dropdown listbox */
1223 if (!(lphc
->wState
& CBF_NOROLLUP
))
1225 CBRollUp( lphc
, (HIWORD(wParam
) == LBN_SELCHANGE
), TRUE
);
1227 else lphc
->wState
&= ~CBF_NOROLLUP
;
1229 CB_NOTIFY( lphc
, CBN_SELCHANGE
);
1231 if( HIWORD(wParam
) == LBN_SELCHANGE
)
1233 if( lphc
->wState
& CBF_EDIT
)
1234 lphc
->wState
|= CBF_NOLBSELECT
;
1235 CBPaintText( lphc
, NULL
);
1241 /* nothing to do here since ComboLBox always resets the focus to its
1242 * combo/edit counterpart */
1249 /***********************************************************************
1252 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
1254 static LRESULT
COMBO_ItemOp( LPHEADCOMBO lphc
, UINT msg
, LPARAM lParam
)
1256 HWND hWnd
= lphc
->self
;
1257 UINT id
= (UINT
)GetWindowLongPtrW( hWnd
, GWLP_ID
);
1259 TRACE("[%p]: ownerdraw op %04x\n", lphc
->self
, msg
);
1265 DELETEITEMSTRUCT
*lpIS
= (DELETEITEMSTRUCT
*)lParam
;
1266 lpIS
->CtlType
= ODT_COMBOBOX
;
1268 lpIS
->hwndItem
= hWnd
;
1273 DRAWITEMSTRUCT
*lpIS
= (DRAWITEMSTRUCT
*)lParam
;
1274 lpIS
->CtlType
= ODT_COMBOBOX
;
1276 lpIS
->hwndItem
= hWnd
;
1279 case WM_COMPAREITEM
:
1281 COMPAREITEMSTRUCT
*lpIS
= (COMPAREITEMSTRUCT
*)lParam
;
1282 lpIS
->CtlType
= ODT_COMBOBOX
;
1284 lpIS
->hwndItem
= hWnd
;
1287 case WM_MEASUREITEM
:
1289 MEASUREITEMSTRUCT
*lpIS
= (MEASUREITEMSTRUCT
*)lParam
;
1290 lpIS
->CtlType
= ODT_COMBOBOX
;
1295 return SendMessageW(lphc
->owner
, msg
, id
, lParam
);
1299 /***********************************************************************
1302 static LRESULT
COMBO_GetTextW( LPHEADCOMBO lphc
, INT count
, LPWSTR buf
)
1306 if( lphc
->wState
& CBF_EDIT
)
1307 return SendMessageW( lphc
->hWndEdit
, WM_GETTEXT
, count
, (LPARAM
)buf
);
1309 /* get it from the listbox */
1311 if (!count
|| !buf
) return 0;
1312 if( lphc
->hWndLBox
)
1314 INT idx
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1315 if (idx
== LB_ERR
) goto error
;
1316 length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, idx
, 0 );
1317 if (length
== LB_ERR
) goto error
;
1319 /* 'length' is without the terminating character */
1320 if (length
>= count
)
1322 LPWSTR lpBuffer
= HeapAlloc(GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
));
1323 if (!lpBuffer
) goto error
;
1324 length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)lpBuffer
);
1326 /* truncate if buffer is too short */
1327 if (length
!= LB_ERR
)
1329 lstrcpynW( buf
, lpBuffer
, count
);
1332 HeapFree( GetProcessHeap(), 0, lpBuffer
);
1334 else length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)buf
);
1336 if (length
== LB_ERR
) return 0;
1340 error
: /* error - truncate string, return zero */
1346 /***********************************************************************
1349 * NOTE! LB_GETTEXT does not count terminating \0, WM_GETTEXT does.
1350 * also LB_GETTEXT might return values < 0, WM_GETTEXT doesn't.
1352 static LRESULT
COMBO_GetTextA( LPHEADCOMBO lphc
, INT count
, LPSTR buf
)
1356 if( lphc
->wState
& CBF_EDIT
)
1357 return SendMessageA( lphc
->hWndEdit
, WM_GETTEXT
, count
, (LPARAM
)buf
);
1359 /* get it from the listbox */
1361 if (!count
|| !buf
) return 0;
1362 if( lphc
->hWndLBox
)
1364 INT idx
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1365 if (idx
== LB_ERR
) goto error
;
1366 length
= SendMessageA(lphc
->hWndLBox
, LB_GETTEXTLEN
, idx
, 0 );
1367 if (length
== LB_ERR
) goto error
;
1369 /* 'length' is without the terminating character */
1370 if (length
>= count
)
1372 LPSTR lpBuffer
= HeapAlloc(GetProcessHeap(), 0, (length
+ 1) );
1373 if (!lpBuffer
) goto error
;
1374 length
= SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)lpBuffer
);
1376 /* truncate if buffer is too short */
1377 if (length
!= LB_ERR
)
1379 lstrcpynA( buf
, lpBuffer
, count
);
1382 HeapFree( GetProcessHeap(), 0, lpBuffer
);
1384 else length
= SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)buf
);
1386 if (length
== LB_ERR
) return 0;
1390 error
: /* error - truncate string, return zero */
1396 /***********************************************************************
1399 * This function sets window positions according to the updated
1400 * component placement struct.
1402 static void CBResetPos(HEADCOMBO
*combo
, BOOL redraw
)
1404 BOOL drop
= CB_GETTYPE(combo
) != CBS_SIMPLE
;
1406 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1407 * sizing messages */
1408 if (combo
->wState
& CBF_EDIT
)
1409 SetWindowPos(combo
->hWndEdit
, 0, combo
->textRect
.left
, combo
->textRect
.top
,
1410 combo
->textRect
.right
- combo
->textRect
.left
,
1411 combo
->textRect
.bottom
- combo
->textRect
.top
,
1412 SWP_NOZORDER
| SWP_NOACTIVATE
| (drop
? SWP_NOREDRAW
: 0));
1414 SetWindowPos(combo
->hWndLBox
, 0, combo
->droppedRect
.left
, combo
->droppedRect
.top
,
1415 combo
->droppedRect
.right
- combo
->droppedRect
.left
,
1416 combo
->droppedRect
.bottom
- combo
->droppedRect
.top
,
1417 SWP_NOACTIVATE
| SWP_NOZORDER
| (drop
? SWP_NOREDRAW
: 0));
1421 if (combo
->wState
& CBF_DROPPED
)
1423 combo
->wState
&= ~CBF_DROPPED
;
1424 ShowWindow(combo
->hWndLBox
, SW_HIDE
);
1427 if (redraw
&& !(combo
->wState
& CBF_NOREDRAW
))
1428 RedrawWindow(combo
->self
, NULL
, 0, RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
);
1432 /***********************************************************************
1435 static void COMBO_Size( HEADCOMBO
*lphc
)
1437 if (!lphc
->hWndLBox
|| (lphc
->wState
& CBF_NORESIZE
))
1441 * Those controls are always the same height. So we have to make sure
1442 * they are not resized to another value.
1444 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
1446 int newComboHeight
, curComboHeight
, curComboWidth
;
1449 GetWindowRect(lphc
->self
, &rc
);
1450 curComboHeight
= rc
.bottom
- rc
.top
;
1451 curComboWidth
= rc
.right
- rc
.left
;
1452 newComboHeight
= CBGetTextAreaHeight(lphc
, TRUE
) + 2*COMBO_YBORDERSIZE();
1455 * Resizing a combobox has another side effect, it resizes the dropped
1456 * rectangle as well. However, it does it only if the new height for the
1457 * combobox is more than the height it should have. In other words,
1458 * if the application resizing the combobox only had the intention to resize
1459 * the actual control, for example, to do the layout of a dialog that is
1460 * resized, the height of the dropdown is not changed.
1462 if( curComboHeight
> newComboHeight
)
1464 TRACE("oldComboHeight=%d, newComboHeight=%d, oldDropBottom=%d, oldDropTop=%d\n",
1465 curComboHeight
, newComboHeight
, lphc
->droppedRect
.bottom
,
1466 lphc
->droppedRect
.top
);
1467 lphc
->droppedRect
.bottom
= lphc
->droppedRect
.top
+ curComboHeight
- newComboHeight
;
1470 * Restore original height
1472 if (curComboHeight
!= newComboHeight
)
1474 lphc
->wState
|= CBF_NORESIZE
;
1475 SetWindowPos(lphc
->self
, 0, 0, 0, curComboWidth
, newComboHeight
,
1476 SWP_NOZORDER
| SWP_NOMOVE
| SWP_NOACTIVATE
| SWP_NOREDRAW
);
1477 lphc
->wState
&= ~CBF_NORESIZE
;
1481 CBCalcPlacement(lphc
);
1483 CBResetPos(lphc
, FALSE
);
1487 /***********************************************************************
1490 static void COMBO_Font( LPHEADCOMBO lphc
, HFONT hFont
, BOOL bRedraw
)
1492 lphc
->hFont
= hFont
;
1493 lphc
->item_height
= combo_get_text_height(lphc
);
1496 * Propagate to owned windows.
1498 if( lphc
->wState
& CBF_EDIT
)
1499 SendMessageW(lphc
->hWndEdit
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1500 SendMessageW(lphc
->hWndLBox
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1503 * Redo the layout of the control.
1505 if ( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
1507 CBCalcPlacement(lphc
);
1509 CBResetPos(lphc
, TRUE
);
1513 CBForceDummyResize(lphc
);
1518 /***********************************************************************
1519 * COMBO_SetItemHeight
1521 static LRESULT
COMBO_SetItemHeight( LPHEADCOMBO lphc
, INT index
, INT height
)
1523 LRESULT lRet
= CB_ERR
;
1525 if( index
== -1 ) /* set text field height */
1527 if( height
< 32768 )
1529 lphc
->item_height
= height
+ 2; /* Is the 2 for 2*EDIT_CONTROL_PADDING? */
1532 * Redo the layout of the control.
1534 if ( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
1536 CBCalcPlacement(lphc
);
1538 CBResetPos(lphc
, TRUE
);
1542 CBForceDummyResize(lphc
);
1548 else if ( CB_OWNERDRAWN(lphc
) ) /* set listbox item height */
1549 lRet
= SendMessageW(lphc
->hWndLBox
, LB_SETITEMHEIGHT
, index
, height
);
1553 /***********************************************************************
1554 * COMBO_SelectString
1556 static LRESULT
COMBO_SelectString( LPHEADCOMBO lphc
, INT start
, LPARAM pText
, BOOL unicode
)
1558 INT index
= unicode
? SendMessageW(lphc
->hWndLBox
, LB_SELECTSTRING
, start
, pText
) :
1559 SendMessageA(lphc
->hWndLBox
, LB_SELECTSTRING
, start
, pText
);
1562 if( lphc
->wState
& CBF_EDIT
)
1563 CBUpdateEdit( lphc
, index
);
1566 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1569 return (LRESULT
)index
;
1572 /***********************************************************************
1575 static void COMBO_LButtonDown( LPHEADCOMBO lphc
, LPARAM lParam
)
1579 HWND hWnd
= lphc
->self
;
1581 pt
.x
= (short)LOWORD(lParam
);
1582 pt
.y
= (short)HIWORD(lParam
);
1583 bButton
= PtInRect(&lphc
->buttonRect
, pt
);
1585 if( (CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
) ||
1586 (bButton
&& (CB_GETTYPE(lphc
) == CBS_DROPDOWN
)) )
1588 lphc
->wState
|= CBF_BUTTONDOWN
;
1589 if( lphc
->wState
& CBF_DROPPED
)
1591 /* got a click to cancel selection */
1593 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1594 CBRollUp( lphc
, TRUE
, FALSE
);
1595 if( !IsWindow( hWnd
) ) return;
1597 if( lphc
->wState
& CBF_CAPTURE
)
1599 lphc
->wState
&= ~CBF_CAPTURE
;
1605 /* drop down the listbox and start tracking */
1607 lphc
->wState
|= CBF_CAPTURE
;
1611 if( bButton
) CBRepaintButton( lphc
);
1615 /***********************************************************************
1618 * Release capture and stop tracking if needed.
1620 static void COMBO_LButtonUp( LPHEADCOMBO lphc
)
1622 if( lphc
->wState
& CBF_CAPTURE
)
1624 lphc
->wState
&= ~CBF_CAPTURE
;
1625 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1627 INT index
= CBUpdateLBox( lphc
, TRUE
);
1628 /* Update edit only if item is in the list */
1631 lphc
->wState
|= CBF_NOLBSELECT
;
1632 CBUpdateEdit( lphc
, index
);
1633 lphc
->wState
&= ~CBF_NOLBSELECT
;
1637 SetCapture(lphc
->hWndLBox
);
1640 if( lphc
->wState
& CBF_BUTTONDOWN
)
1642 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1643 CBRepaintButton( lphc
);
1647 /***********************************************************************
1650 * Two things to do - track combo button and release capture when
1651 * pointer goes into the listbox.
1653 static void COMBO_MouseMove( LPHEADCOMBO lphc
, WPARAM wParam
, LPARAM lParam
)
1658 pt
.x
= (short)LOWORD(lParam
);
1659 pt
.y
= (short)HIWORD(lParam
);
1661 if( lphc
->wState
& CBF_BUTTONDOWN
)
1665 bButton
= PtInRect(&lphc
->buttonRect
, pt
);
1669 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1670 CBRepaintButton( lphc
);
1674 GetClientRect( lphc
->hWndLBox
, &lbRect
);
1675 MapWindowPoints( lphc
->self
, lphc
->hWndLBox
, &pt
, 1 );
1676 if( PtInRect(&lbRect
, pt
) )
1678 lphc
->wState
&= ~CBF_CAPTURE
;
1680 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
) CBUpdateLBox( lphc
, TRUE
);
1682 /* hand over pointer tracking */
1683 SendMessageW(lphc
->hWndLBox
, WM_LBUTTONDOWN
, wParam
, lParam
);
1687 static LRESULT
COMBO_GetComboBoxInfo(const HEADCOMBO
*lphc
, COMBOBOXINFO
*pcbi
)
1689 if (!pcbi
|| (pcbi
->cbSize
< sizeof(COMBOBOXINFO
)))
1692 pcbi
->rcItem
= lphc
->textRect
;
1693 pcbi
->rcButton
= lphc
->buttonRect
;
1694 pcbi
->stateButton
= 0;
1695 if (lphc
->wState
& CBF_BUTTONDOWN
)
1696 pcbi
->stateButton
|= STATE_SYSTEM_PRESSED
;
1697 if (IsRectEmpty(&lphc
->buttonRect
))
1698 pcbi
->stateButton
|= STATE_SYSTEM_INVISIBLE
;
1699 pcbi
->hwndCombo
= lphc
->self
;
1700 pcbi
->hwndItem
= lphc
->hWndEdit
;
1701 pcbi
->hwndList
= lphc
->hWndLBox
;
1705 static char *strdupA(LPCSTR str
)
1710 if(!str
) return NULL
;
1713 ret
= HeapAlloc(GetProcessHeap(), 0, len
+ 1);
1714 memcpy(ret
, str
, len
+ 1);
1718 /***********************************************************************
1719 * ComboWndProc_common
1721 LRESULT
ComboWndProc_common( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL unicode
)
1723 LPHEADCOMBO lphc
= (LPHEADCOMBO
)GetWindowLongPtrW( hwnd
, 0 );
1725 TRACE("[%p]: msg %s wp %08lx lp %08lx\n",
1726 hwnd
, SPY_GetMsgName(message
, hwnd
), wParam
, lParam
);
1728 if (!IsWindow(hwnd
)) return 0;
1730 if( lphc
|| message
== WM_NCCREATE
)
1734 /* System messages */
1738 LONG style
= unicode
? ((LPCREATESTRUCTW
)lParam
)->style
:
1739 ((LPCREATESTRUCTA
)lParam
)->style
;
1740 return COMBO_NCCreate(hwnd
, style
);
1743 COMBO_NCDestroy(lphc
);
1744 break;/* -> DefWindowProc */
1752 hwndParent
= ((LPCREATESTRUCTW
)lParam
)->hwndParent
;
1753 style
= ((LPCREATESTRUCTW
)lParam
)->style
;
1757 hwndParent
= ((LPCREATESTRUCTA
)lParam
)->hwndParent
;
1758 style
= ((LPCREATESTRUCTA
)lParam
)->style
;
1760 return COMBO_Create(hwnd
, lphc
, hwndParent
, style
, unicode
);
1763 case WM_PRINTCLIENT
:
1766 /* wParam may contain a valid HDC! */
1767 return COMBO_Paint(lphc
, (HDC
)wParam
);
1770 /* do all painting in WM_PAINT like Windows does */
1775 LRESULT result
= DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1776 if (lParam
&& (((LPMSG
)lParam
)->message
== WM_KEYDOWN
))
1778 int vk
= (int)((LPMSG
)lParam
)->wParam
;
1780 if ((vk
== VK_RETURN
|| vk
== VK_ESCAPE
) && (lphc
->wState
& CBF_DROPPED
))
1781 result
|= DLGC_WANTMESSAGE
;
1789 COMBO_Font( lphc
, (HFONT
)wParam
, (BOOL
)lParam
);
1792 return (LRESULT
)lphc
->hFont
;
1794 if( lphc
->wState
& CBF_EDIT
) {
1795 SetFocus( lphc
->hWndEdit
);
1796 /* The first time focus is received, select all the text */
1797 if( !(lphc
->wState
& CBF_BEENFOCUSED
) ) {
1798 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, -1);
1799 lphc
->wState
|= CBF_BEENFOCUSED
;
1803 COMBO_SetFocus( lphc
);
1807 HWND hwndFocus
= WIN_GetFullHandle( (HWND
)wParam
);
1809 (hwndFocus
!= lphc
->hWndEdit
&& hwndFocus
!= lphc
->hWndLBox
))
1810 COMBO_KillFocus( lphc
);
1814 return COMBO_Command( lphc
, wParam
, WIN_GetFullHandle( (HWND
)lParam
) );
1816 return unicode
? COMBO_GetTextW( lphc
, wParam
, (LPWSTR
)lParam
)
1817 : COMBO_GetTextA( lphc
, wParam
, (LPSTR
)lParam
);
1819 case WM_GETTEXTLENGTH
:
1821 if ((message
== WM_GETTEXTLENGTH
) && !ISWIN31
&& !(lphc
->wState
& CBF_EDIT
))
1823 int j
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1824 if (j
== -1) return 0;
1825 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, j
, 0) :
1826 SendMessageA(lphc
->hWndLBox
, LB_GETTEXTLEN
, j
, 0);
1828 else if( lphc
->wState
& CBF_EDIT
)
1831 lphc
->wState
|= CBF_NOEDITNOTIFY
;
1832 ret
= unicode
? SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
) :
1833 SendMessageA(lphc
->hWndEdit
, message
, wParam
, lParam
);
1834 lphc
->wState
&= ~CBF_NOEDITNOTIFY
;
1841 if( lphc
->wState
& CBF_EDIT
)
1843 return unicode
? SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
) :
1844 SendMessageA(lphc
->hWndEdit
, message
, wParam
, lParam
);
1850 case WM_COMPAREITEM
:
1851 case WM_MEASUREITEM
:
1852 return COMBO_ItemOp(lphc
, message
, lParam
);
1854 if( lphc
->wState
& CBF_EDIT
)
1855 EnableWindow( lphc
->hWndEdit
, (BOOL
)wParam
);
1856 EnableWindow( lphc
->hWndLBox
, (BOOL
)wParam
);
1858 /* Force the control to repaint when the enabled state changes. */
1859 InvalidateRect(lphc
->self
, NULL
, TRUE
);
1863 lphc
->wState
&= ~CBF_NOREDRAW
;
1865 lphc
->wState
|= CBF_NOREDRAW
;
1867 if( lphc
->wState
& CBF_EDIT
)
1868 SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
);
1869 SendMessageW(lphc
->hWndLBox
, message
, wParam
, lParam
);
1872 if( KEYDATA_ALT
& HIWORD(lParam
) )
1873 if( wParam
== VK_UP
|| wParam
== VK_DOWN
)
1874 COMBO_FlipListbox( lphc
, FALSE
, FALSE
);
1878 if ((wParam
== VK_RETURN
|| wParam
== VK_ESCAPE
) &&
1879 (lphc
->wState
& CBF_DROPPED
))
1881 CBRollUp( lphc
, wParam
== VK_RETURN
, FALSE
);
1884 else if ((wParam
== VK_F4
) && !(lphc
->wState
& CBF_EUI
))
1886 COMBO_FlipListbox( lphc
, FALSE
, FALSE
);
1895 if( lphc
->wState
& CBF_EDIT
)
1896 hwndTarget
= lphc
->hWndEdit
;
1898 hwndTarget
= lphc
->hWndLBox
;
1900 return unicode
? SendMessageW(hwndTarget
, message
, wParam
, lParam
) :
1901 SendMessageA(hwndTarget
, message
, wParam
, lParam
);
1903 case WM_LBUTTONDOWN
:
1904 if( !(lphc
->wState
& CBF_FOCUSED
) ) SetFocus( lphc
->self
);
1905 if( lphc
->wState
& CBF_FOCUSED
) COMBO_LButtonDown( lphc
, lParam
);
1908 COMBO_LButtonUp( lphc
);
1911 if( lphc
->wState
& CBF_CAPTURE
)
1912 COMBO_MouseMove( lphc
, wParam
, lParam
);
1916 if (wParam
& (MK_SHIFT
| MK_CONTROL
))
1917 return unicode
? DefWindowProcW(hwnd
, message
, wParam
, lParam
) :
1918 DefWindowProcA(hwnd
, message
, wParam
, lParam
);
1920 if (GET_WHEEL_DELTA_WPARAM(wParam
) > 0) return SendMessageW(hwnd
, WM_KEYDOWN
, VK_UP
, 0);
1921 if (GET_WHEEL_DELTA_WPARAM(wParam
) < 0) return SendMessageW(hwnd
, WM_KEYDOWN
, VK_DOWN
, 0);
1925 case WM_CTLCOLORMSGBOX
:
1926 case WM_CTLCOLOREDIT
:
1927 case WM_CTLCOLORLISTBOX
:
1928 case WM_CTLCOLORBTN
:
1929 case WM_CTLCOLORDLG
:
1930 case WM_CTLCOLORSCROLLBAR
:
1931 case WM_CTLCOLORSTATIC
:
1933 return SendMessageW(lphc
->owner
, message
, wParam
, lParam
);
1936 /* Combo messages */
1941 if( lphc
->dwStyle
& CBS_LOWERCASE
)
1942 CharLowerW((LPWSTR
)lParam
);
1943 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
1944 CharUpperW((LPWSTR
)lParam
);
1945 return SendMessageW(lphc
->hWndLBox
, LB_ADDSTRING
, 0, lParam
);
1947 else /* unlike the unicode version, the ansi version does not overwrite
1948 the string if converting case */
1950 char *string
= NULL
;
1952 if( lphc
->dwStyle
& CBS_LOWERCASE
)
1954 string
= strdupA((LPSTR
)lParam
);
1958 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
1960 string
= strdupA((LPSTR
)lParam
);
1964 ret
= SendMessageA(lphc
->hWndLBox
, LB_ADDSTRING
, 0, string
? (LPARAM
)string
: lParam
);
1965 HeapFree(GetProcessHeap(), 0, string
);
1968 case CB_INSERTSTRING
:
1971 if( lphc
->dwStyle
& CBS_LOWERCASE
)
1972 CharLowerW((LPWSTR
)lParam
);
1973 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
1974 CharUpperW((LPWSTR
)lParam
);
1975 return SendMessageW(lphc
->hWndLBox
, LB_INSERTSTRING
, wParam
, lParam
);
1979 if( lphc
->dwStyle
& CBS_LOWERCASE
)
1980 CharLowerA((LPSTR
)lParam
);
1981 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
1982 CharUpperA((LPSTR
)lParam
);
1984 return SendMessageA(lphc
->hWndLBox
, LB_INSERTSTRING
, wParam
, lParam
);
1986 case CB_DELETESTRING
:
1987 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_DELETESTRING
, wParam
, 0) :
1988 SendMessageA(lphc
->hWndLBox
, LB_DELETESTRING
, wParam
, 0);
1989 case CB_SELECTSTRING
:
1990 return COMBO_SelectString(lphc
, (INT
)wParam
, lParam
, unicode
);
1992 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_FINDSTRING
, wParam
, lParam
) :
1993 SendMessageA(lphc
->hWndLBox
, LB_FINDSTRING
, wParam
, lParam
);
1994 case CB_FINDSTRINGEXACT
:
1995 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_FINDSTRINGEXACT
, wParam
, lParam
) :
1996 SendMessageA(lphc
->hWndLBox
, LB_FINDSTRINGEXACT
, wParam
, lParam
);
1997 case CB_SETITEMHEIGHT
:
1998 return COMBO_SetItemHeight( lphc
, (INT
)wParam
, (INT
)lParam
);
1999 case CB_GETITEMHEIGHT
:
2000 if( (INT
)wParam
>= 0 ) /* listbox item */
2001 return SendMessageW(lphc
->hWndLBox
, LB_GETITEMHEIGHT
, wParam
, 0);
2002 return CBGetTextAreaHeight(lphc
, FALSE
);
2003 case CB_RESETCONTENT
:
2004 SendMessageW(lphc
->hWndLBox
, LB_RESETCONTENT
, 0, 0);
2005 if( (lphc
->wState
& CBF_EDIT
) && CB_HASSTRINGS(lphc
) )
2006 SendMessageW(lphc
->hWndEdit
, WM_SETTEXT
, 0, (LPARAM
)L
"");
2008 InvalidateRect(lphc
->self
, NULL
, TRUE
);
2010 case CB_INITSTORAGE
:
2011 return SendMessageW(lphc
->hWndLBox
, LB_INITSTORAGE
, wParam
, lParam
);
2012 case CB_GETHORIZONTALEXTENT
:
2013 return SendMessageW(lphc
->hWndLBox
, LB_GETHORIZONTALEXTENT
, 0, 0);
2014 case CB_SETHORIZONTALEXTENT
:
2015 return SendMessageW(lphc
->hWndLBox
, LB_SETHORIZONTALEXTENT
, wParam
, 0);
2016 case CB_GETTOPINDEX
:
2017 return SendMessageW(lphc
->hWndLBox
, LB_GETTOPINDEX
, 0, 0);
2019 return SendMessageW(lphc
->hWndLBox
, LB_GETLOCALE
, 0, 0);
2021 return SendMessageW(lphc
->hWndLBox
, LB_SETLOCALE
, wParam
, 0);
2022 case CB_SETDROPPEDWIDTH
:
2023 if( (CB_GETTYPE(lphc
) == CBS_SIMPLE
) ||
2024 (INT
)wParam
>= 32768 )
2026 /* new value must be higher than combobox width */
2027 if((INT
)wParam
>= lphc
->droppedRect
.right
- lphc
->droppedRect
.left
)
2028 lphc
->droppedWidth
= wParam
;
2030 lphc
->droppedWidth
= 0;
2032 /* recalculate the combobox area */
2033 CBCalcPlacement(lphc
);
2036 case CB_GETDROPPEDWIDTH
:
2037 if( lphc
->droppedWidth
)
2038 return lphc
->droppedWidth
;
2039 return lphc
->droppedRect
.right
- lphc
->droppedRect
.left
;
2040 case CB_GETDROPPEDCONTROLRECT
:
2041 if( lParam
) CBGetDroppedControlRect(lphc
, (LPRECT
)lParam
);
2043 case CB_GETDROPPEDSTATE
:
2044 return (lphc
->wState
& CBF_DROPPED
) != 0;
2046 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_DIR
, wParam
, lParam
) :
2047 SendMessageA(lphc
->hWndLBox
, LB_DIR
, wParam
, lParam
);
2049 case CB_SHOWDROPDOWN
:
2050 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
2054 if( !(lphc
->wState
& CBF_DROPPED
) )
2058 if( lphc
->wState
& CBF_DROPPED
)
2059 CBRollUp( lphc
, FALSE
, TRUE
);
2063 return SendMessageW(lphc
->hWndLBox
, LB_GETCOUNT
, 0, 0);
2065 return SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
2067 lParam
= SendMessageW(lphc
->hWndLBox
, LB_SETCURSEL
, wParam
, 0);
2069 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
, wParam
, 0);
2071 /* no LBN_SELCHANGE in this case, update manually */
2072 CBPaintText( lphc
, NULL
);
2073 lphc
->wState
&= ~CBF_SELCHANGE
;
2076 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, wParam
, lParam
) :
2077 SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, wParam
, lParam
);
2078 case CB_GETLBTEXTLEN
:
2079 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, wParam
, 0) :
2080 SendMessageA(lphc
->hWndLBox
, LB_GETTEXTLEN
, wParam
, 0);
2081 case CB_GETITEMDATA
:
2082 return SendMessageW(lphc
->hWndLBox
, LB_GETITEMDATA
, wParam
, 0);
2083 case CB_SETITEMDATA
:
2084 return SendMessageW(lphc
->hWndLBox
, LB_SETITEMDATA
, wParam
, lParam
);
2086 /* Edit checks passed parameters itself */
2087 if( lphc
->wState
& CBF_EDIT
)
2088 return SendMessageW(lphc
->hWndEdit
, EM_GETSEL
, wParam
, lParam
);
2091 if( lphc
->wState
& CBF_EDIT
)
2092 return SendMessageW(lphc
->hWndEdit
, EM_SETSEL
,
2093 (INT
)(SHORT
)LOWORD(lParam
), (INT
)(SHORT
)HIWORD(lParam
) );
2095 case CB_SETEXTENDEDUI
:
2096 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
2099 lphc
->wState
|= CBF_EUI
;
2100 else lphc
->wState
&= ~CBF_EUI
;
2102 case CB_GETEXTENDEDUI
:
2103 return (lphc
->wState
& CBF_EUI
) != 0;
2104 case CB_GETCOMBOBOXINFO
:
2105 return COMBO_GetComboBoxInfo(lphc
, (COMBOBOXINFO
*)lParam
);
2107 if( lphc
->wState
& CBF_EDIT
)
2108 return SendMessageW(lphc
->hWndEdit
, EM_LIMITTEXT
, wParam
, lParam
);
2111 if (message
>= WM_USER
)
2112 WARN("unknown msg WM_USER+%04x wp=%04lx lp=%08lx\n",
2113 message
- WM_USER
, wParam
, lParam
);
2116 return unicode
? DefWindowProcW(hwnd
, message
, wParam
, lParam
) :
2117 DefWindowProcA(hwnd
, message
, wParam
, lParam
);
2120 /*************************************************************************
2121 * GetComboBoxInfo (USER32.@)
2123 BOOL WINAPI
GetComboBoxInfo(HWND hwndCombo
, /* [in] handle to combo box */
2124 PCOMBOBOXINFO pcbi
/* [in/out] combo box information */)
2126 TRACE("(%p, %p)\n", hwndCombo
, pcbi
);
2127 return SendMessageW(hwndCombo
, CB_GETCOMBOBOXINFO
, 0, (LPARAM
)pcbi
);