4 * Copyright 1997 Alex Korobka
6 * FIXME: roll up in Netscape 3.01.
15 #include "wine/winuser16.h"
16 #include "wine/unicode.h"
21 #include "debugtools.h"
23 DEFAULT_DEBUG_CHANNEL(combo
);
25 /* bits in the dwKeyData */
26 #define KEYDATA_ALT 0x2000
27 #define KEYDATA_PREVSTATE 0x4000
30 * Additional combo box definitions
33 #define CB_NOTIFY( lphc, code ) \
34 (SendMessageW((lphc)->owner, WM_COMMAND, \
35 MAKEWPARAM(GetWindowLongA((lphc)->self,GWL_ID), (code)), (LPARAM)(lphc)->self))
37 #define CB_DISABLED( lphc ) (!IsWindowEnabled((lphc)->self))
38 #define CB_OWNERDRAWN( lphc ) ((lphc)->dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE))
39 #define CB_HASSTRINGS( lphc ) ((lphc)->dwStyle & CBS_HASSTRINGS)
40 #define CB_HWND( lphc ) ((lphc)->self)
42 #define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
47 static HBITMAP hComboBmp
= 0;
48 static UINT CBitHeight
, CBitWidth
;
51 * Look and feel dependant "constants"
54 #define COMBO_YBORDERGAP 5
55 #define COMBO_XBORDERSIZE() ( (TWEAK_WineLook == WIN31_LOOK) ? 0 : 2 )
56 #define COMBO_YBORDERSIZE() ( (TWEAK_WineLook == WIN31_LOOK) ? 0 : 2 )
57 #define COMBO_EDITBUTTONSPACE() ( (TWEAK_WineLook == WIN31_LOOK) ? 8 : 0 )
58 #define EDIT_CONTROL_PADDING() ( (TWEAK_WineLook == WIN31_LOOK) ? 0 : 1 )
60 static LRESULT WINAPI
ComboWndProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
61 static LRESULT WINAPI
ComboWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
63 /*********************************************************************
64 * combo class descriptor
66 const struct builtin_class_descr COMBO_builtin_class
=
68 "ComboBox", /* name */
69 CS_GLOBALCLASS
| CS_PARENTDC
| CS_DBLCLKS
, /* style */
70 ComboWndProcA
, /* procA */
71 ComboWndProcW
, /* procW */
72 sizeof(HEADCOMBO
*), /* extra */
73 IDC_ARROWA
, /* cursor */
78 /***********************************************************************
81 * Load combo button bitmap.
83 static BOOL
COMBO_Init()
87 if( hComboBmp
) return TRUE
;
88 if( (hDC
= CreateCompatibleDC(0)) )
91 if( (hComboBmp
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_COMBO
))) )
97 GetObjectW( hComboBmp
, sizeof(bm
), &bm
);
98 CBitHeight
= bm
.bmHeight
;
99 CBitWidth
= bm
.bmWidth
;
101 TRACE("combo bitmap [%i,%i]\n", CBitWidth
, CBitHeight
);
103 hPrevB
= SelectObject( hDC
, hComboBmp
);
104 SetRect( &r
, 0, 0, CBitWidth
, CBitHeight
);
105 InvertRect( hDC
, &r
);
106 SelectObject( hDC
, hPrevB
);
115 /***********************************************************************
118 static LRESULT
COMBO_NCCreate(HWND hwnd
, LONG style
)
122 if (COMBO_Init() && (lphc
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HEADCOMBO
))) )
125 SetWindowLongA( hwnd
, 0, (LONG
)lphc
);
127 /* some braindead apps do try to use scrollbar/border flags */
129 lphc
->dwStyle
= style
& ~(WS_BORDER
| WS_HSCROLL
| WS_VSCROLL
);
130 SetWindowLongA( hwnd
, GWL_STYLE
, style
& ~(WS_BORDER
| WS_HSCROLL
| WS_VSCROLL
) );
133 * We also have to remove the client edge style to make sure
134 * we don't end-up with a non client area.
136 SetWindowLongA( hwnd
, GWL_EXSTYLE
,
137 GetWindowLongA( hwnd
, GWL_EXSTYLE
) & ~WS_EX_CLIENTEDGE
);
139 if( !(style
& (CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
)) )
140 lphc
->dwStyle
|= CBS_HASSTRINGS
;
141 if( !(GetWindowLongA( hwnd
, GWL_EXSTYLE
) & WS_EX_NOPARENTNOTIFY
) )
142 lphc
->wState
|= CBF_NOTIFY
;
144 TRACE("[%p], style = %08x\n", lphc
, lphc
->dwStyle
);
150 /***********************************************************************
153 static LRESULT
COMBO_NCDestroy( LPHEADCOMBO lphc
)
158 TRACE("[%04x]: freeing storage\n", lphc
->self
);
160 if( (CB_GETTYPE(lphc
) != CBS_SIMPLE
) && lphc
->hWndLBox
)
161 DestroyWindow( lphc
->hWndLBox
);
163 SetWindowLongA( lphc
->self
, 0, 0 );
164 HeapFree( GetProcessHeap(), 0, lphc
);
169 /***********************************************************************
170 * CBGetTextAreaHeight
172 * This method will calculate the height of the text area of the
174 * The height of the text area is set in two ways.
175 * It can be set explicitly through a combobox message or through a
176 * WM_MEASUREITEM callback.
177 * If this is not the case, the height is set to 13 dialog units.
178 * This height was determined through experimentation.
180 static INT
CBGetTextAreaHeight(
186 if( lphc
->editHeight
) /* explicitly set height */
188 iTextItemHeight
= lphc
->editHeight
;
193 HDC hDC
= GetDC(hwnd
);
198 hPrevFont
= SelectObject( hDC
, lphc
->hFont
);
200 GetTextMetricsW(hDC
, &tm
);
202 baseUnitY
= tm
.tmHeight
;
205 SelectObject( hDC
, hPrevFont
);
207 ReleaseDC(hwnd
, hDC
);
209 iTextItemHeight
= ((13 * baseUnitY
) / 8);
212 * This "formula" calculates the height of the complete control.
213 * To calculate the height of the text area, we have to remove the
216 iTextItemHeight
-= 2*COMBO_YBORDERSIZE();
220 * Check the ownerdraw case if we haven't asked the parent the size
223 if ( CB_OWNERDRAWN(lphc
) &&
224 (lphc
->wState
& CBF_MEASUREITEM
) )
226 MEASUREITEMSTRUCT measureItem
;
228 INT originalItemHeight
= iTextItemHeight
;
229 UINT id
= GetWindowLongA( lphc
->self
, GWL_ID
);
232 * We use the client rect for the width of the item.
234 GetClientRect(hwnd
, &clientRect
);
236 lphc
->wState
&= ~CBF_MEASUREITEM
;
239 * Send a first one to measure the size of the text area
241 measureItem
.CtlType
= ODT_COMBOBOX
;
242 measureItem
.CtlID
= id
;
243 measureItem
.itemID
= -1;
244 measureItem
.itemWidth
= clientRect
.right
;
245 measureItem
.itemHeight
= iTextItemHeight
- 6; /* ownerdrawn cb is taller */
246 measureItem
.itemData
= 0;
247 SendMessageW(lphc
->owner
, WM_MEASUREITEM
, id
, (LPARAM
)&measureItem
);
248 iTextItemHeight
= 6 + measureItem
.itemHeight
;
251 * Send a second one in the case of a fixed ownerdraw list to calculate the
252 * size of the list items. (we basically do this on behalf of the listbox)
254 if (lphc
->dwStyle
& CBS_OWNERDRAWFIXED
)
256 measureItem
.CtlType
= ODT_COMBOBOX
;
257 measureItem
.CtlID
= id
;
258 measureItem
.itemID
= 0;
259 measureItem
.itemWidth
= clientRect
.right
;
260 measureItem
.itemHeight
= originalItemHeight
;
261 measureItem
.itemData
= 0;
262 SendMessageW(lphc
->owner
, WM_MEASUREITEM
, id
, (LPARAM
)&measureItem
);
263 lphc
->fixedOwnerDrawHeight
= measureItem
.itemHeight
;
267 * Keep the size for the next time
269 lphc
->editHeight
= iTextItemHeight
;
272 return iTextItemHeight
;
275 /***********************************************************************
278 * The dummy resize is used for listboxes that have a popup to trigger
279 * a re-arranging of the contents of the combobox and the recalculation
280 * of the size of the "real" control window.
282 static void CBForceDummyResize(
288 newComboHeight
= CBGetTextAreaHeight(lphc
->self
,lphc
) + 2*COMBO_YBORDERSIZE();
290 GetWindowRect(lphc
->self
, &windowRect
);
293 * We have to be careful, resizing a combobox also has the meaning that the
294 * dropped rect will be resized. In this case, we want to trigger a resize
295 * to recalculate layout but we don't want to change the dropped rectangle
296 * So, we pass the height of text area of control as the height.
297 * this will cancel-out in the processing of the WM_WINDOWPOSCHANGING
300 SetWindowPos( lphc
->self
,
303 windowRect
.right
- windowRect
.left
,
305 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
308 /***********************************************************************
311 * Set up component coordinates given valid lphc->RectCombo.
313 static void CBCalcPlacement(
321 * Again, start with the client rectangle.
323 GetClientRect(hwnd
, lprEdit
);
328 InflateRect(lprEdit
, -COMBO_XBORDERSIZE(), -COMBO_YBORDERSIZE());
331 * Chop off the bottom part to fit with the height of the text area.
333 lprEdit
->bottom
= lprEdit
->top
+ CBGetTextAreaHeight(hwnd
, lphc
);
336 * The button starts the same vertical position as the text area.
338 CopyRect(lprButton
, lprEdit
);
341 * If the combobox is "simple" there is no button.
343 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
344 lprButton
->left
= lprButton
->right
= lprButton
->bottom
= 0;
348 * Let's assume the combobox button is the same width as the
350 * size the button horizontally and cut-off the text area.
352 lprButton
->left
= lprButton
->right
- GetSystemMetrics(SM_CXVSCROLL
);
353 lprEdit
->right
= lprButton
->left
;
357 * In the case of a dropdown, there is an additional spacing between the
358 * text area and the button.
360 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
362 lprEdit
->right
-= COMBO_EDITBUTTONSPACE();
366 * If we have an edit control, we space it away from the borders slightly.
368 if (CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
)
370 InflateRect(lprEdit
, -EDIT_CONTROL_PADDING(), -EDIT_CONTROL_PADDING());
374 * Adjust the size of the listbox popup.
376 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
379 * Use the client rectangle to initialize the listbox rectangle
381 GetClientRect(hwnd
, lprLB
);
384 * Then, chop-off the top part.
386 lprLB
->top
= lprEdit
->bottom
+ COMBO_YBORDERSIZE();
391 * Make sure the dropped width is as large as the combobox itself.
393 if (lphc
->droppedWidth
< (lprButton
->right
+ COMBO_XBORDERSIZE()))
395 lprLB
->right
= lprLB
->left
+ (lprButton
->right
+ COMBO_XBORDERSIZE());
398 * In the case of a dropdown, the popup listbox is offset to the right.
399 * so, we want to make sure it's flush with the right side of the
402 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
403 lprLB
->right
-= COMBO_EDITBUTTONSPACE();
406 lprLB
->right
= lprLB
->left
+ lphc
->droppedWidth
;
409 TRACE("\ttext\t= (%i,%i-%i,%i)\n",
410 lprEdit
->left
, lprEdit
->top
, lprEdit
->right
, lprEdit
->bottom
);
412 TRACE("\tbutton\t= (%i,%i-%i,%i)\n",
413 lprButton
->left
, lprButton
->top
, lprButton
->right
, lprButton
->bottom
);
415 TRACE("\tlbox\t= (%i,%i-%i,%i)\n",
416 lprLB
->left
, lprLB
->top
, lprLB
->right
, lprLB
->bottom
);
419 /***********************************************************************
420 * CBGetDroppedControlRect
422 static void CBGetDroppedControlRect( LPHEADCOMBO lphc
, LPRECT lpRect
)
424 /* In windows, CB_GETDROPPEDCONTROLRECT returns the upper left corner
425 of the combo box and the lower right corner of the listbox */
427 GetWindowRect(lphc
->self
, lpRect
);
429 lpRect
->right
= lpRect
->left
+ lphc
->droppedRect
.right
- lphc
->droppedRect
.left
;
430 lpRect
->bottom
= lpRect
->top
+ lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
;
434 /***********************************************************************
435 * COMBO_WindowPosChanging
437 static LRESULT
COMBO_WindowPosChanging(
440 WINDOWPOS
* posChanging
)
443 * We need to override the WM_WINDOWPOSCHANGING method to handle all
444 * the non-simple comboboxes. The problem is that those controls are
445 * always the same height. We have to make sure they are not resized
448 if ( ( CB_GETTYPE(lphc
) != CBS_SIMPLE
) &&
449 ((posChanging
->flags
& SWP_NOSIZE
) == 0) )
453 newComboHeight
= CBGetTextAreaHeight(hwnd
,lphc
) +
454 2*COMBO_YBORDERSIZE();
457 * Resizing a combobox has another side effect, it resizes the dropped
458 * rectangle as well. However, it does it only if the new height for the
459 * combobox is different from the height it should have. In other words,
460 * if the application resizing the combobox only had the intention to resize
461 * the actual control, for example, to do the layout of a dialog that is
462 * resized, the height of the dropdown is not changed.
464 if (posChanging
->cy
!= newComboHeight
)
466 TRACE("posChanging->cy=%d, newComboHeight=%d, oldbot=%d, oldtop=%d\n",
467 posChanging
->cy
, newComboHeight
, lphc
->droppedRect
.bottom
,
468 lphc
->droppedRect
.top
);
469 lphc
->droppedRect
.bottom
= lphc
->droppedRect
.top
+ posChanging
->cy
- newComboHeight
;
471 posChanging
->cy
= newComboHeight
;
478 /***********************************************************************
481 static LRESULT
COMBO_Create( HWND hwnd
, LPHEADCOMBO lphc
, HWND hwndParent
, LONG style
)
483 static const WCHAR clbName
[] = {'C','o','m','b','o','L','B','o','x',0};
484 static const WCHAR editName
[] = {'E','d','i','t',0};
486 if( !CB_GETTYPE(lphc
) ) lphc
->dwStyle
|= CBS_SIMPLE
;
487 if( CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
) lphc
->wState
|= CBF_EDIT
;
489 lphc
->owner
= hwndParent
;
492 * The item height and dropped width are not set when the control
495 lphc
->droppedWidth
= lphc
->editHeight
= 0;
498 * The first time we go through, we want to measure the ownerdraw item
500 lphc
->wState
|= CBF_MEASUREITEM
;
502 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
504 if( lphc
->owner
|| !(style
& WS_VISIBLE
) )
510 * Initialize the dropped rect to the size of the client area of the
511 * control and then, force all the areas of the combobox to be
514 GetClientRect( hwnd
, &lphc
->droppedRect
);
515 CBCalcPlacement(hwnd
, lphc
, &lphc
->textRect
, &lphc
->buttonRect
, &lphc
->droppedRect
);
518 * Adjust the position of the popup listbox if it's necessary
520 if ( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
522 lphc
->droppedRect
.top
= lphc
->textRect
.bottom
+ COMBO_YBORDERSIZE();
525 * If it's a dropdown, the listbox is offset
527 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
528 lphc
->droppedRect
.left
+= COMBO_EDITBUTTONSPACE();
530 ClientToScreen(hwnd
, (LPPOINT
)&lphc
->droppedRect
);
531 ClientToScreen(hwnd
, (LPPOINT
)&lphc
->droppedRect
.right
);
534 /* create listbox popup */
536 lbeStyle
= (LBS_NOTIFY
| WS_BORDER
| WS_CLIPSIBLINGS
| WS_CHILD
) |
537 (style
& (WS_VSCROLL
| CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
));
539 if( lphc
->dwStyle
& CBS_SORT
)
540 lbeStyle
|= LBS_SORT
;
541 if( lphc
->dwStyle
& CBS_HASSTRINGS
)
542 lbeStyle
|= LBS_HASSTRINGS
;
543 if( lphc
->dwStyle
& CBS_NOINTEGRALHEIGHT
)
544 lbeStyle
|= LBS_NOINTEGRALHEIGHT
;
545 if( lphc
->dwStyle
& CBS_DISABLENOSCROLL
)
546 lbeStyle
|= LBS_DISABLENOSCROLL
;
548 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
) /* child listbox */
550 lbeStyle
|= WS_VISIBLE
;
553 * In win 95 look n feel, the listbox in the simple combobox has
554 * the WS_EXCLIENTEDGE style instead of the WS_BORDER style.
556 if (TWEAK_WineLook
> WIN31_LOOK
)
558 lbeStyle
&= ~WS_BORDER
;
559 lbeExStyle
|= WS_EX_CLIENTEDGE
;
563 lphc
->hWndLBox
= CreateWindowExW(lbeExStyle
,
567 lphc
->droppedRect
.left
,
568 lphc
->droppedRect
.top
,
569 lphc
->droppedRect
.right
- lphc
->droppedRect
.left
,
570 lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
,
571 hwnd
, (HMENU
)ID_CB_LISTBOX
,
572 GetWindowLongA( hwnd
, GWL_HINSTANCE
), lphc
);
577 lbeStyle
= WS_CHILD
| WS_VISIBLE
| ES_NOHIDESEL
| ES_LEFT
| ES_COMBO
;
580 * In Win95 look, the border fo the edit control is
581 * provided by the combobox
583 if (TWEAK_WineLook
== WIN31_LOOK
)
584 lbeStyle
|= WS_BORDER
;
586 if( lphc
->wState
& CBF_EDIT
)
588 if( lphc
->dwStyle
& CBS_OEMCONVERT
)
589 lbeStyle
|= ES_OEMCONVERT
;
590 if( lphc
->dwStyle
& CBS_AUTOHSCROLL
)
591 lbeStyle
|= ES_AUTOHSCROLL
;
592 if( lphc
->dwStyle
& CBS_LOWERCASE
)
593 lbeStyle
|= ES_LOWERCASE
;
594 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
595 lbeStyle
|= ES_UPPERCASE
;
597 if (!IsWindowEnabled(hwnd
)) lbeStyle
|= WS_DISABLED
;
599 lphc
->hWndEdit
= CreateWindowExW(0,
603 lphc
->textRect
.left
, lphc
->textRect
.top
,
604 lphc
->textRect
.right
- lphc
->textRect
.left
,
605 lphc
->textRect
.bottom
- lphc
->textRect
.top
,
606 hwnd
, (HMENU
)ID_CB_EDIT
,
607 GetWindowLongA( hwnd
, GWL_HINSTANCE
), NULL
);
609 if( !lphc
->hWndEdit
)
615 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
617 /* Now do the trick with parent */
618 SetParent(lphc
->hWndLBox
, HWND_DESKTOP
);
620 * If the combo is a dropdown, we must resize the control
621 * to fit only the text area and button. To do this,
622 * we send a dummy resize and the WM_WINDOWPOSCHANGING message
623 * will take care of setting the height for us.
625 CBForceDummyResize(lphc
);
628 TRACE("init done\n");
631 ERR("edit control failure.\n");
632 } else ERR("listbox failure.\n");
633 } else ERR("no owner for visible combo.\n");
635 /* CreateWindow() will send WM_NCDESTROY to cleanup */
640 /***********************************************************************
643 * Paint combo button (normal, pressed, and disabled states).
645 static void CBPaintButton(
650 if( lphc
->wState
& CBF_NOREDRAW
)
653 if (TWEAK_WineLook
== WIN31_LOOK
)
659 COLORREF oldTextColor
, oldBkColor
;
662 hPrevBrush
= SelectObject(hdc
, GetSysColorBrush(COLOR_BTNFACE
));
665 * Draw the button background
670 rectButton
.right
-rectButton
.left
,
671 rectButton
.bottom
-rectButton
.top
,
674 if( (bBool
= lphc
->wState
& CBF_BUTTONDOWN
) )
676 DrawEdge( hdc
, &rectButton
, EDGE_SUNKEN
, BF_RECT
);
680 DrawEdge( hdc
, &rectButton
, EDGE_RAISED
, BF_RECT
);
684 * Remove the edge of the button from the rectangle
685 * and calculate the position of the bitmap.
687 InflateRect( &rectButton
, -2, -2);
689 x
= (rectButton
.left
+ rectButton
.right
- CBitWidth
) >> 1;
690 y
= (rectButton
.top
+ rectButton
.bottom
- CBitHeight
) >> 1;
693 hMemDC
= CreateCompatibleDC( hdc
);
694 SelectObject( hMemDC
, hComboBmp
);
695 oldTextColor
= SetTextColor( hdc
, GetSysColor(COLOR_BTNFACE
) );
696 oldBkColor
= SetBkColor( hdc
, CB_DISABLED(lphc
) ? RGB(128,128,128) :
698 BitBlt( hdc
, x
, y
, CBitWidth
, CBitHeight
, hMemDC
, 0, 0, SRCCOPY
);
699 SetBkColor( hdc
, oldBkColor
);
700 SetTextColor( hdc
, oldTextColor
);
702 SelectObject( hdc
, hPrevBrush
);
706 UINT buttonState
= DFCS_SCROLLCOMBOBOX
;
708 if (lphc
->wState
& CBF_BUTTONDOWN
)
710 buttonState
|= DFCS_PUSHED
;
713 if (CB_DISABLED(lphc
))
715 buttonState
|= DFCS_INACTIVE
;
718 DrawFrameControl(hdc
,
725 /***********************************************************************
728 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
730 static void CBPaintText(
738 if( lphc
->wState
& CBF_NOREDRAW
) return;
742 /* follow Windows combobox that sends a bunch of text
743 * inquiries to its listbox while processing WM_PAINT. */
745 if( (id
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0) ) != LB_ERR
)
747 size
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, id
, 0);
748 if( (pText
= HeapAlloc( GetProcessHeap(), 0, (size
+ 1) * sizeof(WCHAR
))) )
750 /* size from LB_GETTEXTLEN may be too large, from LB_GETTEXT is accurate */
751 size
=SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, (WPARAM
)id
, (LPARAM
)pText
);
752 pText
[size
] = '\0'; /* just in case */
756 if( !CB_OWNERDRAWN(lphc
) )
759 if( lphc
->wState
& CBF_EDIT
)
761 static const WCHAR empty_stringW
[] = { 0 };
762 if( CB_HASSTRINGS(lphc
) ) SetWindowTextW( lphc
->hWndEdit
, pText
? pText
: empty_stringW
);
763 if( lphc
->wState
& CBF_FOCUSED
)
764 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1));
766 else /* paint text field ourselves */
768 UINT itemState
= ODS_COMBOBOXEDIT
;
769 HFONT hPrevFont
= (lphc
->hFont
) ? SelectObject(hdc
, lphc
->hFont
) : 0;
772 * Give ourselves some space.
774 InflateRect( &rectEdit
, -1, -1 );
776 if( CB_OWNERDRAWN(lphc
) )
780 UINT ctlid
= GetWindowLongA( lphc
->self
, GWL_ID
);
782 /* setup state for DRAWITEM message. Owner will highlight */
783 if ( (lphc
->wState
& CBF_FOCUSED
) &&
784 !(lphc
->wState
& CBF_DROPPED
) )
785 itemState
|= ODS_SELECTED
| ODS_FOCUS
;
788 * Save the current clip region.
789 * To retrieve the clip region, we need to create one "dummy"
792 clipRegion
= CreateRectRgnIndirect(&rectEdit
);
794 if (GetClipRgn(hdc
, clipRegion
)!=1)
796 DeleteObject(clipRegion
);
797 clipRegion
=(HRGN
)NULL
;
800 if (!IsWindowEnabled(lphc
->self
) & WS_DISABLED
) itemState
|= ODS_DISABLED
;
802 dis
.CtlType
= ODT_COMBOBOX
;
804 dis
.hwndItem
= lphc
->self
;
805 dis
.itemAction
= ODA_DRAWENTIRE
;
807 dis
.itemState
= itemState
;
809 dis
.rcItem
= rectEdit
;
810 dis
.itemData
= SendMessageW(lphc
->hWndLBox
, LB_GETITEMDATA
,
814 * Clip the DC and have the parent draw the item.
816 IntersectClipRect(hdc
,
817 rectEdit
.left
, rectEdit
.top
,
818 rectEdit
.right
, rectEdit
.bottom
);
820 SendMessageW(lphc
->owner
, WM_DRAWITEM
, ctlid
, (LPARAM
)&dis
);
823 * Reset the clipping region.
825 SelectClipRgn(hdc
, clipRegion
);
829 static const WCHAR empty_stringW
[] = { 0 };
831 if ( (lphc
->wState
& CBF_FOCUSED
) &&
832 !(lphc
->wState
& CBF_DROPPED
) ) {
835 FillRect( hdc
, &rectEdit
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
836 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
837 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
843 ETO_OPAQUE
| ETO_CLIPPED
,
845 pText
? pText
: empty_stringW
, size
, NULL
);
847 if(lphc
->wState
& CBF_FOCUSED
&& !(lphc
->wState
& CBF_DROPPED
))
848 DrawFocusRect( hdc
, &rectEdit
);
852 SelectObject(hdc
, hPrevFont
);
855 HeapFree( GetProcessHeap(), 0, pText
);
858 /***********************************************************************
861 static void CBPaintBorder(
868 if (CB_GETTYPE(lphc
) != CBS_SIMPLE
)
870 GetClientRect(hwnd
, &clientRect
);
874 CopyRect(&clientRect
, &lphc
->textRect
);
876 InflateRect(&clientRect
, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
877 InflateRect(&clientRect
, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
880 DrawEdge(hdc
, &clientRect
, EDGE_SUNKEN
, BF_RECT
);
883 /***********************************************************************
884 * COMBO_PrepareColors
886 * This method will sent the appropriate WM_CTLCOLOR message to
887 * prepare and setup the colors for the combo's DC.
889 * It also returns the brush to use for the background.
891 static HBRUSH
COMBO_PrepareColors(
898 * Get the background brush for this control.
900 if (CB_DISABLED(lphc
))
902 hBkgBrush
= SendMessageW(lphc
->owner
, WM_CTLCOLORSTATIC
, hDC
, (LPARAM
)lphc
->self
);
905 * We have to change the text color since WM_CTLCOLORSTATIC will
906 * set it to the "enabled" color. This is the same behavior as the
909 SetTextColor(hDC
, GetSysColor(COLOR_GRAYTEXT
));
913 if (lphc
->wState
& CBF_EDIT
)
915 hBkgBrush
= SendMessageW(lphc
->owner
, WM_CTLCOLOREDIT
, hDC
, (LPARAM
)lphc
->self
);
919 hBkgBrush
= SendMessageW(lphc
->owner
, WM_CTLCOLORLISTBOX
, hDC
, (LPARAM
)lphc
->self
);
927 hBkgBrush
= GetSysColorBrush(COLOR_WINDOW
);
932 /***********************************************************************
933 * COMBO_EraseBackground
935 static LRESULT
COMBO_EraseBackground(
943 if(lphc
->wState
& CBF_EDIT
)
946 hDC
= (hParamDC
) ? hParamDC
949 * Retrieve the background brush
951 hBkgBrush
= COMBO_PrepareColors(lphc
, hDC
);
953 FillRect(hDC
, &lphc
->textRect
, hBkgBrush
);
956 ReleaseDC(hwnd
, hDC
);
961 /***********************************************************************
964 static LRESULT
COMBO_Paint(LPHEADCOMBO lphc
, HDC hParamDC
)
969 hDC
= (hParamDC
) ? hParamDC
970 : BeginPaint( lphc
->self
, &ps
);
972 TRACE("hdc=%04x\n", hDC
);
974 if( hDC
&& !(lphc
->wState
& CBF_NOREDRAW
) )
976 HBRUSH hPrevBrush
, hBkgBrush
;
979 * Retrieve the background brush and select it in the
982 hBkgBrush
= COMBO_PrepareColors(lphc
, hDC
);
984 hPrevBrush
= SelectObject( hDC
, hBkgBrush
);
987 * In non 3.1 look, there is a sunken border on the combobox
989 if (TWEAK_WineLook
!= WIN31_LOOK
)
991 CBPaintBorder(lphc
->self
, lphc
, hDC
);
994 if( !IsRectEmpty(&lphc
->buttonRect
) )
996 CBPaintButton(lphc
, hDC
, lphc
->buttonRect
);
999 /* paint the edit control padding area */
1000 if (CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
)
1002 RECT rPadEdit
= lphc
->textRect
;
1004 InflateRect(&rPadEdit
, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
1006 FrameRect( hDC
, &rPadEdit
, GetSysColorBrush(COLOR_WINDOW
) );
1009 if( !(lphc
->wState
& CBF_EDIT
) )
1012 * The text area has a border only in Win 3.1 look.
1014 if (TWEAK_WineLook
== WIN31_LOOK
)
1016 HPEN hPrevPen
= SelectObject( hDC
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1019 lphc
->textRect
.left
, lphc
->textRect
.top
,
1020 lphc
->textRect
.right
- 1, lphc
->textRect
.bottom
- 1);
1022 SelectObject( hDC
, hPrevPen
);
1025 CBPaintText( lphc
, hDC
, lphc
->textRect
);
1029 SelectObject( hDC
, hPrevBrush
);
1033 EndPaint(lphc
->self
, &ps
);
1038 /***********************************************************************
1041 * Select listbox entry according to the contents of the edit control.
1043 static INT
CBUpdateLBox( LPHEADCOMBO lphc
, BOOL bSelect
)
1046 LPWSTR pText
= NULL
;
1049 length
= SendMessageW( lphc
->hWndEdit
, WM_GETTEXTLENGTH
, 0, 0 );
1052 pText
= HeapAlloc( GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
));
1054 TRACE("\t edit text length %i\n", length
);
1058 if( length
) GetWindowTextW( lphc
->hWndEdit
, pText
, length
+ 1);
1059 else pText
[0] = '\0';
1060 idx
= SendMessageW(lphc
->hWndLBox
, LB_FINDSTRING
,
1061 (WPARAM
)(-1), (LPARAM
)pText
);
1062 HeapFree( GetProcessHeap(), 0, pText
);
1065 SendMessageW(lphc
->hWndLBox
, LB_SETCURSEL
, (WPARAM
)(bSelect
? idx
: -1), 0);
1067 /* probably superfluous but Windows sends this too */
1068 SendMessageW(lphc
->hWndLBox
, LB_SETCARETINDEX
, (WPARAM
)(idx
< 0 ? 0 : idx
), 0);
1069 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
, (WPARAM
)(idx
< 0 ? 0 : idx
), 0);
1074 /***********************************************************************
1077 * Copy a listbox entry to the edit control.
1079 static void CBUpdateEdit( LPHEADCOMBO lphc
, INT index
)
1082 LPWSTR pText
= NULL
;
1083 static const WCHAR empty_stringW
[] = { 0 };
1085 TRACE("\t %i\n", index
);
1087 if( index
>= 0 ) /* got an entry */
1089 length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, (WPARAM
)index
, 0);
1092 if( (pText
= HeapAlloc( GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
))) )
1094 SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
,
1095 (WPARAM
)index
, (LPARAM
)pText
);
1100 lphc
->wState
|= (CBF_NOEDITNOTIFY
| CBF_NOLBSELECT
);
1101 SendMessageW(lphc
->hWndEdit
, WM_SETTEXT
, 0, pText
? (LPARAM
)pText
: (LPARAM
)empty_stringW
);
1102 lphc
->wState
&= ~(CBF_NOEDITNOTIFY
| CBF_NOLBSELECT
);
1104 if( lphc
->wState
& CBF_FOCUSED
)
1105 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1));
1108 HeapFree( GetProcessHeap(), 0, pText
);
1111 /***********************************************************************
1114 * Show listbox popup.
1116 static void CBDropDown( LPHEADCOMBO lphc
)
1122 TRACE("[%04x]: drop down\n", lphc
->self
);
1124 CB_NOTIFY( lphc
, CBN_DROPDOWN
);
1128 lphc
->wState
|= CBF_DROPPED
;
1129 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1131 lphc
->droppedIndex
= CBUpdateLBox( lphc
, TRUE
);
1133 /* Update edit only if item is in the list */
1134 if( !(lphc
->wState
& CBF_CAPTURE
) && lphc
->droppedIndex
>= 0)
1135 CBUpdateEdit( lphc
, lphc
->droppedIndex
);
1139 lphc
->droppedIndex
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1141 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
,
1142 (WPARAM
)(lphc
->droppedIndex
== LB_ERR
? 0 : lphc
->droppedIndex
), 0 );
1143 SendMessageW(lphc
->hWndLBox
, LB_CARETON
, 0, 0);
1146 /* now set popup position */
1147 GetWindowRect( lphc
->self
, &rect
);
1150 * If it's a dropdown, the listbox is offset
1152 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1153 rect
.left
+= COMBO_EDITBUTTONSPACE();
1155 /* if the dropped height is greater than the total height of the dropped
1156 items list, then force the drop down list height to be the total height
1157 of the items in the dropped list */
1159 /* And Remove any extra space (Best Fit) */
1160 nDroppedHeight
= lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
;
1161 /* if listbox length has been set directly by its handle */
1162 GetWindowRect(lphc
->hWndLBox
, &r
);
1163 if (nDroppedHeight
< r
.bottom
- r
.top
)
1164 nDroppedHeight
= r
.bottom
- r
.top
;
1165 nItems
= (int)SendMessageW(lphc
->hWndLBox
, LB_GETCOUNT
, 0, 0);
1171 nHeight
= (int)SendMessageW(lphc
->hWndLBox
, LB_GETITEMHEIGHT
, 0, 0);
1174 if (nHeight
< nDroppedHeight
- COMBO_YBORDERSIZE())
1175 nDroppedHeight
= nHeight
+ COMBO_YBORDERSIZE();
1178 /*If height of dropped rectangle gets beyond a screen size it should go up, otherwise down.*/
1179 if( (rect
.bottom
+ nDroppedHeight
) >= GetSystemMetrics( SM_CYSCREEN
) )
1180 rect
.bottom
= rect
.top
- nDroppedHeight
;
1182 SetWindowPos( lphc
->hWndLBox
, HWND_TOP
, rect
.left
, rect
.bottom
,
1183 lphc
->droppedRect
.right
- lphc
->droppedRect
.left
,
1185 SWP_NOACTIVATE
| SWP_SHOWWINDOW
);
1188 if( !(lphc
->wState
& CBF_NOREDRAW
) )
1189 RedrawWindow( lphc
->self
, NULL
, 0, RDW_INVALIDATE
|
1190 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1192 EnableWindow( lphc
->hWndLBox
, TRUE
);
1193 if (GetCapture() != lphc
->self
)
1194 SetCapture(lphc
->hWndLBox
);
1197 /***********************************************************************
1200 * Hide listbox popup.
1202 static void CBRollUp( LPHEADCOMBO lphc
, BOOL ok
, BOOL bButton
)
1204 HWND hWnd
= lphc
->self
;
1206 TRACE("[%04x]: sel ok? [%i] dropped? [%i]\n",
1207 lphc
->self
, (INT
)ok
, (INT
)(lphc
->wState
& CBF_DROPPED
));
1209 CB_NOTIFY( lphc
, (ok
) ? CBN_SELENDOK
: CBN_SELENDCANCEL
);
1211 if( IsWindow( hWnd
) && CB_GETTYPE(lphc
) != CBS_SIMPLE
)
1214 if( lphc
->wState
& CBF_DROPPED
)
1218 lphc
->wState
&= ~CBF_DROPPED
;
1219 ShowWindow( lphc
->hWndLBox
, SW_HIDE
);
1221 if(GetCapture() == lphc
->hWndLBox
)
1226 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1228 rect
= lphc
->buttonRect
;
1239 rect
= lphc
->textRect
;
1244 if( bButton
&& !(lphc
->wState
& CBF_NOREDRAW
) )
1245 RedrawWindow( hWnd
, &rect
, 0, RDW_INVALIDATE
|
1246 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1247 CB_NOTIFY( lphc
, CBN_CLOSEUP
);
1252 /***********************************************************************
1255 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
1257 BOOL
COMBO_FlipListbox( LPHEADCOMBO lphc
, BOOL ok
, BOOL bRedrawButton
)
1259 if( lphc
->wState
& CBF_DROPPED
)
1261 CBRollUp( lphc
, ok
, bRedrawButton
);
1269 /***********************************************************************
1272 static void CBRepaintButton( LPHEADCOMBO lphc
)
1274 InvalidateRect(lphc
->self
, &lphc
->buttonRect
, TRUE
);
1275 UpdateWindow(lphc
->self
);
1278 /***********************************************************************
1281 static void COMBO_SetFocus( LPHEADCOMBO lphc
)
1283 if( !(lphc
->wState
& CBF_FOCUSED
) )
1285 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
1286 SendMessageW(lphc
->hWndLBox
, LB_CARETON
, 0, 0);
1288 /* This is wrong. Message sequences seem to indicate that this
1289 is set *after* the notify. */
1290 /* lphc->wState |= CBF_FOCUSED; */
1292 if( !(lphc
->wState
& CBF_EDIT
) )
1293 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1295 CB_NOTIFY( lphc
, CBN_SETFOCUS
);
1296 lphc
->wState
|= CBF_FOCUSED
;
1300 /***********************************************************************
1303 static void COMBO_KillFocus( LPHEADCOMBO lphc
)
1305 HWND hWnd
= lphc
->self
;
1307 if( lphc
->wState
& CBF_FOCUSED
)
1309 CBRollUp( lphc
, FALSE
, TRUE
);
1310 if( IsWindow( hWnd
) )
1312 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
1313 SendMessageW(lphc
->hWndLBox
, LB_CARETOFF
, 0, 0);
1315 lphc
->wState
&= ~CBF_FOCUSED
;
1318 if( !(lphc
->wState
& CBF_EDIT
) )
1319 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1321 CB_NOTIFY( lphc
, CBN_KILLFOCUS
);
1326 /***********************************************************************
1329 static LRESULT
COMBO_Command( LPHEADCOMBO lphc
, WPARAM wParam
, HWND hWnd
)
1331 if ( lphc
->wState
& CBF_EDIT
&& lphc
->hWndEdit
== hWnd
)
1333 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
1335 switch( HIWORD(wParam
) >> 8 )
1337 case (EN_SETFOCUS
>> 8):
1339 TRACE("[%04x]: edit [%04x] got focus\n",
1340 lphc
->self
, lphc
->hWndEdit
);
1342 COMBO_SetFocus( lphc
);
1345 case (EN_KILLFOCUS
>> 8):
1347 TRACE("[%04x]: edit [%04x] lost focus\n",
1348 lphc
->self
, lphc
->hWndEdit
);
1350 /* NOTE: it seems that Windows' edit control sends an
1351 * undocumented message WM_USER + 0x1B instead of this
1352 * notification (only when it happens to be a part of
1353 * the combo). ?? - AK.
1356 COMBO_KillFocus( lphc
);
1360 case (EN_CHANGE
>> 8):
1362 * In some circumstances (when the selection of the combobox
1363 * is changed for example) we don't wans the EN_CHANGE notification
1364 * to be forwarded to the parent of the combobox. This code
1365 * checks a flag that is set in these occasions and ignores the
1368 if (lphc
->wState
& CBF_NOLBSELECT
)
1370 lphc
->wState
&= ~CBF_NOLBSELECT
;
1374 CBUpdateLBox( lphc
, lphc
->wState
& CBF_DROPPED
);
1377 if (!(lphc
->wState
& CBF_NOEDITNOTIFY
))
1378 CB_NOTIFY( lphc
, CBN_EDITCHANGE
);
1381 case (EN_UPDATE
>> 8):
1382 if (!(lphc
->wState
& CBF_NOEDITNOTIFY
))
1383 CB_NOTIFY( lphc
, CBN_EDITUPDATE
);
1386 case (EN_ERRSPACE
>> 8):
1387 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
1390 else if( lphc
->hWndLBox
== hWnd
)
1392 switch( HIWORD(wParam
) )
1395 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
1399 CB_NOTIFY( lphc
, CBN_DBLCLK
);
1405 TRACE("[%04x]: lbox selection change [%04x]\n",
1406 lphc
->self
, lphc
->wState
);
1408 if( HIWORD(wParam
) == LBN_SELCHANGE
)
1410 if( lphc
->wState
& CBF_EDIT
)
1412 INT index
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1413 lphc
->wState
|= CBF_NOLBSELECT
;
1414 CBUpdateEdit( lphc
, index
);
1415 /* select text in edit, as Windows does */
1416 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1));
1419 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1422 /* do not roll up if selection is being tracked
1423 * by arrowkeys in the dropdown listbox */
1424 if( ((lphc
->wState
& CBF_DROPPED
) && !(lphc
->wState
& CBF_NOROLLUP
)) )
1426 CBRollUp( lphc
, (HIWORD(wParam
) == LBN_SELCHANGE
), TRUE
);
1428 else lphc
->wState
&= ~CBF_NOROLLUP
;
1430 CB_NOTIFY( lphc
, CBN_SELCHANGE
);
1436 /* nothing to do here since ComboLBox always resets the focus to its
1437 * combo/edit counterpart */
1444 /***********************************************************************
1447 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
1449 static LRESULT
COMBO_ItemOp( LPHEADCOMBO lphc
, UINT msg
, LPARAM lParam
)
1451 HWND hWnd
= lphc
->self
;
1452 UINT id
= GetWindowLongA( hWnd
, GWL_ID
);
1454 TRACE("[%04x]: ownerdraw op %04x\n", lphc
->self
, msg
);
1460 DELETEITEMSTRUCT
*lpIS
= (DELETEITEMSTRUCT
*)lParam
;
1461 lpIS
->CtlType
= ODT_COMBOBOX
;
1463 lpIS
->hwndItem
= hWnd
;
1468 DRAWITEMSTRUCT
*lpIS
= (DRAWITEMSTRUCT
*)lParam
;
1469 lpIS
->CtlType
= ODT_COMBOBOX
;
1471 lpIS
->hwndItem
= hWnd
;
1474 case WM_COMPAREITEM
:
1476 COMPAREITEMSTRUCT
*lpIS
= (COMPAREITEMSTRUCT
*)lParam
;
1477 lpIS
->CtlType
= ODT_COMBOBOX
;
1479 lpIS
->hwndItem
= hWnd
;
1482 case WM_MEASUREITEM
:
1484 MEASUREITEMSTRUCT
*lpIS
= (MEASUREITEMSTRUCT
*)lParam
;
1485 lpIS
->CtlType
= ODT_COMBOBOX
;
1490 return SendMessageW(lphc
->owner
, msg
, id
, lParam
);
1493 /***********************************************************************
1496 * NOTE! LB_GETTEXT does not count terminating \0, WM_GETTEXT does.
1497 * also LB_GETTEXT might return values < 0, WM_GETTEXT doesn't.
1499 static LRESULT
COMBO_GetText( LPHEADCOMBO lphc
, INT N
, LPARAM lParam
, BOOL unicode
)
1501 if( lphc
->wState
& CBF_EDIT
)
1502 return unicode
? SendMessageW(lphc
->hWndEdit
, WM_GETTEXT
, (WPARAM
)N
, lParam
) :
1503 SendMessageA(lphc
->hWndEdit
, WM_GETTEXT
, (WPARAM
)N
, lParam
);
1505 /* get it from the listbox */
1507 if( lphc
->hWndLBox
)
1509 INT idx
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1513 INT length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
,
1518 LPWSTR lpBuffer
, lpText
= (LPWSTR
)lParam
;
1520 /* 'length' is without the terminating character */
1522 lpBuffer
= HeapAlloc(GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
));
1528 n
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, (WPARAM
)idx
, (LPARAM
)lpBuffer
);
1530 /* truncate if buffer is too short */
1536 strncpyW(lpText
, lpBuffer
, (N
> n
) ? n
+1 : N
-1);
1537 lpText
[N
- 1] = '\0';
1539 HeapFree( GetProcessHeap(), 0, lpBuffer
);
1545 LPSTR lpBuffer
, lpText
= (LPSTR
)lParam
;
1547 /* 'length' is without the terminating character */
1549 lpBuffer
= HeapAlloc(GetProcessHeap(), 0, length
+ 1);
1555 n
= SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, (WPARAM
)idx
, (LPARAM
)lpBuffer
);
1557 /* truncate if buffer is too short */
1563 strncpy(lpText
, lpBuffer
, (N
> n
) ? n
+1 : N
-1);
1564 lpText
[N
- 1] = '\0';
1566 HeapFree( GetProcessHeap(), 0, lpBuffer
);
1581 /***********************************************************************
1584 * This function sets window positions according to the updated
1585 * component placement struct.
1587 static void CBResetPos(
1593 BOOL bDrop
= (CB_GETTYPE(lphc
) != CBS_SIMPLE
);
1595 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1596 * sizing messages */
1598 if( lphc
->wState
& CBF_EDIT
)
1599 SetWindowPos( lphc
->hWndEdit
, 0,
1600 rectEdit
->left
, rectEdit
->top
,
1601 rectEdit
->right
- rectEdit
->left
,
1602 rectEdit
->bottom
- rectEdit
->top
,
1603 SWP_NOZORDER
| SWP_NOACTIVATE
| ((bDrop
) ? SWP_NOREDRAW
: 0) );
1605 SetWindowPos( lphc
->hWndLBox
, 0,
1606 rectLB
->left
, rectLB
->top
,
1607 rectLB
->right
- rectLB
->left
,
1608 rectLB
->bottom
- rectLB
->top
,
1609 SWP_NOACTIVATE
| SWP_NOZORDER
| ((bDrop
) ? SWP_NOREDRAW
: 0) );
1613 if( lphc
->wState
& CBF_DROPPED
)
1615 lphc
->wState
&= ~CBF_DROPPED
;
1616 ShowWindow( lphc
->hWndLBox
, SW_HIDE
);
1619 if( bRedraw
&& !(lphc
->wState
& CBF_NOREDRAW
) )
1620 RedrawWindow( lphc
->self
, NULL
, 0,
1621 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
);
1626 /***********************************************************************
1629 static void COMBO_Size( LPHEADCOMBO lphc
)
1631 CBCalcPlacement(lphc
->self
,
1635 &lphc
->droppedRect
);
1637 CBResetPos( lphc
, &lphc
->textRect
, &lphc
->droppedRect
, TRUE
);
1641 /***********************************************************************
1644 static void COMBO_Font( LPHEADCOMBO lphc
, HFONT hFont
, BOOL bRedraw
)
1649 lphc
->hFont
= hFont
;
1652 * Propagate to owned windows.
1654 if( lphc
->wState
& CBF_EDIT
)
1655 SendMessageW(lphc
->hWndEdit
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1656 SendMessageW(lphc
->hWndLBox
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1659 * Redo the layout of the control.
1661 if ( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
1663 CBCalcPlacement(lphc
->self
,
1667 &lphc
->droppedRect
);
1669 CBResetPos( lphc
, &lphc
->textRect
, &lphc
->droppedRect
, TRUE
);
1673 CBForceDummyResize(lphc
);
1678 /***********************************************************************
1679 * COMBO_SetItemHeight
1681 static LRESULT
COMBO_SetItemHeight( LPHEADCOMBO lphc
, INT index
, INT height
)
1683 LRESULT lRet
= CB_ERR
;
1685 if( index
== -1 ) /* set text field height */
1687 if( height
< 32768 )
1689 lphc
->editHeight
= height
;
1692 * Redo the layout of the control.
1694 if ( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
1696 CBCalcPlacement(lphc
->self
,
1700 &lphc
->droppedRect
);
1702 CBResetPos( lphc
, &lphc
->textRect
, &lphc
->droppedRect
, TRUE
);
1706 CBForceDummyResize(lphc
);
1712 else if ( CB_OWNERDRAWN(lphc
) ) /* set listbox item height */
1713 lRet
= SendMessageW(lphc
->hWndLBox
, LB_SETITEMHEIGHT
,
1714 (WPARAM
)index
, (LPARAM
)height
);
1718 /***********************************************************************
1719 * COMBO_SelectString
1721 static LRESULT
COMBO_SelectString( LPHEADCOMBO lphc
, INT start
, LPARAM pText
, BOOL unicode
)
1723 INT index
= unicode
? SendMessageW(lphc
->hWndLBox
, LB_SELECTSTRING
, (WPARAM
)start
, pText
) :
1724 SendMessageA(lphc
->hWndLBox
, LB_SELECTSTRING
, (WPARAM
)start
, pText
);
1727 if( lphc
->wState
& CBF_EDIT
)
1728 CBUpdateEdit( lphc
, index
);
1731 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1734 return (LRESULT
)index
;
1737 /***********************************************************************
1740 static void COMBO_LButtonDown( LPHEADCOMBO lphc
, LPARAM lParam
)
1744 HWND hWnd
= lphc
->self
;
1746 pt
.x
= LOWORD(lParam
);
1747 pt
.y
= HIWORD(lParam
);
1748 bButton
= PtInRect(&lphc
->buttonRect
, pt
);
1750 if( (CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
) ||
1751 (bButton
&& (CB_GETTYPE(lphc
) == CBS_DROPDOWN
)) )
1753 lphc
->wState
|= CBF_BUTTONDOWN
;
1754 if( lphc
->wState
& CBF_DROPPED
)
1756 /* got a click to cancel selection */
1758 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1759 CBRollUp( lphc
, TRUE
, FALSE
);
1760 if( !IsWindow( hWnd
) ) return;
1762 if( lphc
->wState
& CBF_CAPTURE
)
1764 lphc
->wState
&= ~CBF_CAPTURE
;
1770 /* drop down the listbox and start tracking */
1772 lphc
->wState
|= CBF_CAPTURE
;
1776 if( bButton
) CBRepaintButton( lphc
);
1780 /***********************************************************************
1783 * Release capture and stop tracking if needed.
1785 static void COMBO_LButtonUp( LPHEADCOMBO lphc
)
1787 if( lphc
->wState
& CBF_CAPTURE
)
1789 lphc
->wState
&= ~CBF_CAPTURE
;
1790 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1792 INT index
= CBUpdateLBox( lphc
, TRUE
);
1793 /* Update edit only if item is in the list */
1796 lphc
->wState
|= CBF_NOLBSELECT
;
1797 CBUpdateEdit( lphc
, index
);
1798 lphc
->wState
&= ~CBF_NOLBSELECT
;
1802 SetCapture(lphc
->hWndLBox
);
1805 if( lphc
->wState
& CBF_BUTTONDOWN
)
1807 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1808 CBRepaintButton( lphc
);
1812 /***********************************************************************
1815 * Two things to do - track combo button and release capture when
1816 * pointer goes into the listbox.
1818 static void COMBO_MouseMove( LPHEADCOMBO lphc
, WPARAM wParam
, LPARAM lParam
)
1823 pt
.x
= LOWORD(lParam
);
1824 pt
.y
= HIWORD(lParam
);
1826 if( lphc
->wState
& CBF_BUTTONDOWN
)
1830 bButton
= PtInRect(&lphc
->buttonRect
, pt
);
1834 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1835 CBRepaintButton( lphc
);
1839 GetClientRect( lphc
->hWndLBox
, &lbRect
);
1840 MapWindowPoints( lphc
->self
, lphc
->hWndLBox
, &pt
, 1 );
1841 if( PtInRect(&lbRect
, pt
) )
1843 lphc
->wState
&= ~CBF_CAPTURE
;
1845 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
) CBUpdateLBox( lphc
, TRUE
);
1847 /* hand over pointer tracking */
1848 SendMessageW(lphc
->hWndLBox
, WM_LBUTTONDOWN
, wParam
, lParam
);
1853 /***********************************************************************
1854 * ComboWndProc_common
1856 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
1858 static LRESULT
ComboWndProc_common( HWND hwnd
, UINT message
,
1859 WPARAM wParam
, LPARAM lParam
, BOOL unicode
)
1861 LPHEADCOMBO lphc
= (LPHEADCOMBO
)GetWindowLongA( hwnd
, 0 );
1863 TRACE("[%04x]: msg %s wp %08x lp %08lx\n",
1864 hwnd
, SPY_GetMsgName(message
, hwnd
), wParam
, lParam
);
1866 if( lphc
|| message
== WM_NCCREATE
)
1870 /* System messages */
1874 LONG style
= unicode
? ((LPCREATESTRUCTW
)lParam
)->style
:
1875 ((LPCREATESTRUCTA
)lParam
)->style
;
1876 return COMBO_NCCreate(hwnd
, style
);
1879 COMBO_NCDestroy(lphc
);
1880 break;/* -> DefWindowProc */
1888 hwndParent
= ((LPCREATESTRUCTW
)lParam
)->hwndParent
;
1889 style
= ((LPCREATESTRUCTW
)lParam
)->style
;
1893 hwndParent
= ((LPCREATESTRUCTA
)lParam
)->hwndParent
;
1894 style
= ((LPCREATESTRUCTA
)lParam
)->style
;
1896 return COMBO_Create(hwnd
, lphc
, hwndParent
, style
);
1899 case WM_PRINTCLIENT
:
1900 if (lParam
& PRF_ERASEBKGND
)
1901 COMBO_EraseBackground(hwnd
, lphc
, wParam
);
1905 /* wParam may contain a valid HDC! */
1906 return COMBO_Paint(lphc
, wParam
);
1908 return COMBO_EraseBackground(hwnd
, lphc
, wParam
);
1911 LRESULT result
= DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1912 if (lParam
&& (((LPMSG
)lParam
)->message
== WM_KEYDOWN
))
1914 int vk
= (int)((LPMSG
)lParam
)->wParam
;
1916 if ((vk
== VK_RETURN
|| vk
== VK_ESCAPE
) && (lphc
->wState
& CBF_DROPPED
))
1917 result
|= DLGC_WANTMESSAGE
;
1921 case WM_WINDOWPOSCHANGING
:
1922 return COMBO_WindowPosChanging(hwnd
, lphc
, (LPWINDOWPOS
)lParam
);
1923 case WM_WINDOWPOSCHANGED
:
1924 /* SetWindowPos can be called on a Combobox to resize its Listbox.
1925 * In that case, the Combobox itself will not be resized, so we won't
1926 * get a WM_SIZE. Since we still want to update the Listbox, we have to
1931 if( lphc
->hWndLBox
&&
1932 !(lphc
->wState
& CBF_NORESIZE
) ) COMBO_Size( lphc
);
1935 COMBO_Font( lphc
, (HFONT16
)wParam
, (BOOL
)lParam
);
1938 return (LRESULT
)lphc
->hFont
;
1940 if( lphc
->wState
& CBF_EDIT
)
1941 SetFocus( lphc
->hWndEdit
);
1943 COMBO_SetFocus( lphc
);
1947 HWND hwndFocus
= WIN_GetFullHandle( (HWND
)wParam
);
1949 (hwndFocus
!= lphc
->hWndEdit
&& hwndFocus
!= lphc
->hWndLBox
))
1950 COMBO_KillFocus( lphc
);
1954 return COMBO_Command( lphc
, wParam
, WIN_GetFullHandle( (HWND
)lParam
) );
1956 return COMBO_GetText( lphc
, (INT
)wParam
, lParam
, unicode
);
1958 case WM_GETTEXTLENGTH
:
1960 if ((message
== WM_GETTEXTLENGTH
) && !ISWIN31
&& !(lphc
->wState
& CBF_EDIT
))
1962 int j
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1963 if (j
== -1) return 0;
1964 return SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, j
, 0);
1966 else if( lphc
->wState
& CBF_EDIT
)
1969 lphc
->wState
|= CBF_NOEDITNOTIFY
;
1970 ret
= unicode
? SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
) :
1971 SendMessageA(lphc
->hWndEdit
, message
, wParam
, lParam
);
1972 lphc
->wState
&= ~CBF_NOEDITNOTIFY
;
1979 if( lphc
->wState
& CBF_EDIT
)
1981 return unicode
? SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
) :
1982 SendMessageA(lphc
->hWndEdit
, message
, wParam
, lParam
);
1988 case WM_COMPAREITEM
:
1989 case WM_MEASUREITEM
:
1990 return COMBO_ItemOp(lphc
, message
, lParam
);
1992 if( lphc
->wState
& CBF_EDIT
)
1993 EnableWindow( lphc
->hWndEdit
, (BOOL
)wParam
);
1994 EnableWindow( lphc
->hWndLBox
, (BOOL
)wParam
);
1996 /* Force the control to repaint when the enabled state changes. */
1997 InvalidateRect(lphc
->self
, NULL
, TRUE
);
2001 lphc
->wState
&= ~CBF_NOREDRAW
;
2003 lphc
->wState
|= CBF_NOREDRAW
;
2005 if( lphc
->wState
& CBF_EDIT
)
2006 SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
);
2007 SendMessageW(lphc
->hWndLBox
, message
, wParam
, lParam
);
2010 if( KEYDATA_ALT
& HIWORD(lParam
) )
2011 if( wParam
== VK_UP
|| wParam
== VK_DOWN
)
2012 COMBO_FlipListbox( lphc
, FALSE
, FALSE
);
2020 if ((wParam
== VK_RETURN
|| wParam
== VK_ESCAPE
) &&
2021 (lphc
->wState
& CBF_DROPPED
))
2023 CBRollUp( lphc
, wParam
== VK_RETURN
, FALSE
);
2027 if( lphc
->wState
& CBF_EDIT
)
2028 hwndTarget
= lphc
->hWndEdit
;
2030 hwndTarget
= lphc
->hWndLBox
;
2032 return unicode
? SendMessageW(hwndTarget
, message
, wParam
, lParam
) :
2033 SendMessageA(hwndTarget
, message
, wParam
, lParam
);
2035 case WM_LBUTTONDOWN
:
2036 if( !(lphc
->wState
& CBF_FOCUSED
) ) SetFocus( lphc
->self
);
2037 if( lphc
->wState
& CBF_FOCUSED
) COMBO_LButtonDown( lphc
, lParam
);
2040 COMBO_LButtonUp( lphc
);
2043 if( lphc
->wState
& CBF_CAPTURE
)
2044 COMBO_MouseMove( lphc
, wParam
, lParam
);
2048 if (wParam
& (MK_SHIFT
| MK_CONTROL
))
2049 return unicode
? DefWindowProcW(hwnd
, message
, wParam
, lParam
) :
2050 DefWindowProcA(hwnd
, message
, wParam
, lParam
);
2051 if (SHIWORD(wParam
) > 0) return SendMessageW(hwnd
, WM_KEYDOWN
, VK_UP
, 0);
2052 if (SHIWORD(wParam
) < 0) return SendMessageW(hwnd
, WM_KEYDOWN
, VK_DOWN
, 0);
2055 /* Combo messages */
2057 case CB_ADDSTRING16
:
2058 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2061 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_ADDSTRING
, 0, lParam
) :
2062 SendMessageA(lphc
->hWndLBox
, LB_ADDSTRING
, 0, lParam
);
2063 case CB_INSERTSTRING16
:
2064 wParam
= (INT
)(INT16
)wParam
;
2065 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2067 case CB_INSERTSTRING
:
2068 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_INSERTSTRING
, wParam
, lParam
) :
2069 SendMessageA(lphc
->hWndLBox
, LB_INSERTSTRING
, wParam
, lParam
);
2070 case CB_DELETESTRING16
:
2071 case CB_DELETESTRING
:
2072 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_DELETESTRING
, wParam
, 0) :
2073 SendMessageA(lphc
->hWndLBox
, LB_DELETESTRING
, wParam
, 0);
2074 case CB_SELECTSTRING16
:
2075 wParam
= (INT
)(INT16
)wParam
;
2076 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2078 case CB_SELECTSTRING
:
2079 return COMBO_SelectString(lphc
, (INT
)wParam
, lParam
, unicode
);
2080 case CB_FINDSTRING16
:
2081 wParam
= (INT
)(INT16
)wParam
;
2082 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2085 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_FINDSTRING
, wParam
, lParam
) :
2086 SendMessageA(lphc
->hWndLBox
, LB_FINDSTRING
, wParam
, lParam
);
2087 case CB_FINDSTRINGEXACT16
:
2088 wParam
= (INT
)(INT16
)wParam
;
2089 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2091 case CB_FINDSTRINGEXACT
:
2092 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_FINDSTRINGEXACT
, wParam
, lParam
) :
2093 SendMessageA(lphc
->hWndLBox
, LB_FINDSTRINGEXACT
, wParam
, lParam
);
2094 case CB_SETITEMHEIGHT16
:
2095 wParam
= (INT
)(INT16
)wParam
; /* signed integer */
2097 case CB_SETITEMHEIGHT
:
2098 return COMBO_SetItemHeight( lphc
, (INT
)wParam
, (INT
)lParam
);
2099 case CB_GETITEMHEIGHT16
:
2100 wParam
= (INT
)(INT16
)wParam
;
2102 case CB_GETITEMHEIGHT
:
2103 if( (INT
)wParam
>= 0 ) /* listbox item */
2104 return SendMessageW(lphc
->hWndLBox
, LB_GETITEMHEIGHT
, wParam
, 0);
2105 return CBGetTextAreaHeight(hwnd
, lphc
);
2106 case CB_RESETCONTENT16
:
2107 case CB_RESETCONTENT
:
2108 SendMessageW(lphc
->hWndLBox
, LB_RESETCONTENT
, 0, 0);
2109 if( (lphc
->wState
& CBF_EDIT
) && CB_HASSTRINGS(lphc
) )
2111 static const WCHAR empty_stringW
[] = { 0 };
2112 SendMessageW(lphc
->hWndEdit
, WM_SETTEXT
, 0, (LPARAM
)empty_stringW
);
2115 InvalidateRect(lphc
->self
, NULL
, TRUE
);
2117 case CB_INITSTORAGE
:
2118 return SendMessageW(lphc
->hWndLBox
, LB_INITSTORAGE
, wParam
, lParam
);
2119 case CB_GETHORIZONTALEXTENT
:
2120 return SendMessageW(lphc
->hWndLBox
, LB_GETHORIZONTALEXTENT
, 0, 0);
2121 case CB_SETHORIZONTALEXTENT
:
2122 return SendMessageW(lphc
->hWndLBox
, LB_SETHORIZONTALEXTENT
, wParam
, 0);
2123 case CB_GETTOPINDEX
:
2124 return SendMessageW(lphc
->hWndLBox
, LB_GETTOPINDEX
, 0, 0);
2126 return SendMessageW(lphc
->hWndLBox
, LB_GETLOCALE
, 0, 0);
2128 return SendMessageW(lphc
->hWndLBox
, LB_SETLOCALE
, wParam
, 0);
2129 case CB_GETDROPPEDWIDTH
:
2130 if( lphc
->droppedWidth
)
2131 return lphc
->droppedWidth
;
2132 return lphc
->droppedRect
.right
- lphc
->droppedRect
.left
;
2133 case CB_SETDROPPEDWIDTH
:
2134 if( (CB_GETTYPE(lphc
) != CBS_SIMPLE
) &&
2135 (INT
)wParam
< 32768 ) lphc
->droppedWidth
= (INT
)wParam
;
2137 case CB_GETDROPPEDCONTROLRECT16
:
2138 lParam
= (LPARAM
)MapSL(lParam
);
2142 CBGetDroppedControlRect( lphc
, &r
);
2143 CONV_RECT32TO16( &r
, (LPRECT16
)lParam
);
2146 case CB_GETDROPPEDCONTROLRECT
:
2147 if( lParam
) CBGetDroppedControlRect(lphc
, (LPRECT
)lParam
);
2149 case CB_GETDROPPEDSTATE16
:
2150 case CB_GETDROPPEDSTATE
:
2151 return (lphc
->wState
& CBF_DROPPED
) ? TRUE
: FALSE
;
2153 lParam
= (LPARAM
)MapSL(lParam
);
2157 if(message
== CB_DIR
) message
= LB_DIR
;
2158 return unicode
? SendMessageW(lphc
->hWndLBox
, message
, wParam
, lParam
) :
2159 SendMessageA(lphc
->hWndLBox
, message
, wParam
, lParam
);
2161 case CB_SHOWDROPDOWN16
:
2162 case CB_SHOWDROPDOWN
:
2163 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
2167 if( !(lphc
->wState
& CBF_DROPPED
) )
2171 if( lphc
->wState
& CBF_DROPPED
)
2172 CBRollUp( lphc
, FALSE
, TRUE
);
2177 return SendMessageW(lphc
->hWndLBox
, LB_GETCOUNT
, 0, 0);
2178 case CB_GETCURSEL16
:
2180 return SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
2181 case CB_SETCURSEL16
:
2182 wParam
= (INT
)(INT16
)wParam
;
2185 lParam
= SendMessageW(lphc
->hWndLBox
, LB_SETCURSEL
, wParam
, 0);
2187 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
, wParam
, 0);
2189 /* no LBN_SELCHANGE in this case, update manually */
2190 if( lphc
->wState
& CBF_EDIT
)
2191 CBUpdateEdit( lphc
, (INT
)wParam
);
2193 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
2194 lphc
->wState
&= ~CBF_SELCHANGE
;
2196 case CB_GETLBTEXT16
:
2197 wParam
= (INT
)(INT16
)wParam
;
2198 lParam
= (LPARAM
)MapSL(lParam
);
2201 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, wParam
, lParam
) :
2202 SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, wParam
, lParam
);
2203 case CB_GETLBTEXTLEN16
:
2204 wParam
= (INT
)(INT16
)wParam
;
2206 case CB_GETLBTEXTLEN
:
2207 return SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, wParam
, 0);
2208 case CB_GETITEMDATA16
:
2209 wParam
= (INT
)(INT16
)wParam
;
2211 case CB_GETITEMDATA
:
2212 return SendMessageW(lphc
->hWndLBox
, LB_GETITEMDATA
, wParam
, 0);
2213 case CB_SETITEMDATA16
:
2214 wParam
= (INT
)(INT16
)wParam
;
2216 case CB_SETITEMDATA
:
2217 return SendMessageW(lphc
->hWndLBox
, LB_SETITEMDATA
, wParam
, lParam
);
2218 case CB_GETEDITSEL16
:
2219 wParam
= lParam
= 0; /* just in case */
2222 /* Edit checks passed parameters itself */
2223 if( lphc
->wState
& CBF_EDIT
)
2224 return SendMessageW(lphc
->hWndEdit
, EM_GETSEL
, wParam
, lParam
);
2226 case CB_SETEDITSEL16
:
2228 if( lphc
->wState
& CBF_EDIT
)
2229 return SendMessageW(lphc
->hWndEdit
, EM_SETSEL
,
2230 (INT
)(INT16
)LOWORD(lParam
), (INT
)(INT16
)HIWORD(lParam
) );
2232 case CB_SETEXTENDEDUI16
:
2233 case CB_SETEXTENDEDUI
:
2234 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
2237 lphc
->wState
|= CBF_EUI
;
2238 else lphc
->wState
&= ~CBF_EUI
;
2240 case CB_GETEXTENDEDUI16
:
2241 case CB_GETEXTENDEDUI
:
2242 return (lphc
->wState
& CBF_EUI
) ? TRUE
: FALSE
;
2245 if (message
>= WM_USER
)
2246 WARN("unknown msg WM_USER+%04x wp=%04x lp=%08lx\n",
2247 message
- WM_USER
, wParam
, lParam
);
2250 return unicode
? DefWindowProcW(hwnd
, message
, wParam
, lParam
) :
2251 DefWindowProcA(hwnd
, message
, wParam
, lParam
);
2254 /***********************************************************************
2257 * This is just a wrapper for the real ComboWndProc which locks/unlocks
2260 static LRESULT WINAPI
ComboWndProcA( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2262 if (!IsWindow(hwnd
)) return 0;
2263 return ComboWndProc_common( hwnd
, message
, wParam
, lParam
, FALSE
);
2266 /***********************************************************************
2269 static LRESULT WINAPI
ComboWndProcW( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2271 if (!IsWindow(hwnd
)) return 0;
2272 return ComboWndProc_common( hwnd
, message
, wParam
, lParam
, TRUE
);