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("[0x%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 SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, (WPARAM
)id
, (LPARAM
)pText
);
751 pText
[size
] = '\0'; /* just in case */
755 if( !CB_OWNERDRAWN(lphc
) )
758 if( lphc
->wState
& CBF_EDIT
)
760 static const WCHAR empty_stringW
[] = { 0 };
761 if( CB_HASSTRINGS(lphc
) ) SetWindowTextW( lphc
->hWndEdit
, pText
? pText
: empty_stringW
);
762 if( lphc
->wState
& CBF_FOCUSED
)
763 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1));
765 else /* paint text field ourselves */
767 UINT itemState
= ODS_COMBOBOXEDIT
;
768 HFONT hPrevFont
= (lphc
->hFont
) ? SelectObject(hdc
, lphc
->hFont
) : 0;
771 * Give ourselves some space.
773 InflateRect( &rectEdit
, -1, -1 );
775 if( CB_OWNERDRAWN(lphc
) )
779 UINT ctlid
= GetWindowLongA( lphc
->self
, GWL_ID
);
781 /* setup state for DRAWITEM message. Owner will highlight */
782 if ( (lphc
->wState
& CBF_FOCUSED
) &&
783 !(lphc
->wState
& CBF_DROPPED
) )
784 itemState
|= ODS_SELECTED
| ODS_FOCUS
;
787 * Save the current clip region.
788 * To retrieve the clip region, we need to create one "dummy"
791 clipRegion
= CreateRectRgnIndirect(&rectEdit
);
793 if (GetClipRgn(hdc
, clipRegion
)!=1)
795 DeleteObject(clipRegion
);
796 clipRegion
=(HRGN
)NULL
;
799 if (!IsWindowEnabled(lphc
->self
) & WS_DISABLED
) itemState
|= ODS_DISABLED
;
801 dis
.CtlType
= ODT_COMBOBOX
;
803 dis
.hwndItem
= lphc
->self
;
804 dis
.itemAction
= ODA_DRAWENTIRE
;
806 dis
.itemState
= itemState
;
808 dis
.rcItem
= rectEdit
;
809 dis
.itemData
= SendMessageW(lphc
->hWndLBox
, LB_GETITEMDATA
,
813 * Clip the DC and have the parent draw the item.
815 IntersectClipRect(hdc
,
816 rectEdit
.left
, rectEdit
.top
,
817 rectEdit
.right
, rectEdit
.bottom
);
819 SendMessageW(lphc
->owner
, WM_DRAWITEM
, ctlid
, (LPARAM
)&dis
);
822 * Reset the clipping region.
824 SelectClipRgn(hdc
, clipRegion
);
828 static const WCHAR empty_stringW
[] = { 0 };
830 if ( (lphc
->wState
& CBF_FOCUSED
) &&
831 !(lphc
->wState
& CBF_DROPPED
) ) {
834 FillRect( hdc
, &rectEdit
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
835 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
836 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
842 ETO_OPAQUE
| ETO_CLIPPED
,
844 pText
? pText
: empty_stringW
, size
, NULL
);
846 if(lphc
->wState
& CBF_FOCUSED
&& !(lphc
->wState
& CBF_DROPPED
))
847 DrawFocusRect( hdc
, &rectEdit
);
851 SelectObject(hdc
, hPrevFont
);
854 HeapFree( GetProcessHeap(), 0, pText
);
857 /***********************************************************************
860 static void CBPaintBorder(
867 if (CB_GETTYPE(lphc
) != CBS_SIMPLE
)
869 GetClientRect(hwnd
, &clientRect
);
873 CopyRect(&clientRect
, &lphc
->textRect
);
875 InflateRect(&clientRect
, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
876 InflateRect(&clientRect
, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
879 DrawEdge(hdc
, &clientRect
, EDGE_SUNKEN
, BF_RECT
);
882 /***********************************************************************
883 * COMBO_PrepareColors
885 * This method will sent the appropriate WM_CTLCOLOR message to
886 * prepare and setup the colors for the combo's DC.
888 * It also returns the brush to use for the background.
890 static HBRUSH
COMBO_PrepareColors(
897 * Get the background brush for this control.
899 if (CB_DISABLED(lphc
))
901 hBkgBrush
= SendMessageW(lphc
->owner
, WM_CTLCOLORSTATIC
, hDC
, (LPARAM
)lphc
->self
);
904 * We have to change the text color since WM_CTLCOLORSTATIC will
905 * set it to the "enabled" color. This is the same behavior as the
908 SetTextColor(hDC
, GetSysColor(COLOR_GRAYTEXT
));
912 if (lphc
->wState
& CBF_EDIT
)
914 hBkgBrush
= SendMessageW(lphc
->owner
, WM_CTLCOLOREDIT
, hDC
, (LPARAM
)lphc
->self
);
918 hBkgBrush
= SendMessageW(lphc
->owner
, WM_CTLCOLORLISTBOX
, hDC
, (LPARAM
)lphc
->self
);
926 hBkgBrush
= GetSysColorBrush(COLOR_WINDOW
);
931 /***********************************************************************
932 * COMBO_EraseBackground
934 static LRESULT
COMBO_EraseBackground(
942 if(lphc
->wState
& CBF_EDIT
)
945 hDC
= (hParamDC
) ? hParamDC
948 * Retrieve the background brush
950 hBkgBrush
= COMBO_PrepareColors(lphc
, hDC
);
952 FillRect(hDC
, &lphc
->textRect
, hBkgBrush
);
955 ReleaseDC(hwnd
, hDC
);
960 /***********************************************************************
963 static LRESULT
COMBO_Paint(LPHEADCOMBO lphc
, HDC hParamDC
)
968 hDC
= (hParamDC
) ? hParamDC
969 : BeginPaint( lphc
->self
, &ps
);
971 TRACE("hdc=%04x\n", hDC
);
973 if( hDC
&& !(lphc
->wState
& CBF_NOREDRAW
) )
975 HBRUSH hPrevBrush
, hBkgBrush
;
978 * Retrieve the background brush and select it in the
981 hBkgBrush
= COMBO_PrepareColors(lphc
, hDC
);
983 hPrevBrush
= SelectObject( hDC
, hBkgBrush
);
986 * In non 3.1 look, there is a sunken border on the combobox
988 if (TWEAK_WineLook
!= WIN31_LOOK
)
990 CBPaintBorder(lphc
->self
, lphc
, hDC
);
993 if( !IsRectEmpty(&lphc
->buttonRect
) )
995 CBPaintButton(lphc
, hDC
, lphc
->buttonRect
);
998 /* paint the edit control padding area */
999 if (CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
)
1001 RECT rPadEdit
= lphc
->textRect
;
1003 InflateRect(&rPadEdit
, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
1005 FrameRect( hDC
, &rPadEdit
, GetSysColorBrush(COLOR_WINDOW
) );
1008 if( !(lphc
->wState
& CBF_EDIT
) )
1011 * The text area has a border only in Win 3.1 look.
1013 if (TWEAK_WineLook
== WIN31_LOOK
)
1015 HPEN hPrevPen
= SelectObject( hDC
, GetSysColorPen(COLOR_WINDOWFRAME
) );
1018 lphc
->textRect
.left
, lphc
->textRect
.top
,
1019 lphc
->textRect
.right
- 1, lphc
->textRect
.bottom
- 1);
1021 SelectObject( hDC
, hPrevPen
);
1024 CBPaintText( lphc
, hDC
, lphc
->textRect
);
1028 SelectObject( hDC
, hPrevBrush
);
1032 EndPaint(lphc
->self
, &ps
);
1037 /***********************************************************************
1040 * Select listbox entry according to the contents of the edit control.
1042 static INT
CBUpdateLBox( LPHEADCOMBO lphc
, BOOL bSelect
)
1045 LPWSTR pText
= NULL
;
1048 length
= SendMessageW( lphc
->hWndEdit
, WM_GETTEXTLENGTH
, 0, 0 );
1051 pText
= HeapAlloc( GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
));
1053 TRACE("\t edit text length %i\n", length
);
1057 if( length
) GetWindowTextW( lphc
->hWndEdit
, pText
, length
+ 1);
1058 else pText
[0] = '\0';
1059 idx
= SendMessageW(lphc
->hWndLBox
, LB_FINDSTRING
,
1060 (WPARAM
)(-1), (LPARAM
)pText
);
1061 HeapFree( GetProcessHeap(), 0, pText
);
1064 SendMessageW(lphc
->hWndLBox
, LB_SETCURSEL
, (WPARAM
)(bSelect
? idx
: -1), 0);
1066 /* probably superfluous but Windows sends this too */
1067 SendMessageW(lphc
->hWndLBox
, LB_SETCARETINDEX
, (WPARAM
)(idx
< 0 ? 0 : idx
), 0);
1068 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
, (WPARAM
)(idx
< 0 ? 0 : idx
), 0);
1073 /***********************************************************************
1076 * Copy a listbox entry to the edit control.
1078 static void CBUpdateEdit( LPHEADCOMBO lphc
, INT index
)
1081 LPWSTR pText
= NULL
;
1082 static const WCHAR empty_stringW
[] = { 0 };
1084 TRACE("\t %i\n", index
);
1086 if( index
>= 0 ) /* got an entry */
1088 length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, (WPARAM
)index
, 0);
1091 if( (pText
= HeapAlloc( GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
))) )
1093 SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
,
1094 (WPARAM
)index
, (LPARAM
)pText
);
1099 lphc
->wState
|= (CBF_NOEDITNOTIFY
| CBF_NOLBSELECT
);
1100 SendMessageW(lphc
->hWndEdit
, WM_SETTEXT
, 0, pText
? (LPARAM
)pText
: (LPARAM
)empty_stringW
);
1101 lphc
->wState
&= ~(CBF_NOEDITNOTIFY
| CBF_NOLBSELECT
);
1103 if( lphc
->wState
& CBF_FOCUSED
)
1104 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1));
1107 HeapFree( GetProcessHeap(), 0, pText
);
1110 /***********************************************************************
1113 * Show listbox popup.
1115 static void CBDropDown( LPHEADCOMBO lphc
)
1121 TRACE("[%04x]: drop down\n", lphc
->self
);
1123 CB_NOTIFY( lphc
, CBN_DROPDOWN
);
1127 lphc
->wState
|= CBF_DROPPED
;
1128 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1130 lphc
->droppedIndex
= CBUpdateLBox( lphc
, TRUE
);
1132 /* Update edit only if item is in the list */
1133 if( !(lphc
->wState
& CBF_CAPTURE
) && lphc
->droppedIndex
>= 0)
1134 CBUpdateEdit( lphc
, lphc
->droppedIndex
);
1138 lphc
->droppedIndex
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1140 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
,
1141 (WPARAM
)(lphc
->droppedIndex
== LB_ERR
? 0 : lphc
->droppedIndex
), 0 );
1142 SendMessageW(lphc
->hWndLBox
, LB_CARETON
, 0, 0);
1145 /* now set popup position */
1146 GetWindowRect( lphc
->self
, &rect
);
1149 * If it's a dropdown, the listbox is offset
1151 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1152 rect
.left
+= COMBO_EDITBUTTONSPACE();
1154 /* if the dropped height is greater than the total height of the dropped
1155 items list, then force the drop down list height to be the total height
1156 of the items in the dropped list */
1158 /* And Remove any extra space (Best Fit) */
1159 nDroppedHeight
= lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
;
1160 /* if listbox length has been set directly by its handle */
1161 GetWindowRect(lphc
->hWndLBox
, &r
);
1162 if (nDroppedHeight
< r
.bottom
- r
.top
)
1163 nDroppedHeight
= r
.bottom
- r
.top
;
1164 nItems
= (int)SendMessageW(lphc
->hWndLBox
, LB_GETCOUNT
, 0, 0);
1170 nHeight
= (int)SendMessageW(lphc
->hWndLBox
, LB_GETITEMHEIGHT
, 0, 0);
1173 if (nHeight
< nDroppedHeight
- COMBO_YBORDERSIZE())
1174 nDroppedHeight
= nHeight
+ COMBO_YBORDERSIZE();
1177 /*If height of dropped rectangle gets beyond a screen size it should go up, otherwise down.*/
1178 if( (rect
.bottom
+ nDroppedHeight
) >= GetSystemMetrics( SM_CYSCREEN
) )
1179 rect
.bottom
= rect
.top
- nDroppedHeight
;
1181 SetWindowPos( lphc
->hWndLBox
, HWND_TOP
, rect
.left
, rect
.bottom
,
1182 lphc
->droppedRect
.right
- lphc
->droppedRect
.left
,
1184 SWP_NOACTIVATE
| SWP_SHOWWINDOW
);
1187 if( !(lphc
->wState
& CBF_NOREDRAW
) )
1188 RedrawWindow( lphc
->self
, NULL
, 0, RDW_INVALIDATE
|
1189 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1191 EnableWindow( lphc
->hWndLBox
, TRUE
);
1192 if (GetCapture() != lphc
->self
)
1193 SetCapture(lphc
->hWndLBox
);
1196 /***********************************************************************
1199 * Hide listbox popup.
1201 static void CBRollUp( LPHEADCOMBO lphc
, BOOL ok
, BOOL bButton
)
1203 HWND hWnd
= lphc
->self
;
1205 TRACE("[%04x]: sel ok? [%i] dropped? [%i]\n",
1206 lphc
->self
, (INT
)ok
, (INT
)(lphc
->wState
& CBF_DROPPED
));
1208 CB_NOTIFY( lphc
, (ok
) ? CBN_SELENDOK
: CBN_SELENDCANCEL
);
1210 if( IsWindow( hWnd
) && CB_GETTYPE(lphc
) != CBS_SIMPLE
)
1213 if( lphc
->wState
& CBF_DROPPED
)
1217 lphc
->wState
&= ~CBF_DROPPED
;
1218 ShowWindow( lphc
->hWndLBox
, SW_HIDE
);
1220 if(GetCapture() == lphc
->hWndLBox
)
1225 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1227 rect
= lphc
->buttonRect
;
1238 rect
= lphc
->textRect
;
1243 if( bButton
&& !(lphc
->wState
& CBF_NOREDRAW
) )
1244 RedrawWindow( hWnd
, &rect
, 0, RDW_INVALIDATE
|
1245 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1246 CB_NOTIFY( lphc
, CBN_CLOSEUP
);
1251 /***********************************************************************
1254 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
1256 BOOL
COMBO_FlipListbox( LPHEADCOMBO lphc
, BOOL ok
, BOOL bRedrawButton
)
1258 if( lphc
->wState
& CBF_DROPPED
)
1260 CBRollUp( lphc
, ok
, bRedrawButton
);
1268 /***********************************************************************
1271 static void CBRepaintButton( LPHEADCOMBO lphc
)
1273 InvalidateRect(lphc
->self
, &lphc
->buttonRect
, TRUE
);
1274 UpdateWindow(lphc
->self
);
1277 /***********************************************************************
1280 static void COMBO_SetFocus( LPHEADCOMBO lphc
)
1282 if( !(lphc
->wState
& CBF_FOCUSED
) )
1284 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
1285 SendMessageW(lphc
->hWndLBox
, LB_CARETON
, 0, 0);
1287 /* This is wrong. Message sequences seem to indicate that this
1288 is set *after* the notify. */
1289 /* lphc->wState |= CBF_FOCUSED; */
1291 if( !(lphc
->wState
& CBF_EDIT
) )
1292 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1294 CB_NOTIFY( lphc
, CBN_SETFOCUS
);
1295 lphc
->wState
|= CBF_FOCUSED
;
1299 /***********************************************************************
1302 static void COMBO_KillFocus( LPHEADCOMBO lphc
)
1304 HWND hWnd
= lphc
->self
;
1306 if( lphc
->wState
& CBF_FOCUSED
)
1308 CBRollUp( lphc
, FALSE
, TRUE
);
1309 if( IsWindow( hWnd
) )
1311 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
1312 SendMessageW(lphc
->hWndLBox
, LB_CARETOFF
, 0, 0);
1314 lphc
->wState
&= ~CBF_FOCUSED
;
1317 if( !(lphc
->wState
& CBF_EDIT
) )
1318 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1320 CB_NOTIFY( lphc
, CBN_KILLFOCUS
);
1325 /***********************************************************************
1328 static LRESULT
COMBO_Command( LPHEADCOMBO lphc
, WPARAM wParam
, HWND hWnd
)
1330 if ( lphc
->wState
& CBF_EDIT
&& lphc
->hWndEdit
== hWnd
)
1332 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
1334 switch( HIWORD(wParam
) >> 8 )
1336 case (EN_SETFOCUS
>> 8):
1338 TRACE("[%04x]: edit [%04x] got focus\n",
1339 lphc
->self
, lphc
->hWndEdit
);
1341 COMBO_SetFocus( lphc
);
1344 case (EN_KILLFOCUS
>> 8):
1346 TRACE("[%04x]: edit [%04x] lost focus\n",
1347 lphc
->self
, lphc
->hWndEdit
);
1349 /* NOTE: it seems that Windows' edit control sends an
1350 * undocumented message WM_USER + 0x1B instead of this
1351 * notification (only when it happens to be a part of
1352 * the combo). ?? - AK.
1355 COMBO_KillFocus( lphc
);
1359 case (EN_CHANGE
>> 8):
1361 * In some circumstances (when the selection of the combobox
1362 * is changed for example) we don't wans the EN_CHANGE notification
1363 * to be forwarded to the parent of the combobox. This code
1364 * checks a flag that is set in these occasions and ignores the
1367 if (lphc
->wState
& CBF_NOLBSELECT
)
1369 lphc
->wState
&= ~CBF_NOLBSELECT
;
1373 CBUpdateLBox( lphc
, lphc
->wState
& CBF_DROPPED
);
1376 if (!(lphc
->wState
& CBF_NOEDITNOTIFY
))
1377 CB_NOTIFY( lphc
, CBN_EDITCHANGE
);
1380 case (EN_UPDATE
>> 8):
1381 if (!(lphc
->wState
& CBF_NOEDITNOTIFY
))
1382 CB_NOTIFY( lphc
, CBN_EDITUPDATE
);
1385 case (EN_ERRSPACE
>> 8):
1386 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
1389 else if( lphc
->hWndLBox
== hWnd
)
1391 switch( HIWORD(wParam
) )
1394 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
1398 CB_NOTIFY( lphc
, CBN_DBLCLK
);
1404 TRACE("[%04x]: lbox selection change [%04x]\n",
1405 lphc
->self
, lphc
->wState
);
1407 if( HIWORD(wParam
) == LBN_SELCHANGE
)
1409 if( lphc
->wState
& CBF_EDIT
)
1411 INT index
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1412 lphc
->wState
|= CBF_NOLBSELECT
;
1413 CBUpdateEdit( lphc
, index
);
1414 /* select text in edit, as Windows does */
1415 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1));
1418 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1421 /* do not roll up if selection is being tracked
1422 * by arrowkeys in the dropdown listbox */
1423 if( ((lphc
->wState
& CBF_DROPPED
) && !(lphc
->wState
& CBF_NOROLLUP
)) )
1425 CBRollUp( lphc
, (HIWORD(wParam
) == LBN_SELCHANGE
), TRUE
);
1427 else lphc
->wState
&= ~CBF_NOROLLUP
;
1429 CB_NOTIFY( lphc
, CBN_SELCHANGE
);
1435 /* nothing to do here since ComboLBox always resets the focus to its
1436 * combo/edit counterpart */
1443 /***********************************************************************
1446 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
1448 static LRESULT
COMBO_ItemOp( LPHEADCOMBO lphc
, UINT msg
, LPARAM lParam
)
1450 HWND hWnd
= lphc
->self
;
1451 UINT id
= GetWindowLongA( hWnd
, GWL_ID
);
1453 TRACE("[%04x]: ownerdraw op %04x\n", lphc
->self
, msg
);
1459 DELETEITEMSTRUCT
*lpIS
= (DELETEITEMSTRUCT
*)lParam
;
1460 lpIS
->CtlType
= ODT_COMBOBOX
;
1462 lpIS
->hwndItem
= hWnd
;
1467 DRAWITEMSTRUCT
*lpIS
= (DRAWITEMSTRUCT
*)lParam
;
1468 lpIS
->CtlType
= ODT_COMBOBOX
;
1470 lpIS
->hwndItem
= hWnd
;
1473 case WM_COMPAREITEM
:
1475 COMPAREITEMSTRUCT
*lpIS
= (COMPAREITEMSTRUCT
*)lParam
;
1476 lpIS
->CtlType
= ODT_COMBOBOX
;
1478 lpIS
->hwndItem
= hWnd
;
1481 case WM_MEASUREITEM
:
1483 MEASUREITEMSTRUCT
*lpIS
= (MEASUREITEMSTRUCT
*)lParam
;
1484 lpIS
->CtlType
= ODT_COMBOBOX
;
1489 return SendMessageW(lphc
->owner
, msg
, id
, lParam
);
1492 /***********************************************************************
1495 * NOTE! LB_GETTEXT does not count terminating \0, WM_GETTEXT does.
1496 * also LB_GETTEXT might return values < 0, WM_GETTEXT doesn't.
1498 static LRESULT
COMBO_GetText( LPHEADCOMBO lphc
, INT N
, LPARAM lParam
, BOOL unicode
)
1500 if( lphc
->wState
& CBF_EDIT
)
1501 return unicode
? SendMessageW(lphc
->hWndEdit
, WM_GETTEXT
, (WPARAM
)N
, lParam
) :
1502 SendMessageA(lphc
->hWndEdit
, WM_GETTEXT
, (WPARAM
)N
, lParam
);
1504 /* get it from the listbox */
1506 if( lphc
->hWndLBox
)
1508 INT idx
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1512 INT length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
,
1517 LPWSTR lpBuffer
, lpText
= (LPWSTR
)lParam
;
1519 /* 'length' is without the terminating character */
1521 lpBuffer
= HeapAlloc(GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
));
1527 n
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, (WPARAM
)idx
, (LPARAM
)lpBuffer
);
1529 /* truncate if buffer is too short */
1535 strncpyW(lpText
, lpBuffer
, (N
> n
) ? n
+1 : N
-1);
1536 lpText
[N
- 1] = '\0';
1538 HeapFree( GetProcessHeap(), 0, lpBuffer
);
1544 LPSTR lpBuffer
, lpText
= (LPSTR
)lParam
;
1546 /* 'length' is without the terminating character */
1548 lpBuffer
= HeapAlloc(GetProcessHeap(), 0, length
+ 1);
1554 n
= SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, (WPARAM
)idx
, (LPARAM
)lpBuffer
);
1556 /* truncate if buffer is too short */
1562 strncpy(lpText
, lpBuffer
, (N
> n
) ? n
+1 : N
-1);
1563 lpText
[N
- 1] = '\0';
1565 HeapFree( GetProcessHeap(), 0, lpBuffer
);
1580 /***********************************************************************
1583 * This function sets window positions according to the updated
1584 * component placement struct.
1586 static void CBResetPos(
1592 BOOL bDrop
= (CB_GETTYPE(lphc
) != CBS_SIMPLE
);
1594 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1595 * sizing messages */
1597 if( lphc
->wState
& CBF_EDIT
)
1598 SetWindowPos( lphc
->hWndEdit
, 0,
1599 rectEdit
->left
, rectEdit
->top
,
1600 rectEdit
->right
- rectEdit
->left
,
1601 rectEdit
->bottom
- rectEdit
->top
,
1602 SWP_NOZORDER
| SWP_NOACTIVATE
| ((bDrop
) ? SWP_NOREDRAW
: 0) );
1604 SetWindowPos( lphc
->hWndLBox
, 0,
1605 rectLB
->left
, rectLB
->top
,
1606 rectLB
->right
- rectLB
->left
,
1607 rectLB
->bottom
- rectLB
->top
,
1608 SWP_NOACTIVATE
| SWP_NOZORDER
| ((bDrop
) ? SWP_NOREDRAW
: 0) );
1612 if( lphc
->wState
& CBF_DROPPED
)
1614 lphc
->wState
&= ~CBF_DROPPED
;
1615 ShowWindow( lphc
->hWndLBox
, SW_HIDE
);
1618 if( bRedraw
&& !(lphc
->wState
& CBF_NOREDRAW
) )
1619 RedrawWindow( lphc
->self
, NULL
, 0,
1620 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
);
1625 /***********************************************************************
1628 static void COMBO_Size( LPHEADCOMBO lphc
)
1630 CBCalcPlacement(lphc
->self
,
1634 &lphc
->droppedRect
);
1636 CBResetPos( lphc
, &lphc
->textRect
, &lphc
->droppedRect
, TRUE
);
1640 /***********************************************************************
1643 static void COMBO_Font( LPHEADCOMBO lphc
, HFONT hFont
, BOOL bRedraw
)
1648 lphc
->hFont
= hFont
;
1651 * Propagate to owned windows.
1653 if( lphc
->wState
& CBF_EDIT
)
1654 SendMessageW(lphc
->hWndEdit
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1655 SendMessageW(lphc
->hWndLBox
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1658 * Redo the layout of the control.
1660 if ( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
1662 CBCalcPlacement(lphc
->self
,
1666 &lphc
->droppedRect
);
1668 CBResetPos( lphc
, &lphc
->textRect
, &lphc
->droppedRect
, TRUE
);
1672 CBForceDummyResize(lphc
);
1677 /***********************************************************************
1678 * COMBO_SetItemHeight
1680 static LRESULT
COMBO_SetItemHeight( LPHEADCOMBO lphc
, INT index
, INT height
)
1682 LRESULT lRet
= CB_ERR
;
1684 if( index
== -1 ) /* set text field height */
1686 if( height
< 32768 )
1688 lphc
->editHeight
= height
;
1691 * Redo the layout of the control.
1693 if ( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
1695 CBCalcPlacement(lphc
->self
,
1699 &lphc
->droppedRect
);
1701 CBResetPos( lphc
, &lphc
->textRect
, &lphc
->droppedRect
, TRUE
);
1705 CBForceDummyResize(lphc
);
1711 else if ( CB_OWNERDRAWN(lphc
) ) /* set listbox item height */
1712 lRet
= SendMessageW(lphc
->hWndLBox
, LB_SETITEMHEIGHT
,
1713 (WPARAM
)index
, (LPARAM
)height
);
1717 /***********************************************************************
1718 * COMBO_SelectString
1720 static LRESULT
COMBO_SelectString( LPHEADCOMBO lphc
, INT start
, LPARAM pText
, BOOL unicode
)
1722 INT index
= unicode
? SendMessageW(lphc
->hWndLBox
, LB_SELECTSTRING
, (WPARAM
)start
, pText
) :
1723 SendMessageA(lphc
->hWndLBox
, LB_SELECTSTRING
, (WPARAM
)start
, pText
);
1726 if( lphc
->wState
& CBF_EDIT
)
1727 CBUpdateEdit( lphc
, index
);
1730 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1733 return (LRESULT
)index
;
1736 /***********************************************************************
1739 static void COMBO_LButtonDown( LPHEADCOMBO lphc
, LPARAM lParam
)
1743 HWND hWnd
= lphc
->self
;
1745 pt
.x
= LOWORD(lParam
);
1746 pt
.y
= HIWORD(lParam
);
1747 bButton
= PtInRect(&lphc
->buttonRect
, pt
);
1749 if( (CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
) ||
1750 (bButton
&& (CB_GETTYPE(lphc
) == CBS_DROPDOWN
)) )
1752 lphc
->wState
|= CBF_BUTTONDOWN
;
1753 if( lphc
->wState
& CBF_DROPPED
)
1755 /* got a click to cancel selection */
1757 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1758 CBRollUp( lphc
, TRUE
, FALSE
);
1759 if( !IsWindow( hWnd
) ) return;
1761 if( lphc
->wState
& CBF_CAPTURE
)
1763 lphc
->wState
&= ~CBF_CAPTURE
;
1769 /* drop down the listbox and start tracking */
1771 lphc
->wState
|= CBF_CAPTURE
;
1775 if( bButton
) CBRepaintButton( lphc
);
1779 /***********************************************************************
1782 * Release capture and stop tracking if needed.
1784 static void COMBO_LButtonUp( LPHEADCOMBO lphc
)
1786 if( lphc
->wState
& CBF_CAPTURE
)
1788 lphc
->wState
&= ~CBF_CAPTURE
;
1789 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1791 INT index
= CBUpdateLBox( lphc
, TRUE
);
1792 /* Update edit only if item is in the list */
1795 lphc
->wState
|= CBF_NOLBSELECT
;
1796 CBUpdateEdit( lphc
, index
);
1797 lphc
->wState
&= ~CBF_NOLBSELECT
;
1801 SetCapture(lphc
->hWndLBox
);
1804 if( lphc
->wState
& CBF_BUTTONDOWN
)
1806 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1807 CBRepaintButton( lphc
);
1811 /***********************************************************************
1814 * Two things to do - track combo button and release capture when
1815 * pointer goes into the listbox.
1817 static void COMBO_MouseMove( LPHEADCOMBO lphc
, WPARAM wParam
, LPARAM lParam
)
1822 pt
.x
= LOWORD(lParam
);
1823 pt
.y
= HIWORD(lParam
);
1825 if( lphc
->wState
& CBF_BUTTONDOWN
)
1829 bButton
= PtInRect(&lphc
->buttonRect
, pt
);
1833 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1834 CBRepaintButton( lphc
);
1838 GetClientRect( lphc
->hWndLBox
, &lbRect
);
1839 MapWindowPoints( lphc
->self
, lphc
->hWndLBox
, &pt
, 1 );
1840 if( PtInRect(&lbRect
, pt
) )
1842 lphc
->wState
&= ~CBF_CAPTURE
;
1844 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
) CBUpdateLBox( lphc
, TRUE
);
1846 /* hand over pointer tracking */
1847 SendMessageW(lphc
->hWndLBox
, WM_LBUTTONDOWN
, wParam
, lParam
);
1852 /***********************************************************************
1853 * ComboWndProc_common
1855 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
1857 static LRESULT
ComboWndProc_common( HWND hwnd
, UINT message
,
1858 WPARAM wParam
, LPARAM lParam
, BOOL unicode
)
1860 LPHEADCOMBO lphc
= (LPHEADCOMBO
)GetWindowLongA( hwnd
, 0 );
1862 TRACE("[%04x]: msg %s wp %08x lp %08lx\n",
1863 hwnd
, SPY_GetMsgName(message
, hwnd
), wParam
, lParam
);
1865 if( lphc
|| message
== WM_NCCREATE
)
1869 /* System messages */
1873 LONG style
= unicode
? ((LPCREATESTRUCTW
)lParam
)->style
:
1874 ((LPCREATESTRUCTA
)lParam
)->style
;
1875 return COMBO_NCCreate(hwnd
, style
);
1878 COMBO_NCDestroy(lphc
);
1879 break;/* -> DefWindowProc */
1887 hwndParent
= ((LPCREATESTRUCTW
)lParam
)->hwndParent
;
1888 style
= ((LPCREATESTRUCTW
)lParam
)->style
;
1892 hwndParent
= ((LPCREATESTRUCTA
)lParam
)->hwndParent
;
1893 style
= ((LPCREATESTRUCTA
)lParam
)->style
;
1895 return COMBO_Create(hwnd
, lphc
, hwndParent
, style
);
1898 case WM_PRINTCLIENT
:
1899 if (lParam
& PRF_ERASEBKGND
)
1900 COMBO_EraseBackground(hwnd
, lphc
, wParam
);
1904 /* wParam may contain a valid HDC! */
1905 return COMBO_Paint(lphc
, wParam
);
1907 return COMBO_EraseBackground(hwnd
, lphc
, wParam
);
1910 LRESULT result
= DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1911 if (lParam
&& (((LPMSG
)lParam
)->message
== WM_KEYDOWN
))
1913 int vk
= (int)((LPMSG
)lParam
)->wParam
;
1915 if ((vk
== VK_RETURN
|| vk
== VK_ESCAPE
) && (lphc
->wState
& CBF_DROPPED
))
1916 result
|= DLGC_WANTMESSAGE
;
1920 case WM_WINDOWPOSCHANGING
:
1921 return COMBO_WindowPosChanging(hwnd
, lphc
, (LPWINDOWPOS
)lParam
);
1922 case WM_WINDOWPOSCHANGED
:
1923 /* SetWindowPos can be called on a Combobox to resize its Listbox.
1924 * In that case, the Combobox itself will not be resized, so we won't
1925 * get a WM_SIZE. Since we still want to update the Listbox, we have to
1930 if( lphc
->hWndLBox
&&
1931 !(lphc
->wState
& CBF_NORESIZE
) ) COMBO_Size( lphc
);
1934 COMBO_Font( lphc
, (HFONT16
)wParam
, (BOOL
)lParam
);
1937 return (LRESULT
)lphc
->hFont
;
1939 if( lphc
->wState
& CBF_EDIT
)
1940 SetFocus( lphc
->hWndEdit
);
1942 COMBO_SetFocus( lphc
);
1946 HWND hwndFocus
= WIN_GetFullHandle( (HWND
)wParam
);
1948 (hwndFocus
!= lphc
->hWndEdit
&& hwndFocus
!= lphc
->hWndLBox
))
1949 COMBO_KillFocus( lphc
);
1953 return COMBO_Command( lphc
, wParam
, WIN_GetFullHandle( (HWND
)lParam
) );
1955 return COMBO_GetText( lphc
, (INT
)wParam
, lParam
, unicode
);
1957 case WM_GETTEXTLENGTH
:
1959 if ((message
== WM_GETTEXTLENGTH
) && !ISWIN31
&& !(lphc
->wState
& CBF_EDIT
))
1961 int j
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1962 if (j
== -1) return 0;
1963 return SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, j
, 0);
1965 else if( lphc
->wState
& CBF_EDIT
)
1968 lphc
->wState
|= CBF_NOEDITNOTIFY
;
1969 ret
= unicode
? SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
) :
1970 SendMessageA(lphc
->hWndEdit
, message
, wParam
, lParam
);
1971 lphc
->wState
&= ~CBF_NOEDITNOTIFY
;
1978 if( lphc
->wState
& CBF_EDIT
)
1980 return unicode
? SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
) :
1981 SendMessageA(lphc
->hWndEdit
, message
, wParam
, lParam
);
1987 case WM_COMPAREITEM
:
1988 case WM_MEASUREITEM
:
1989 return COMBO_ItemOp(lphc
, message
, lParam
);
1991 if( lphc
->wState
& CBF_EDIT
)
1992 EnableWindow( lphc
->hWndEdit
, (BOOL
)wParam
);
1993 EnableWindow( lphc
->hWndLBox
, (BOOL
)wParam
);
1995 /* Force the control to repaint when the enabled state changes. */
1996 InvalidateRect(lphc
->self
, NULL
, TRUE
);
2000 lphc
->wState
&= ~CBF_NOREDRAW
;
2002 lphc
->wState
|= CBF_NOREDRAW
;
2004 if( lphc
->wState
& CBF_EDIT
)
2005 SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
);
2006 SendMessageW(lphc
->hWndLBox
, message
, wParam
, lParam
);
2009 if( KEYDATA_ALT
& HIWORD(lParam
) )
2010 if( wParam
== VK_UP
|| wParam
== VK_DOWN
)
2011 COMBO_FlipListbox( lphc
, FALSE
, FALSE
);
2019 if ((wParam
== VK_RETURN
|| wParam
== VK_ESCAPE
) &&
2020 (lphc
->wState
& CBF_DROPPED
))
2022 CBRollUp( lphc
, wParam
== VK_RETURN
, FALSE
);
2026 if( lphc
->wState
& CBF_EDIT
)
2027 hwndTarget
= lphc
->hWndEdit
;
2029 hwndTarget
= lphc
->hWndLBox
;
2031 return unicode
? SendMessageW(hwndTarget
, message
, wParam
, lParam
) :
2032 SendMessageA(hwndTarget
, message
, wParam
, lParam
);
2034 case WM_LBUTTONDOWN
:
2035 if( !(lphc
->wState
& CBF_FOCUSED
) ) SetFocus( lphc
->self
);
2036 if( lphc
->wState
& CBF_FOCUSED
) COMBO_LButtonDown( lphc
, lParam
);
2039 COMBO_LButtonUp( lphc
);
2042 if( lphc
->wState
& CBF_CAPTURE
)
2043 COMBO_MouseMove( lphc
, wParam
, lParam
);
2047 if (wParam
& (MK_SHIFT
| MK_CONTROL
))
2048 return unicode
? DefWindowProcW(hwnd
, message
, wParam
, lParam
) :
2049 DefWindowProcA(hwnd
, message
, wParam
, lParam
);
2050 if (SHIWORD(wParam
) > 0) return SendMessageW(hwnd
, WM_KEYDOWN
, VK_UP
, 0);
2051 if (SHIWORD(wParam
) < 0) return SendMessageW(hwnd
, WM_KEYDOWN
, VK_DOWN
, 0);
2054 /* Combo messages */
2056 case CB_ADDSTRING16
:
2057 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2060 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_ADDSTRING
, 0, lParam
) :
2061 SendMessageA(lphc
->hWndLBox
, LB_ADDSTRING
, 0, lParam
);
2062 case CB_INSERTSTRING16
:
2063 wParam
= (INT
)(INT16
)wParam
;
2064 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2066 case CB_INSERTSTRING
:
2067 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_INSERTSTRING
, wParam
, lParam
) :
2068 SendMessageA(lphc
->hWndLBox
, LB_INSERTSTRING
, wParam
, lParam
);
2069 case CB_DELETESTRING16
:
2070 case CB_DELETESTRING
:
2071 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_DELETESTRING
, wParam
, 0) :
2072 SendMessageA(lphc
->hWndLBox
, LB_DELETESTRING
, wParam
, 0);
2073 case CB_SELECTSTRING16
:
2074 wParam
= (INT
)(INT16
)wParam
;
2075 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2077 case CB_SELECTSTRING
:
2078 return COMBO_SelectString(lphc
, (INT
)wParam
, lParam
, unicode
);
2079 case CB_FINDSTRING16
:
2080 wParam
= (INT
)(INT16
)wParam
;
2081 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2084 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_FINDSTRING
, wParam
, lParam
) :
2085 SendMessageA(lphc
->hWndLBox
, LB_FINDSTRING
, wParam
, lParam
);
2086 case CB_FINDSTRINGEXACT16
:
2087 wParam
= (INT
)(INT16
)wParam
;
2088 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2090 case CB_FINDSTRINGEXACT
:
2091 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_FINDSTRINGEXACT
, wParam
, lParam
) :
2092 SendMessageA(lphc
->hWndLBox
, LB_FINDSTRINGEXACT
, wParam
, lParam
);
2093 case CB_SETITEMHEIGHT16
:
2094 wParam
= (INT
)(INT16
)wParam
; /* signed integer */
2096 case CB_SETITEMHEIGHT
:
2097 return COMBO_SetItemHeight( lphc
, (INT
)wParam
, (INT
)lParam
);
2098 case CB_GETITEMHEIGHT16
:
2099 wParam
= (INT
)(INT16
)wParam
;
2101 case CB_GETITEMHEIGHT
:
2102 if( (INT
)wParam
>= 0 ) /* listbox item */
2103 return SendMessageW(lphc
->hWndLBox
, LB_GETITEMHEIGHT
, wParam
, 0);
2104 return CBGetTextAreaHeight(hwnd
, lphc
);
2105 case CB_RESETCONTENT16
:
2106 case CB_RESETCONTENT
:
2107 SendMessageW(lphc
->hWndLBox
, LB_RESETCONTENT
, 0, 0);
2108 if( (lphc
->wState
& CBF_EDIT
) && CB_HASSTRINGS(lphc
) )
2110 static const WCHAR empty_stringW
[] = { 0 };
2111 SendMessageW(lphc
->hWndEdit
, WM_SETTEXT
, 0, (LPARAM
)empty_stringW
);
2114 InvalidateRect(lphc
->self
, NULL
, TRUE
);
2116 case CB_INITSTORAGE
:
2117 return SendMessageW(lphc
->hWndLBox
, LB_INITSTORAGE
, wParam
, lParam
);
2118 case CB_GETHORIZONTALEXTENT
:
2119 return SendMessageW(lphc
->hWndLBox
, LB_GETHORIZONTALEXTENT
, 0, 0);
2120 case CB_SETHORIZONTALEXTENT
:
2121 return SendMessageW(lphc
->hWndLBox
, LB_SETHORIZONTALEXTENT
, wParam
, 0);
2122 case CB_GETTOPINDEX
:
2123 return SendMessageW(lphc
->hWndLBox
, LB_GETTOPINDEX
, 0, 0);
2125 return SendMessageW(lphc
->hWndLBox
, LB_GETLOCALE
, 0, 0);
2127 return SendMessageW(lphc
->hWndLBox
, LB_SETLOCALE
, wParam
, 0);
2128 case CB_GETDROPPEDWIDTH
:
2129 if( lphc
->droppedWidth
)
2130 return lphc
->droppedWidth
;
2131 return lphc
->droppedRect
.right
- lphc
->droppedRect
.left
;
2132 case CB_SETDROPPEDWIDTH
:
2133 if( (CB_GETTYPE(lphc
) != CBS_SIMPLE
) &&
2134 (INT
)wParam
< 32768 ) lphc
->droppedWidth
= (INT
)wParam
;
2136 case CB_GETDROPPEDCONTROLRECT16
:
2137 lParam
= (LPARAM
)MapSL(lParam
);
2141 CBGetDroppedControlRect( lphc
, &r
);
2142 CONV_RECT32TO16( &r
, (LPRECT16
)lParam
);
2145 case CB_GETDROPPEDCONTROLRECT
:
2146 if( lParam
) CBGetDroppedControlRect(lphc
, (LPRECT
)lParam
);
2148 case CB_GETDROPPEDSTATE16
:
2149 case CB_GETDROPPEDSTATE
:
2150 return (lphc
->wState
& CBF_DROPPED
) ? TRUE
: FALSE
;
2152 lParam
= (LPARAM
)MapSL(lParam
);
2156 if(message
== CB_DIR
) message
= LB_DIR
;
2157 return unicode
? SendMessageW(lphc
->hWndLBox
, message
, wParam
, lParam
) :
2158 SendMessageA(lphc
->hWndLBox
, message
, wParam
, lParam
);
2160 case CB_SHOWDROPDOWN16
:
2161 case CB_SHOWDROPDOWN
:
2162 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
2166 if( !(lphc
->wState
& CBF_DROPPED
) )
2170 if( lphc
->wState
& CBF_DROPPED
)
2171 CBRollUp( lphc
, FALSE
, TRUE
);
2176 return SendMessageW(lphc
->hWndLBox
, LB_GETCOUNT
, 0, 0);
2177 case CB_GETCURSEL16
:
2179 return SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
2180 case CB_SETCURSEL16
:
2181 wParam
= (INT
)(INT16
)wParam
;
2184 lParam
= SendMessageW(lphc
->hWndLBox
, LB_SETCURSEL
, wParam
, 0);
2186 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
, wParam
, 0);
2188 /* no LBN_SELCHANGE in this case, update manually */
2189 if( lphc
->wState
& CBF_EDIT
)
2190 CBUpdateEdit( lphc
, (INT
)wParam
);
2192 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
2193 lphc
->wState
&= ~CBF_SELCHANGE
;
2195 case CB_GETLBTEXT16
:
2196 wParam
= (INT
)(INT16
)wParam
;
2197 lParam
= (LPARAM
)MapSL(lParam
);
2200 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, wParam
, lParam
) :
2201 SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, wParam
, lParam
);
2202 case CB_GETLBTEXTLEN16
:
2203 wParam
= (INT
)(INT16
)wParam
;
2205 case CB_GETLBTEXTLEN
:
2206 return SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, wParam
, 0);
2207 case CB_GETITEMDATA16
:
2208 wParam
= (INT
)(INT16
)wParam
;
2210 case CB_GETITEMDATA
:
2211 return SendMessageW(lphc
->hWndLBox
, LB_GETITEMDATA
, wParam
, 0);
2212 case CB_SETITEMDATA16
:
2213 wParam
= (INT
)(INT16
)wParam
;
2215 case CB_SETITEMDATA
:
2216 return SendMessageW(lphc
->hWndLBox
, LB_SETITEMDATA
, wParam
, lParam
);
2217 case CB_GETEDITSEL16
:
2218 wParam
= lParam
= 0; /* just in case */
2221 /* Edit checks passed parameters itself */
2222 if( lphc
->wState
& CBF_EDIT
)
2223 return SendMessageW(lphc
->hWndEdit
, EM_GETSEL
, wParam
, lParam
);
2225 case CB_SETEDITSEL16
:
2227 if( lphc
->wState
& CBF_EDIT
)
2228 return SendMessageW(lphc
->hWndEdit
, EM_SETSEL
,
2229 (INT
)(INT16
)LOWORD(lParam
), (INT
)(INT16
)HIWORD(lParam
) );
2231 case CB_SETEXTENDEDUI16
:
2232 case CB_SETEXTENDEDUI
:
2233 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
2236 lphc
->wState
|= CBF_EUI
;
2237 else lphc
->wState
&= ~CBF_EUI
;
2239 case CB_GETEXTENDEDUI16
:
2240 case CB_GETEXTENDEDUI
:
2241 return (lphc
->wState
& CBF_EUI
) ? TRUE
: FALSE
;
2244 if (message
>= WM_USER
)
2245 WARN("unknown msg WM_USER+%04x wp=%04x lp=%08lx\n",
2246 message
- WM_USER
, wParam
, lParam
);
2249 return unicode
? DefWindowProcW(hwnd
, message
, wParam
, lParam
) :
2250 DefWindowProcA(hwnd
, message
, wParam
, lParam
);
2253 /***********************************************************************
2256 * This is just a wrapper for the real ComboWndProc which locks/unlocks
2259 static LRESULT WINAPI
ComboWndProcA( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2261 if (!IsWindow(hwnd
)) return 0;
2262 return ComboWndProc_common( hwnd
, message
, wParam
, lParam
, FALSE
);
2265 /***********************************************************************
2268 static LRESULT WINAPI
ComboWndProcW( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2270 if (!IsWindow(hwnd
)) return 0;
2271 return ComboWndProc_common( hwnd
, message
, wParam
, lParam
, TRUE
);