4 * Copyright 1997 Alex Korobka
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * FIXME: roll up in Netscape 3.01.
32 #include "user32/regcontrol.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(combo
);
37 /* bits in the dwKeyData */
38 #define KEYDATA_ALT 0x2000
39 #define KEYDATA_PREVSTATE 0x4000
42 * Additional combo box definitions
45 #define CB_NOTIFY( lphc, code ) \
46 (SendMessageW((lphc)->owner, WM_COMMAND, \
47 MAKEWPARAM(GetWindowLongA((lphc)->self,GWL_ID), (code)), (LPARAM)(lphc)->self))
49 #define CB_DISABLED( lphc ) (!IsWindowEnabled((lphc)->self))
50 #define CB_OWNERDRAWN( lphc ) ((lphc)->dwStyle & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE))
51 #define CB_HASSTRINGS( lphc ) ((lphc)->dwStyle & CBS_HASSTRINGS)
52 #define CB_HWND( lphc ) ((lphc)->self)
54 #define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
59 static HBITMAP hComboBmp
= 0;
60 static UINT CBitHeight
, CBitWidth
;
63 * Look and feel dependent "constants"
66 #define COMBO_YBORDERGAP 5
67 #define COMBO_XBORDERSIZE() ( (TWEAK_WineLook == WIN31_LOOK) ? 0 : 2 )
68 #define COMBO_YBORDERSIZE() ( (TWEAK_WineLook == WIN31_LOOK) ? 0 : 2 )
69 #define COMBO_EDITBUTTONSPACE() ( (TWEAK_WineLook == WIN31_LOOK) ? 8 : 0 )
70 #define EDIT_CONTROL_PADDING() ( (TWEAK_WineLook == WIN31_LOOK) ? 0 : 1 )
71 #else /* __REACTOS__ */
72 #define COMBO_YBORDERGAP 5
73 #define COMBO_XBORDERSIZE() ( 2 )
74 #define COMBO_YBORDERSIZE() ( 2 )
75 #define COMBO_EDITBUTTONSPACE() ( 0 )
76 #define EDIT_CONTROL_PADDING() ( 1 )
77 #endif /* __REACTOS__ */
79 static LRESULT WINAPI
ComboWndProcA( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
80 static LRESULT WINAPI
ComboWndProcW( HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
82 /*********************************************************************
83 * combo class descriptor
85 const struct builtin_class_descr COMBO_builtin_class
=
87 L
"ComboBox", /* name */
88 CS_GLOBALCLASS
| CS_PARENTDC
| CS_DBLCLKS
, /* style */
89 (WNDPROC
) ComboWndProcW
, /* procW */
90 (WNDPROC
) ComboWndProcA
, /* procA */
91 sizeof(HEADCOMBO
*), /* extra */
92 (LPCWSTR
) IDC_ARROW
, /* cursor */
97 /***********************************************************************
100 * Load combo button bitmap.
102 static BOOL
COMBO_Init()
106 if( hComboBmp
) return TRUE
;
107 if( (hDC
= CreateCompatibleDC(0)) )
110 if( (hComboBmp
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_COMBO
))) )
116 GetObjectW( hComboBmp
, sizeof(bm
), &bm
);
117 CBitHeight
= bm
.bmHeight
;
118 CBitWidth
= bm
.bmWidth
;
120 TRACE("combo bitmap [%i,%i]\n", CBitWidth
, CBitHeight
);
122 hPrevB
= SelectObject( hDC
, hComboBmp
);
123 SetRect( &r
, 0, 0, CBitWidth
, CBitHeight
);
124 InvertRect( hDC
, &r
);
125 SelectObject( hDC
, hPrevB
);
134 /***********************************************************************
137 static LRESULT
COMBO_NCCreate(HWND hwnd
, LONG style
)
141 if (COMBO_Init() && (lphc
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HEADCOMBO
))) )
144 SetWindowLongA( hwnd
, 0, (LONG
)lphc
);
146 /* some braindead apps do try to use scrollbar/border flags */
148 lphc
->dwStyle
= style
& ~(WS_BORDER
| WS_HSCROLL
| WS_VSCROLL
);
149 SetWindowLongA( hwnd
, GWL_STYLE
, style
& ~(WS_BORDER
| WS_HSCROLL
| WS_VSCROLL
) );
152 * We also have to remove the client edge style to make sure
153 * we don't end-up with a non client area.
155 SetWindowLongA( hwnd
, GWL_EXSTYLE
,
156 GetWindowLongA( hwnd
, GWL_EXSTYLE
) & ~WS_EX_CLIENTEDGE
);
158 if( !(style
& (CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
)) )
159 lphc
->dwStyle
|= CBS_HASSTRINGS
;
160 if( !(GetWindowLongA( hwnd
, GWL_EXSTYLE
) & WS_EX_NOPARENTNOTIFY
) )
161 lphc
->wState
|= CBF_NOTIFY
;
163 TRACE("[%p], style = %08x\n", lphc
, lphc
->dwStyle
);
169 /***********************************************************************
172 static LRESULT
COMBO_NCDestroy( LPHEADCOMBO lphc
)
177 TRACE("[%p]: freeing storage\n", lphc
->self
);
179 if( (CB_GETTYPE(lphc
) != CBS_SIMPLE
) && lphc
->hWndLBox
)
180 DestroyWindow( lphc
->hWndLBox
);
182 SetWindowLongA( lphc
->self
, 0, 0 );
183 HeapFree( GetProcessHeap(), 0, lphc
);
188 /***********************************************************************
189 * CBGetTextAreaHeight
191 * This method will calculate the height of the text area of the
193 * The height of the text area is set in two ways.
194 * It can be set explicitly through a combobox message or through a
195 * WM_MEASUREITEM callback.
196 * If this is not the case, the height is set to 13 dialog units.
197 * This height was determined through experimentation.
199 static INT
CBGetTextAreaHeight(
205 if( lphc
->editHeight
) /* explicitly set height */
207 iTextItemHeight
= lphc
->editHeight
;
212 HDC hDC
= GetDC(hwnd
);
217 hPrevFont
= SelectObject( hDC
, lphc
->hFont
);
219 GetTextMetricsW(hDC
, &tm
);
221 baseUnitY
= tm
.tmHeight
;
224 SelectObject( hDC
, hPrevFont
);
226 ReleaseDC(hwnd
, hDC
);
228 iTextItemHeight
= ((13 * baseUnitY
) / 8);
231 * This "formula" calculates the height of the complete control.
232 * To calculate the height of the text area, we have to remove the
235 iTextItemHeight
-= 2*COMBO_YBORDERSIZE();
239 * Check the ownerdraw case if we haven't asked the parent the size
242 if ( CB_OWNERDRAWN(lphc
) &&
243 (lphc
->wState
& CBF_MEASUREITEM
) )
245 MEASUREITEMSTRUCT measureItem
;
247 INT originalItemHeight
= iTextItemHeight
;
248 UINT id
= GetWindowLongA( lphc
->self
, GWL_ID
);
251 * We use the client rect for the width of the item.
253 GetClientRect(hwnd
, &clientRect
);
255 lphc
->wState
&= ~CBF_MEASUREITEM
;
258 * Send a first one to measure the size of the text area
260 measureItem
.CtlType
= ODT_COMBOBOX
;
261 measureItem
.CtlID
= id
;
262 measureItem
.itemID
= -1;
263 measureItem
.itemWidth
= clientRect
.right
;
264 measureItem
.itemHeight
= iTextItemHeight
- 6; /* ownerdrawn cb is taller */
265 measureItem
.itemData
= 0;
266 SendMessageW(lphc
->owner
, WM_MEASUREITEM
, id
, (LPARAM
)&measureItem
);
267 iTextItemHeight
= 6 + measureItem
.itemHeight
;
270 * Send a second one in the case of a fixed ownerdraw list to calculate the
271 * size of the list items. (we basically do this on behalf of the listbox)
273 if (lphc
->dwStyle
& CBS_OWNERDRAWFIXED
)
275 measureItem
.CtlType
= ODT_COMBOBOX
;
276 measureItem
.CtlID
= id
;
277 measureItem
.itemID
= 0;
278 measureItem
.itemWidth
= clientRect
.right
;
279 measureItem
.itemHeight
= originalItemHeight
;
280 measureItem
.itemData
= 0;
281 SendMessageW(lphc
->owner
, WM_MEASUREITEM
, id
, (LPARAM
)&measureItem
);
282 lphc
->fixedOwnerDrawHeight
= measureItem
.itemHeight
;
286 * Keep the size for the next time
288 lphc
->editHeight
= iTextItemHeight
;
291 return iTextItemHeight
;
294 /***********************************************************************
297 * The dummy resize is used for listboxes that have a popup to trigger
298 * a re-arranging of the contents of the combobox and the recalculation
299 * of the size of the "real" control window.
301 static void CBForceDummyResize(
307 newComboHeight
= CBGetTextAreaHeight(lphc
->self
,lphc
) + 2*COMBO_YBORDERSIZE();
309 GetWindowRect(lphc
->self
, &windowRect
);
312 * We have to be careful, resizing a combobox also has the meaning that the
313 * dropped rect will be resized. In this case, we want to trigger a resize
314 * to recalculate layout but we don't want to change the dropped rectangle
315 * So, we pass the height of text area of control as the height.
316 * this will cancel-out in the processing of the WM_WINDOWPOSCHANGING
319 SetWindowPos( lphc
->self
,
322 windowRect
.right
- windowRect
.left
,
324 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
327 /***********************************************************************
330 * Set up component coordinates given valid lphc->RectCombo.
332 static void CBCalcPlacement(
340 * Again, start with the client rectangle.
342 GetClientRect(hwnd
, lprEdit
);
347 InflateRect(lprEdit
, -COMBO_XBORDERSIZE(), -COMBO_YBORDERSIZE());
350 * Chop off the bottom part to fit with the height of the text area.
352 lprEdit
->bottom
= lprEdit
->top
+ CBGetTextAreaHeight(hwnd
, lphc
);
355 * The button starts the same vertical position as the text area.
357 CopyRect(lprButton
, lprEdit
);
360 * If the combobox is "simple" there is no button.
362 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
363 lprButton
->left
= lprButton
->right
= lprButton
->bottom
= 0;
367 * Let's assume the combobox button is the same width as the
369 * size the button horizontally and cut-off the text area.
371 lprButton
->left
= lprButton
->right
- GetSystemMetrics(SM_CXVSCROLL
);
372 lprEdit
->right
= lprButton
->left
;
376 * In the case of a dropdown, there is an additional spacing between the
377 * text area and the button.
379 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
381 lprEdit
->right
-= COMBO_EDITBUTTONSPACE();
385 * If we have an edit control, we space it away from the borders slightly.
387 if (CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
)
389 InflateRect(lprEdit
, -EDIT_CONTROL_PADDING(), -EDIT_CONTROL_PADDING());
393 * Adjust the size of the listbox popup.
395 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
398 * Use the client rectangle to initialize the listbox rectangle
400 GetClientRect(hwnd
, lprLB
);
403 * Then, chop-off the top part.
405 lprLB
->top
= lprEdit
->bottom
+ COMBO_YBORDERSIZE();
410 * Make sure the dropped width is as large as the combobox itself.
412 if (lphc
->droppedWidth
< (lprButton
->right
+ COMBO_XBORDERSIZE()))
414 lprLB
->right
= lprLB
->left
+ (lprButton
->right
+ COMBO_XBORDERSIZE());
417 * In the case of a dropdown, the popup listbox is offset to the right.
418 * so, we want to make sure it's flush with the right side of the
421 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
422 lprLB
->right
-= COMBO_EDITBUTTONSPACE();
425 lprLB
->right
= lprLB
->left
+ lphc
->droppedWidth
;
428 TRACE("\ttext\t= (%ld,%ld-%ld,%ld)\n",
429 lprEdit
->left
, lprEdit
->top
, lprEdit
->right
, lprEdit
->bottom
);
431 TRACE("\tbutton\t= (%ld,%ld-%ld,%ld)\n",
432 lprButton
->left
, lprButton
->top
, lprButton
->right
, lprButton
->bottom
);
434 TRACE("\tlbox\t= (%ld,%ld-%ld,%ld)\n",
435 lprLB
->left
, lprLB
->top
, lprLB
->right
, lprLB
->bottom
);
438 /***********************************************************************
439 * CBGetDroppedControlRect
441 static void CBGetDroppedControlRect( LPHEADCOMBO lphc
, LPRECT lpRect
)
443 /* In windows, CB_GETDROPPEDCONTROLRECT returns the upper left corner
444 of the combo box and the lower right corner of the listbox */
446 GetWindowRect(lphc
->self
, lpRect
);
448 lpRect
->right
= lpRect
->left
+ lphc
->droppedRect
.right
- lphc
->droppedRect
.left
;
449 lpRect
->bottom
= lpRect
->top
+ lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
;
453 /***********************************************************************
454 * COMBO_WindowPosChanging
456 static LRESULT
COMBO_WindowPosChanging(
459 WINDOWPOS
* posChanging
)
462 * We need to override the WM_WINDOWPOSCHANGING method to handle all
463 * the non-simple comboboxes. The problem is that those controls are
464 * always the same height. We have to make sure they are not resized
467 if ( ( CB_GETTYPE(lphc
) != CBS_SIMPLE
) &&
468 ((posChanging
->flags
& SWP_NOSIZE
) == 0) )
472 newComboHeight
= CBGetTextAreaHeight(hwnd
,lphc
) +
473 2*COMBO_YBORDERSIZE();
476 * Resizing a combobox has another side effect, it resizes the dropped
477 * rectangle as well. However, it does it only if the new height for the
478 * combobox is different from the height it should have. In other words,
479 * if the application resizing the combobox only had the intention to resize
480 * the actual control, for example, to do the layout of a dialog that is
481 * resized, the height of the dropdown is not changed.
483 if (posChanging
->cy
!= newComboHeight
)
485 TRACE("posChanging->cy=%d, newComboHeight=%d, oldbot=%ld, oldtop=%ld\n",
486 posChanging
->cy
, newComboHeight
, lphc
->droppedRect
.bottom
,
487 lphc
->droppedRect
.top
);
488 lphc
->droppedRect
.bottom
= lphc
->droppedRect
.top
+ posChanging
->cy
- newComboHeight
;
490 posChanging
->cy
= newComboHeight
;
494 posChanging
->cx
= max(posChanging
->cx
, 0);
495 posChanging
->cy
= max(posChanging
->cy
, 0);
500 /***********************************************************************
503 static LRESULT
COMBO_Create( HWND hwnd
, LPHEADCOMBO lphc
, HWND hwndParent
, LONG style
,
506 static const WCHAR clbName
[] = {'C','o','m','b','o','L','B','o','x',0};
507 static const WCHAR editName
[] = {'E','d','i','t',0};
509 if( !CB_GETTYPE(lphc
) ) lphc
->dwStyle
|= CBS_SIMPLE
;
510 if( CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
) lphc
->wState
|= CBF_EDIT
;
512 lphc
->owner
= hwndParent
;
515 * The item height and dropped width are not set when the control
518 lphc
->droppedWidth
= lphc
->editHeight
= 0;
521 * The first time we go through, we want to measure the ownerdraw item
523 lphc
->wState
|= CBF_MEASUREITEM
;
525 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
527 if( lphc
->owner
|| !(style
& WS_VISIBLE
) )
533 * Initialize the dropped rect to the size of the client area of the
534 * control and then, force all the areas of the combobox to be
537 GetClientRect( hwnd
, &lphc
->droppedRect
);
538 CBCalcPlacement(hwnd
, lphc
, &lphc
->textRect
, &lphc
->buttonRect
, &lphc
->droppedRect
);
541 * Adjust the position of the popup listbox if it's necessary
543 if ( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
545 lphc
->droppedRect
.top
= lphc
->textRect
.bottom
+ COMBO_YBORDERSIZE();
548 * If it's a dropdown, the listbox is offset
550 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
551 lphc
->droppedRect
.left
+= COMBO_EDITBUTTONSPACE();
553 ClientToScreen(hwnd
, (LPPOINT
)&lphc
->droppedRect
);
554 ClientToScreen(hwnd
, (LPPOINT
)&lphc
->droppedRect
.right
);
557 /* create listbox popup */
559 lbeStyle
= (LBS_NOTIFY
| WS_BORDER
| WS_CLIPSIBLINGS
| WS_CHILD
) |
560 (style
& (WS_VSCROLL
| CBS_OWNERDRAWFIXED
| CBS_OWNERDRAWVARIABLE
));
562 if( lphc
->dwStyle
& CBS_SORT
)
563 lbeStyle
|= LBS_SORT
;
564 if( lphc
->dwStyle
& CBS_HASSTRINGS
)
565 lbeStyle
|= LBS_HASSTRINGS
;
566 if( lphc
->dwStyle
& CBS_NOINTEGRALHEIGHT
)
567 lbeStyle
|= LBS_NOINTEGRALHEIGHT
;
568 if( lphc
->dwStyle
& CBS_DISABLENOSCROLL
)
569 lbeStyle
|= LBS_DISABLENOSCROLL
;
571 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
) /* child listbox */
573 lbeStyle
|= WS_VISIBLE
;
576 * In win 95 look n feel, the listbox in the simple combobox has
577 * the WS_EXCLIENTEDGE style instead of the WS_BORDER style.
580 if (TWEAK_WineLook
> WIN31_LOOK
)
581 #endif /* __REACTOS__ */
583 lbeStyle
&= ~WS_BORDER
;
584 lbeExStyle
|= WS_EX_CLIENTEDGE
;
589 lphc
->hWndLBox
= CreateWindowExW(lbeExStyle
, clbName
, NULL
, lbeStyle
,
590 lphc
->droppedRect
.left
,
591 lphc
->droppedRect
.top
,
592 lphc
->droppedRect
.right
- lphc
->droppedRect
.left
,
593 lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
,
594 hwnd
, (HMENU
)ID_CB_LISTBOX
,
595 (HINSTANCE
)GetWindowLongA( hwnd
, GWL_HINSTANCE
), lphc
);
597 lphc
->hWndLBox
= CreateWindowExA(lbeExStyle
, "ComboLBox", NULL
, lbeStyle
,
598 lphc
->droppedRect
.left
,
599 lphc
->droppedRect
.top
,
600 lphc
->droppedRect
.right
- lphc
->droppedRect
.left
,
601 lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
,
602 hwnd
, (HMENU
)ID_CB_LISTBOX
,
603 (HINSTANCE
)GetWindowLongA( hwnd
, GWL_HINSTANCE
), lphc
);
608 lbeStyle
= WS_CHILD
| WS_VISIBLE
| ES_NOHIDESEL
| ES_LEFT
| ES_COMBO
;
611 * In Win95 look, the border fo the edit control is
612 * provided by the combobox
615 if (TWEAK_WineLook
== WIN31_LOOK
)
616 lbeStyle
|= WS_BORDER
;
617 #endif /* __REACTOS__ */
618 if( lphc
->wState
& CBF_EDIT
)
620 if( lphc
->dwStyle
& CBS_OEMCONVERT
)
621 lbeStyle
|= ES_OEMCONVERT
;
622 if( lphc
->dwStyle
& CBS_AUTOHSCROLL
)
623 lbeStyle
|= ES_AUTOHSCROLL
;
624 if( lphc
->dwStyle
& CBS_LOWERCASE
)
625 lbeStyle
|= ES_LOWERCASE
;
626 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
627 lbeStyle
|= ES_UPPERCASE
;
629 if (!IsWindowEnabled(hwnd
)) lbeStyle
|= WS_DISABLED
;
632 lphc
->hWndEdit
= CreateWindowExW(0, editName
, NULL
, lbeStyle
,
633 lphc
->textRect
.left
, lphc
->textRect
.top
,
634 lphc
->textRect
.right
- lphc
->textRect
.left
,
635 lphc
->textRect
.bottom
- lphc
->textRect
.top
,
636 hwnd
, (HMENU
)ID_CB_EDIT
,
637 (HINSTANCE
)GetWindowLongA( hwnd
, GWL_HINSTANCE
), NULL
);
639 lphc
->hWndEdit
= CreateWindowExA(0, "Edit", NULL
, lbeStyle
,
640 lphc
->textRect
.left
, lphc
->textRect
.top
,
641 lphc
->textRect
.right
- lphc
->textRect
.left
,
642 lphc
->textRect
.bottom
- lphc
->textRect
.top
,
643 hwnd
, (HMENU
)ID_CB_EDIT
,
644 (HINSTANCE
)GetWindowLongA( hwnd
, GWL_HINSTANCE
), NULL
);
646 if( !lphc
->hWndEdit
)
652 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
654 /* Now do the trick with parent */
655 SetParent(lphc
->hWndLBox
, HWND_DESKTOP
);
657 * If the combo is a dropdown, we must resize the control
658 * to fit only the text area and button. To do this,
659 * we send a dummy resize and the WM_WINDOWPOSCHANGING message
660 * will take care of setting the height for us.
662 CBForceDummyResize(lphc
);
665 TRACE("init done\n");
668 ERR("edit control failure.\n");
669 } else ERR("listbox failure.\n");
670 } else ERR("no owner for visible combo.\n");
672 /* CreateWindow() will send WM_NCDESTROY to cleanup */
677 /***********************************************************************
680 * Paint combo button (normal, pressed, and disabled states).
682 static void CBPaintButton(
687 if( lphc
->wState
& CBF_NOREDRAW
)
690 if (TWEAK_WineLook
== WIN31_LOOK
)
696 COLORREF oldTextColor
, oldBkColor
;
699 hPrevBrush
= SelectObject(hdc
, GetSysColorBrush(COLOR_BTNFACE
));
702 * Draw the button background
707 rectButton
.right
-rectButton
.left
,
708 rectButton
.bottom
-rectButton
.top
,
711 if( (bBool
= lphc
->wState
& CBF_BUTTONDOWN
) )
713 DrawEdge( hdc
, &rectButton
, EDGE_SUNKEN
, BF_RECT
);
717 DrawEdge( hdc
, &rectButton
, EDGE_RAISED
, BF_RECT
);
721 * Remove the edge of the button from the rectangle
722 * and calculate the position of the bitmap.
724 InflateRect( &rectButton
, -2, -2);
726 x
= (rectButton
.left
+ rectButton
.right
- CBitWidth
) >> 1;
727 y
= (rectButton
.top
+ rectButton
.bottom
- CBitHeight
) >> 1;
730 hMemDC
= CreateCompatibleDC( hdc
);
731 SelectObject( hMemDC
, hComboBmp
);
732 oldTextColor
= SetTextColor( hdc
, GetSysColor(COLOR_BTNFACE
) );
733 oldBkColor
= SetBkColor( hdc
, CB_DISABLED(lphc
) ? RGB(128,128,128) :
735 BitBlt( hdc
, x
, y
, CBitWidth
, CBitHeight
, hMemDC
, 0, 0, SRCCOPY
);
736 SetBkColor( hdc
, oldBkColor
);
737 SetTextColor( hdc
, oldTextColor
);
739 SelectObject( hdc
, hPrevBrush
);
742 #endif /* __REACTOS__ */
744 UINT buttonState
= DFCS_SCROLLCOMBOBOX
;
746 if (lphc
->wState
& CBF_BUTTONDOWN
)
748 buttonState
|= DFCS_PUSHED
;
751 if (CB_DISABLED(lphc
))
753 buttonState
|= DFCS_INACTIVE
;
756 DrawFrameControl(hdc
,
763 /***********************************************************************
766 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
768 static void CBPaintText(
776 if( lphc
->wState
& CBF_NOREDRAW
) return;
780 /* follow Windows combobox that sends a bunch of text
781 * inquiries to its listbox while processing WM_PAINT. */
783 if( (id
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0) ) != LB_ERR
)
785 size
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, id
, 0);
787 FIXME("LB_ERR probably not handled yet\n");
788 if( (pText
= HeapAlloc( GetProcessHeap(), 0, (size
+ 1) * sizeof(WCHAR
))) )
790 /* size from LB_GETTEXTLEN may be too large, from LB_GETTEXT is accurate */
791 size
=SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, (WPARAM
)id
, (LPARAM
)pText
);
792 pText
[size
] = '\0'; /* just in case */
796 if( !CB_OWNERDRAWN(lphc
) )
799 if( lphc
->wState
& CBF_EDIT
)
801 static const WCHAR empty_stringW
[] = { 0 };
802 if( CB_HASSTRINGS(lphc
) ) SetWindowTextW( lphc
->hWndEdit
, pText
? pText
: empty_stringW
);
803 if( lphc
->wState
& CBF_FOCUSED
)
804 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1));
806 else /* paint text field ourselves */
808 UINT itemState
= ODS_COMBOBOXEDIT
;
809 HFONT hPrevFont
= (lphc
->hFont
) ? SelectObject(hdc
, lphc
->hFont
) : 0;
812 * Give ourselves some space.
814 InflateRect( &rectEdit
, -1, -1 );
816 if( CB_OWNERDRAWN(lphc
) )
820 UINT ctlid
= GetWindowLongA( lphc
->self
, GWL_ID
);
822 /* setup state for DRAWITEM message. Owner will highlight */
823 if ( (lphc
->wState
& CBF_FOCUSED
) &&
824 !(lphc
->wState
& CBF_DROPPED
) )
825 itemState
|= ODS_SELECTED
| ODS_FOCUS
;
828 * Save the current clip region.
829 * To retrieve the clip region, we need to create one "dummy"
832 clipRegion
= CreateRectRgnIndirect(&rectEdit
);
834 if (GetClipRgn(hdc
, clipRegion
)!=1)
836 DeleteObject(clipRegion
);
840 if (!IsWindowEnabled(lphc
->self
) & WS_DISABLED
) itemState
|= ODS_DISABLED
;
842 dis
.CtlType
= ODT_COMBOBOX
;
844 dis
.hwndItem
= lphc
->self
;
845 dis
.itemAction
= ODA_DRAWENTIRE
;
847 dis
.itemState
= itemState
;
849 dis
.rcItem
= rectEdit
;
850 dis
.itemData
= SendMessageW(lphc
->hWndLBox
, LB_GETITEMDATA
,
854 * Clip the DC and have the parent draw the item.
856 IntersectClipRect(hdc
,
857 rectEdit
.left
, rectEdit
.top
,
858 rectEdit
.right
, rectEdit
.bottom
);
860 SendMessageW(lphc
->owner
, WM_DRAWITEM
, ctlid
, (LPARAM
)&dis
);
863 * Reset the clipping region.
865 SelectClipRgn(hdc
, clipRegion
);
869 static const WCHAR empty_stringW
[] = { 0 };
871 if ( (lphc
->wState
& CBF_FOCUSED
) &&
872 !(lphc
->wState
& CBF_DROPPED
) ) {
875 FillRect( hdc
, &rectEdit
, GetSysColorBrush(COLOR_HIGHLIGHT
) );
876 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
877 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
883 ETO_OPAQUE
| ETO_CLIPPED
,
885 pText
? pText
: empty_stringW
, size
, NULL
);
887 if(lphc
->wState
& CBF_FOCUSED
&& !(lphc
->wState
& CBF_DROPPED
))
888 DrawFocusRect( hdc
, &rectEdit
);
892 SelectObject(hdc
, hPrevFont
);
895 HeapFree( GetProcessHeap(), 0, pText
);
898 /***********************************************************************
901 static void CBPaintBorder(
908 if (CB_GETTYPE(lphc
) != CBS_SIMPLE
)
910 GetClientRect(hwnd
, &clientRect
);
914 CopyRect(&clientRect
, &lphc
->textRect
);
916 InflateRect(&clientRect
, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
917 InflateRect(&clientRect
, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
920 DrawEdge(hdc
, &clientRect
, EDGE_SUNKEN
, BF_RECT
);
923 /***********************************************************************
924 * COMBO_PrepareColors
926 * This method will sent the appropriate WM_CTLCOLOR message to
927 * prepare and setup the colors for the combo's DC.
929 * It also returns the brush to use for the background.
931 static HBRUSH
COMBO_PrepareColors(
938 * Get the background brush for this control.
940 if (CB_DISABLED(lphc
))
942 hBkgBrush
= (HBRUSH
)SendMessageW(lphc
->owner
, WM_CTLCOLORSTATIC
,
943 (WPARAM
)hDC
, (LPARAM
)lphc
->self
);
946 * We have to change the text color since WM_CTLCOLORSTATIC will
947 * set it to the "enabled" color. This is the same behavior as the
950 SetTextColor(hDC
, GetSysColor(COLOR_GRAYTEXT
));
954 if (lphc
->wState
& CBF_EDIT
)
956 hBkgBrush
= (HBRUSH
)SendMessageW(lphc
->owner
, WM_CTLCOLOREDIT
,
957 (WPARAM
)hDC
, (LPARAM
)lphc
->self
);
961 hBkgBrush
= (HBRUSH
)SendMessageW(lphc
->owner
, WM_CTLCOLORLISTBOX
,
962 (WPARAM
)hDC
, (LPARAM
)lphc
->self
);
970 hBkgBrush
= GetSysColorBrush(COLOR_WINDOW
);
975 /***********************************************************************
976 * COMBO_EraseBackground
978 static LRESULT
COMBO_EraseBackground(
986 if(lphc
->wState
& CBF_EDIT
)
989 hDC
= (hParamDC
) ? hParamDC
992 * Retrieve the background brush
994 hBkgBrush
= COMBO_PrepareColors(lphc
, hDC
);
996 FillRect(hDC
, &lphc
->textRect
, hBkgBrush
);
999 ReleaseDC(hwnd
, hDC
);
1004 /***********************************************************************
1007 static LRESULT
COMBO_Paint(LPHEADCOMBO lphc
, HDC hParamDC
)
1012 hDC
= (hParamDC
) ? hParamDC
1013 : BeginPaint( lphc
->self
, &ps
);
1015 TRACE("hdc=%p\n", hDC
);
1017 if( hDC
&& !(lphc
->wState
& CBF_NOREDRAW
) )
1019 HBRUSH hPrevBrush
, hBkgBrush
;
1022 * Retrieve the background brush and select it in the
1025 hBkgBrush
= COMBO_PrepareColors(lphc
, hDC
);
1027 hPrevBrush
= SelectObject( hDC
, hBkgBrush
);
1030 * In non 3.1 look, there is a sunken border on the combobox
1033 if (TWEAK_WineLook
!= WIN31_LOOK
)
1036 CBPaintBorder(lphc
->self
, lphc
, hDC
);
1039 if( !IsRectEmpty(&lphc
->buttonRect
) )
1041 CBPaintButton(lphc
, hDC
, lphc
->buttonRect
);
1044 /* paint the edit control padding area */
1045 if (CB_GETTYPE(lphc
) != CBS_DROPDOWNLIST
)
1047 RECT rPadEdit
= lphc
->textRect
;
1049 InflateRect(&rPadEdit
, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
1051 FrameRect( hDC
, &rPadEdit
, GetSysColorBrush(COLOR_WINDOW
) );
1054 if( !(lphc
->wState
& CBF_EDIT
) )
1057 * The text area has a border only in Win 3.1 look.
1060 if (TWEAK_WineLook
== WIN31_LOOK
)
1062 HPEN hPrevPen
= SelectObject( hDC
, SYSCOLOR_GetPen(COLOR_WINDOWFRAME
) );
1065 lphc
->textRect
.left
, lphc
->textRect
.top
,
1066 lphc
->textRect
.right
- 1, lphc
->textRect
.bottom
- 1);
1068 SelectObject( hDC
, hPrevPen
);
1070 #endif /* __REACTOS__ */
1072 CBPaintText( lphc
, hDC
, lphc
->textRect
);
1076 SelectObject( hDC
, hPrevBrush
);
1080 EndPaint(lphc
->self
, &ps
);
1085 /***********************************************************************
1088 * Select listbox entry according to the contents of the edit control.
1090 static INT
CBUpdateLBox( LPHEADCOMBO lphc
, BOOL bSelect
)
1093 LPWSTR pText
= NULL
;
1096 length
= SendMessageW( lphc
->hWndEdit
, WM_GETTEXTLENGTH
, 0, 0 );
1099 pText
= HeapAlloc( GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
));
1101 TRACE("\t edit text length %i\n", length
);
1105 if( length
) GetWindowTextW( lphc
->hWndEdit
, pText
, length
+ 1);
1106 else pText
[0] = '\0';
1107 idx
= SendMessageW(lphc
->hWndLBox
, LB_FINDSTRING
,
1108 (WPARAM
)(-1), (LPARAM
)pText
);
1109 HeapFree( GetProcessHeap(), 0, pText
);
1112 SendMessageW(lphc
->hWndLBox
, LB_SETCURSEL
, (WPARAM
)(bSelect
? idx
: -1), 0);
1114 /* probably superfluous but Windows sends this too */
1115 SendMessageW(lphc
->hWndLBox
, LB_SETCARETINDEX
, (WPARAM
)(idx
< 0 ? 0 : idx
), 0);
1116 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
, (WPARAM
)(idx
< 0 ? 0 : idx
), 0);
1121 /***********************************************************************
1124 * Copy a listbox entry to the edit control.
1126 static void CBUpdateEdit( LPHEADCOMBO lphc
, INT index
)
1129 LPWSTR pText
= NULL
;
1130 static const WCHAR empty_stringW
[] = { 0 };
1132 TRACE("\t %i\n", index
);
1134 if( index
>= 0 ) /* got an entry */
1136 length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, (WPARAM
)index
, 0);
1137 if( length
!= LB_ERR
)
1139 if( (pText
= HeapAlloc( GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
))) )
1141 SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
,
1142 (WPARAM
)index
, (LPARAM
)pText
);
1147 lphc
->wState
|= (CBF_NOEDITNOTIFY
| CBF_NOLBSELECT
);
1148 SendMessageW(lphc
->hWndEdit
, WM_SETTEXT
, 0, pText
? (LPARAM
)pText
: (LPARAM
)empty_stringW
);
1149 lphc
->wState
&= ~(CBF_NOEDITNOTIFY
| CBF_NOLBSELECT
);
1151 if( lphc
->wState
& CBF_FOCUSED
)
1152 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1));
1155 HeapFree( GetProcessHeap(), 0, pText
);
1158 /***********************************************************************
1161 * Show listbox popup.
1163 static void CBDropDown( LPHEADCOMBO lphc
)
1169 TRACE("[%p]: drop down\n", lphc
->self
);
1171 CB_NOTIFY( lphc
, CBN_DROPDOWN
);
1175 lphc
->wState
|= CBF_DROPPED
;
1176 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1178 lphc
->droppedIndex
= CBUpdateLBox( lphc
, TRUE
);
1180 /* Update edit only if item is in the list */
1181 if( !(lphc
->wState
& CBF_CAPTURE
) && lphc
->droppedIndex
>= 0)
1182 CBUpdateEdit( lphc
, lphc
->droppedIndex
);
1186 lphc
->droppedIndex
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1188 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
,
1189 (WPARAM
)(lphc
->droppedIndex
== LB_ERR
? 0 : lphc
->droppedIndex
), 0 );
1190 SendMessageW(lphc
->hWndLBox
, LB_CARETON
, 0, 0);
1193 /* now set popup position */
1194 GetWindowRect( lphc
->self
, &rect
);
1197 * If it's a dropdown, the listbox is offset
1199 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1200 rect
.left
+= COMBO_EDITBUTTONSPACE();
1202 /* if the dropped height is greater than the total height of the dropped
1203 items list, then force the drop down list height to be the total height
1204 of the items in the dropped list */
1206 /* And Remove any extra space (Best Fit) */
1207 nDroppedHeight
= lphc
->droppedRect
.bottom
- lphc
->droppedRect
.top
;
1208 /* if listbox length has been set directly by its handle */
1209 GetWindowRect(lphc
->hWndLBox
, &r
);
1210 if (nDroppedHeight
< r
.bottom
- r
.top
)
1211 nDroppedHeight
= r
.bottom
- r
.top
;
1212 nItems
= (int)SendMessageW(lphc
->hWndLBox
, LB_GETCOUNT
, 0, 0);
1219 nIHeight
= (int)SendMessageW(lphc
->hWndLBox
, LB_GETITEMHEIGHT
, 0, 0);
1221 nHeight
= nIHeight
*nItems
;
1223 if (nHeight
< nDroppedHeight
- COMBO_YBORDERSIZE())
1224 nDroppedHeight
= nHeight
+ COMBO_YBORDERSIZE();
1226 if (nDroppedHeight
< nIHeight
)
1229 nDroppedHeight
= (nItems
+1)*nIHeight
;
1231 nDroppedHeight
= 6*nIHeight
;
1235 /*If height of dropped rectangle gets beyond a screen size it should go up, otherwise down.*/
1236 if( (rect
.bottom
+ nDroppedHeight
) >= GetSystemMetrics( SM_CYSCREEN
) )
1237 rect
.bottom
= rect
.top
- nDroppedHeight
;
1239 SetWindowPos( lphc
->hWndLBox
, HWND_TOP
, rect
.left
, rect
.bottom
,
1240 lphc
->droppedRect
.right
- lphc
->droppedRect
.left
,
1242 SWP_NOACTIVATE
| SWP_SHOWWINDOW
);
1245 if( !(lphc
->wState
& CBF_NOREDRAW
) )
1246 RedrawWindow( lphc
->self
, NULL
, 0, RDW_INVALIDATE
|
1247 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1249 EnableWindow( lphc
->hWndLBox
, TRUE
);
1250 if (GetCapture() != lphc
->self
)
1251 SetCapture(lphc
->hWndLBox
);
1254 /***********************************************************************
1257 * Hide listbox popup.
1259 static void CBRollUp( LPHEADCOMBO lphc
, BOOL ok
, BOOL bButton
)
1261 HWND hWnd
= lphc
->self
;
1263 TRACE("[%p]: sel ok? [%i] dropped? [%i]\n",
1264 lphc
->self
, (INT
)ok
, (INT
)(lphc
->wState
& CBF_DROPPED
));
1266 CB_NOTIFY( lphc
, (ok
) ? CBN_SELENDOK
: CBN_SELENDCANCEL
);
1268 if( IsWindow( hWnd
) && CB_GETTYPE(lphc
) != CBS_SIMPLE
)
1271 if( lphc
->wState
& CBF_DROPPED
)
1275 lphc
->wState
&= ~CBF_DROPPED
;
1276 ShowWindow( lphc
->hWndLBox
, SW_HIDE
);
1278 if(GetCapture() == lphc
->hWndLBox
)
1283 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1285 rect
= lphc
->buttonRect
;
1296 rect
= lphc
->textRect
;
1301 if( bButton
&& !(lphc
->wState
& CBF_NOREDRAW
) )
1302 RedrawWindow( hWnd
, &rect
, 0, RDW_INVALIDATE
|
1303 RDW_ERASE
| RDW_UPDATENOW
| RDW_NOCHILDREN
);
1304 CB_NOTIFY( lphc
, CBN_CLOSEUP
);
1309 /***********************************************************************
1312 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
1314 BOOL
COMBO_FlipListbox( LPHEADCOMBO lphc
, BOOL ok
, BOOL bRedrawButton
)
1316 if( lphc
->wState
& CBF_DROPPED
)
1318 CBRollUp( lphc
, ok
, bRedrawButton
);
1326 /***********************************************************************
1329 static void CBRepaintButton( LPHEADCOMBO lphc
)
1331 InvalidateRect(lphc
->self
, &lphc
->buttonRect
, TRUE
);
1332 UpdateWindow(lphc
->self
);
1335 /***********************************************************************
1338 static void COMBO_SetFocus( LPHEADCOMBO lphc
)
1340 if( !(lphc
->wState
& CBF_FOCUSED
) )
1342 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
1343 SendMessageW(lphc
->hWndLBox
, LB_CARETON
, 0, 0);
1345 /* This is wrong. Message sequences seem to indicate that this
1346 is set *after* the notify. */
1347 /* lphc->wState |= CBF_FOCUSED; */
1349 if( !(lphc
->wState
& CBF_EDIT
) )
1350 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1352 CB_NOTIFY( lphc
, CBN_SETFOCUS
);
1353 lphc
->wState
|= CBF_FOCUSED
;
1357 /***********************************************************************
1360 static void COMBO_KillFocus( LPHEADCOMBO lphc
)
1362 HWND hWnd
= lphc
->self
;
1364 if( lphc
->wState
& CBF_FOCUSED
)
1366 CBRollUp( lphc
, FALSE
, TRUE
);
1367 if( IsWindow( hWnd
) )
1369 if( CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
)
1370 SendMessageW(lphc
->hWndLBox
, LB_CARETOFF
, 0, 0);
1372 lphc
->wState
&= ~CBF_FOCUSED
;
1375 if( !(lphc
->wState
& CBF_EDIT
) )
1376 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1378 CB_NOTIFY( lphc
, CBN_KILLFOCUS
);
1383 /***********************************************************************
1386 static LRESULT
COMBO_Command( LPHEADCOMBO lphc
, WPARAM wParam
, HWND hWnd
)
1388 if ( lphc
->wState
& CBF_EDIT
&& lphc
->hWndEdit
== hWnd
)
1390 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
1392 switch( HIWORD(wParam
) >> 8 )
1394 case (EN_SETFOCUS
>> 8):
1396 TRACE("[%p]: edit [%p] got focus\n", lphc
->self
, lphc
->hWndEdit
);
1398 COMBO_SetFocus( lphc
);
1401 case (EN_KILLFOCUS
>> 8):
1403 TRACE("[%p]: edit [%p] lost focus\n", lphc
->self
, lphc
->hWndEdit
);
1405 /* NOTE: it seems that Windows' edit control sends an
1406 * undocumented message WM_USER + 0x1B instead of this
1407 * notification (only when it happens to be a part of
1408 * the combo). ?? - AK.
1411 COMBO_KillFocus( lphc
);
1415 case (EN_CHANGE
>> 8):
1417 * In some circumstances (when the selection of the combobox
1418 * is changed for example) we don't wans the EN_CHANGE notification
1419 * to be forwarded to the parent of the combobox. This code
1420 * checks a flag that is set in these occasions and ignores the
1423 if (lphc
->wState
& CBF_NOLBSELECT
)
1425 lphc
->wState
&= ~CBF_NOLBSELECT
;
1429 CBUpdateLBox( lphc
, lphc
->wState
& CBF_DROPPED
);
1432 if (!(lphc
->wState
& CBF_NOEDITNOTIFY
))
1433 CB_NOTIFY( lphc
, CBN_EDITCHANGE
);
1436 case (EN_UPDATE
>> 8):
1437 if (!(lphc
->wState
& CBF_NOEDITNOTIFY
))
1438 CB_NOTIFY( lphc
, CBN_EDITUPDATE
);
1441 case (EN_ERRSPACE
>> 8):
1442 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
1445 else if( lphc
->hWndLBox
== hWnd
)
1447 switch( HIWORD(wParam
) )
1450 CB_NOTIFY( lphc
, CBN_ERRSPACE
);
1454 CB_NOTIFY( lphc
, CBN_DBLCLK
);
1460 TRACE("[%p]: lbox selection change [%x]\n", lphc
->self
, lphc
->wState
);
1462 if( HIWORD(wParam
) == LBN_SELCHANGE
)
1464 if( lphc
->wState
& CBF_EDIT
)
1466 INT index
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1467 lphc
->wState
|= CBF_NOLBSELECT
;
1468 CBUpdateEdit( lphc
, index
);
1469 /* select text in edit, as Windows does */
1470 SendMessageW(lphc
->hWndEdit
, EM_SETSEL
, 0, (LPARAM
)(-1));
1473 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1476 /* do not roll up if selection is being tracked
1477 * by arrowkeys in the dropdown listbox */
1478 if( ((lphc
->wState
& CBF_DROPPED
) && !(lphc
->wState
& CBF_NOROLLUP
)) )
1480 CBRollUp( lphc
, (HIWORD(wParam
) == LBN_SELCHANGE
), TRUE
);
1482 else lphc
->wState
&= ~CBF_NOROLLUP
;
1484 CB_NOTIFY( lphc
, CBN_SELCHANGE
);
1490 /* nothing to do here since ComboLBox always resets the focus to its
1491 * combo/edit counterpart */
1498 /***********************************************************************
1501 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
1503 static LRESULT
COMBO_ItemOp( LPHEADCOMBO lphc
, UINT msg
, LPARAM lParam
)
1505 HWND hWnd
= lphc
->self
;
1506 UINT id
= GetWindowLongA( hWnd
, GWL_ID
);
1508 TRACE("[%p]: ownerdraw op %04x\n", lphc
->self
, msg
);
1514 DELETEITEMSTRUCT
*lpIS
= (DELETEITEMSTRUCT
*)lParam
;
1515 lpIS
->CtlType
= ODT_COMBOBOX
;
1517 lpIS
->hwndItem
= hWnd
;
1522 DRAWITEMSTRUCT
*lpIS
= (DRAWITEMSTRUCT
*)lParam
;
1523 lpIS
->CtlType
= ODT_COMBOBOX
;
1525 lpIS
->hwndItem
= hWnd
;
1528 case WM_COMPAREITEM
:
1530 COMPAREITEMSTRUCT
*lpIS
= (COMPAREITEMSTRUCT
*)lParam
;
1531 lpIS
->CtlType
= ODT_COMBOBOX
;
1533 lpIS
->hwndItem
= hWnd
;
1536 case WM_MEASUREITEM
:
1538 MEASUREITEMSTRUCT
*lpIS
= (MEASUREITEMSTRUCT
*)lParam
;
1539 lpIS
->CtlType
= ODT_COMBOBOX
;
1544 return SendMessageW(lphc
->owner
, msg
, id
, lParam
);
1548 /***********************************************************************
1551 static LRESULT
COMBO_GetTextW( LPHEADCOMBO lphc
, INT count
, LPWSTR buf
)
1555 if( lphc
->wState
& CBF_EDIT
)
1556 return SendMessageW( lphc
->hWndEdit
, WM_GETTEXT
, count
, (LPARAM
)buf
);
1558 /* get it from the listbox */
1560 if (!count
|| !buf
) return 0;
1561 if( lphc
->hWndLBox
)
1563 INT idx
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1564 if (idx
== LB_ERR
) goto error
;
1565 length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, idx
, 0 );
1566 if (length
== LB_ERR
) goto error
;
1568 /* 'length' is without the terminating character */
1569 if (length
>= count
)
1571 LPWSTR lpBuffer
= HeapAlloc(GetProcessHeap(), 0, (length
+ 1) * sizeof(WCHAR
));
1572 if (!lpBuffer
) goto error
;
1573 length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)lpBuffer
);
1575 /* truncate if buffer is too short */
1576 if (length
!= LB_ERR
)
1578 lstrcpynW( buf
, lpBuffer
, count
);
1581 HeapFree( GetProcessHeap(), 0, lpBuffer
);
1583 else length
= SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)buf
);
1585 if (length
== LB_ERR
) return 0;
1589 error
: /* error - truncate string, return zero */
1595 /***********************************************************************
1598 * NOTE! LB_GETTEXT does not count terminating \0, WM_GETTEXT does.
1599 * also LB_GETTEXT might return values < 0, WM_GETTEXT doesn't.
1601 static LRESULT
COMBO_GetTextA( LPHEADCOMBO lphc
, INT count
, LPSTR buf
)
1605 if( lphc
->wState
& CBF_EDIT
)
1606 return SendMessageA( lphc
->hWndEdit
, WM_GETTEXT
, count
, (LPARAM
)buf
);
1608 /* get it from the listbox */
1610 if (!count
|| !buf
) return 0;
1611 if( lphc
->hWndLBox
)
1613 INT idx
= SendMessageA(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
1614 if (idx
== LB_ERR
) goto error
;
1615 length
= SendMessageA(lphc
->hWndLBox
, LB_GETTEXTLEN
, idx
, 0 );
1616 if (length
== LB_ERR
) goto error
;
1618 /* 'length' is without the terminating character */
1619 if (length
>= count
)
1621 LPSTR lpBuffer
= HeapAlloc(GetProcessHeap(), 0, (length
+ 1) );
1622 if (!lpBuffer
) goto error
;
1623 length
= SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)lpBuffer
);
1625 /* truncate if buffer is too short */
1626 if (length
!= LB_ERR
)
1628 lstrcpynA( buf
, lpBuffer
, count
);
1631 HeapFree( GetProcessHeap(), 0, lpBuffer
);
1633 else length
= SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, idx
, (LPARAM
)buf
);
1635 if (length
== LB_ERR
) return 0;
1639 error
: /* error - truncate string, return zero */
1645 /***********************************************************************
1648 * This function sets window positions according to the updated
1649 * component placement struct.
1651 static void CBResetPos(
1657 BOOL bDrop
= (CB_GETTYPE(lphc
) != CBS_SIMPLE
);
1659 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1660 * sizing messages */
1662 if( lphc
->wState
& CBF_EDIT
)
1663 SetWindowPos( lphc
->hWndEdit
, 0,
1664 rectEdit
->left
, rectEdit
->top
,
1665 rectEdit
->right
- rectEdit
->left
,
1666 rectEdit
->bottom
- rectEdit
->top
,
1667 SWP_NOZORDER
| SWP_NOACTIVATE
| ((bDrop
) ? SWP_NOREDRAW
: 0) );
1669 SetWindowPos( lphc
->hWndLBox
, 0,
1670 rectLB
->left
, rectLB
->top
,
1671 rectLB
->right
- rectLB
->left
,
1672 rectLB
->bottom
- rectLB
->top
,
1673 SWP_NOACTIVATE
| SWP_NOZORDER
| ((bDrop
) ? SWP_NOREDRAW
: 0) );
1677 if( lphc
->wState
& CBF_DROPPED
)
1679 lphc
->wState
&= ~CBF_DROPPED
;
1680 ShowWindow( lphc
->hWndLBox
, SW_HIDE
);
1683 if( bRedraw
&& !(lphc
->wState
& CBF_NOREDRAW
) )
1684 RedrawWindow( lphc
->self
, NULL
, 0,
1685 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
);
1690 /***********************************************************************
1693 static void COMBO_Size( LPHEADCOMBO lphc
)
1695 CBCalcPlacement(lphc
->self
,
1699 &lphc
->droppedRect
);
1701 CBResetPos( lphc
, &lphc
->textRect
, &lphc
->droppedRect
, TRUE
);
1705 /***********************************************************************
1708 static void COMBO_Font( LPHEADCOMBO lphc
, HFONT hFont
, BOOL bRedraw
)
1713 lphc
->hFont
= hFont
;
1716 * Propagate to owned windows.
1718 if( lphc
->wState
& CBF_EDIT
)
1719 SendMessageW(lphc
->hWndEdit
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1720 SendMessageW(lphc
->hWndLBox
, WM_SETFONT
, (WPARAM
)hFont
, bRedraw
);
1723 * Redo the layout of the control.
1725 if ( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
1727 CBCalcPlacement(lphc
->self
,
1731 &lphc
->droppedRect
);
1733 CBResetPos( lphc
, &lphc
->textRect
, &lphc
->droppedRect
, TRUE
);
1737 CBForceDummyResize(lphc
);
1742 /***********************************************************************
1743 * COMBO_SetItemHeight
1745 static LRESULT
COMBO_SetItemHeight( LPHEADCOMBO lphc
, INT index
, INT height
)
1747 LRESULT lRet
= CB_ERR
;
1749 if( index
== -1 ) /* set text field height */
1751 if( height
< 32768 )
1753 lphc
->editHeight
= height
;
1756 * Redo the layout of the control.
1758 if ( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
1760 CBCalcPlacement(lphc
->self
,
1764 &lphc
->droppedRect
);
1766 CBResetPos( lphc
, &lphc
->textRect
, &lphc
->droppedRect
, TRUE
);
1770 CBForceDummyResize(lphc
);
1776 else if ( CB_OWNERDRAWN(lphc
) ) /* set listbox item height */
1777 lRet
= SendMessageW(lphc
->hWndLBox
, LB_SETITEMHEIGHT
,
1778 (WPARAM
)index
, (LPARAM
)height
);
1782 /***********************************************************************
1783 * COMBO_SelectString
1785 static LRESULT
COMBO_SelectString( LPHEADCOMBO lphc
, INT start
, LPARAM pText
, BOOL unicode
)
1787 INT index
= unicode
? SendMessageW(lphc
->hWndLBox
, LB_SELECTSTRING
, (WPARAM
)start
, pText
) :
1788 SendMessageA(lphc
->hWndLBox
, LB_SELECTSTRING
, (WPARAM
)start
, pText
);
1791 if( lphc
->wState
& CBF_EDIT
)
1792 CBUpdateEdit( lphc
, index
);
1795 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
1798 return (LRESULT
)index
;
1801 /***********************************************************************
1804 static void COMBO_LButtonDown( LPHEADCOMBO lphc
, LPARAM lParam
)
1808 HWND hWnd
= lphc
->self
;
1810 pt
.x
= LOWORD(lParam
);
1811 pt
.y
= HIWORD(lParam
);
1812 bButton
= PtInRect(&lphc
->buttonRect
, pt
);
1814 if( (CB_GETTYPE(lphc
) == CBS_DROPDOWNLIST
) ||
1815 (bButton
&& (CB_GETTYPE(lphc
) == CBS_DROPDOWN
)) )
1817 lphc
->wState
|= CBF_BUTTONDOWN
;
1818 if( lphc
->wState
& CBF_DROPPED
)
1820 /* got a click to cancel selection */
1822 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1823 CBRollUp( lphc
, TRUE
, FALSE
);
1824 if( !IsWindow( hWnd
) ) return;
1826 if( lphc
->wState
& CBF_CAPTURE
)
1828 lphc
->wState
&= ~CBF_CAPTURE
;
1834 /* drop down the listbox and start tracking */
1836 lphc
->wState
|= CBF_CAPTURE
;
1840 if( bButton
) CBRepaintButton( lphc
);
1844 /***********************************************************************
1847 * Release capture and stop tracking if needed.
1849 static void COMBO_LButtonUp( LPHEADCOMBO lphc
)
1851 if( lphc
->wState
& CBF_CAPTURE
)
1853 lphc
->wState
&= ~CBF_CAPTURE
;
1854 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
)
1856 INT index
= CBUpdateLBox( lphc
, TRUE
);
1857 /* Update edit only if item is in the list */
1860 lphc
->wState
|= CBF_NOLBSELECT
;
1861 CBUpdateEdit( lphc
, index
);
1862 lphc
->wState
&= ~CBF_NOLBSELECT
;
1866 SetCapture(lphc
->hWndLBox
);
1869 if( lphc
->wState
& CBF_BUTTONDOWN
)
1871 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1872 CBRepaintButton( lphc
);
1876 /***********************************************************************
1879 * Two things to do - track combo button and release capture when
1880 * pointer goes into the listbox.
1882 static void COMBO_MouseMove( LPHEADCOMBO lphc
, WPARAM wParam
, LPARAM lParam
)
1887 pt
.x
= LOWORD(lParam
);
1888 pt
.y
= HIWORD(lParam
);
1890 if( lphc
->wState
& CBF_BUTTONDOWN
)
1894 bButton
= PtInRect(&lphc
->buttonRect
, pt
);
1898 lphc
->wState
&= ~CBF_BUTTONDOWN
;
1899 CBRepaintButton( lphc
);
1903 GetClientRect( lphc
->hWndLBox
, &lbRect
);
1904 MapWindowPoints( lphc
->self
, lphc
->hWndLBox
, &pt
, 1 );
1905 if( PtInRect(&lbRect
, pt
) )
1907 lphc
->wState
&= ~CBF_CAPTURE
;
1909 if( CB_GETTYPE(lphc
) == CBS_DROPDOWN
) CBUpdateLBox( lphc
, TRUE
);
1911 /* hand over pointer tracking */
1912 SendMessageW(lphc
->hWndLBox
, WM_LBUTTONDOWN
, wParam
, lParam
);
1917 /***********************************************************************
1918 * ComboWndProc_common
1920 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
1922 static LRESULT
ComboWndProc_common( HWND hwnd
, UINT message
,
1923 WPARAM wParam
, LPARAM lParam
, BOOL unicode
)
1925 LPHEADCOMBO lphc
= (LPHEADCOMBO
)GetWindowLongA( hwnd
, 0 );
1927 TRACE("[%p]: msg %s wp %08x lp %08lx\n",
1928 hwnd
, SPY_GetMsgName(message
, hwnd
), wParam
, lParam
);
1930 if( lphc
|| message
== WM_NCCREATE
)
1934 /* System messages */
1938 LONG style
= unicode
? ((LPCREATESTRUCTW
)lParam
)->style
:
1939 ((LPCREATESTRUCTA
)lParam
)->style
;
1940 return COMBO_NCCreate(hwnd
, style
);
1943 COMBO_NCDestroy(lphc
);
1944 break;/* -> DefWindowProc */
1952 hwndParent
= ((LPCREATESTRUCTW
)lParam
)->hwndParent
;
1953 style
= ((LPCREATESTRUCTW
)lParam
)->style
;
1957 hwndParent
= ((LPCREATESTRUCTA
)lParam
)->hwndParent
;
1958 style
= ((LPCREATESTRUCTA
)lParam
)->style
;
1960 return COMBO_Create(hwnd
, lphc
, hwndParent
, style
, unicode
);
1963 case WM_PRINTCLIENT
:
1964 if (lParam
& PRF_ERASEBKGND
)
1965 COMBO_EraseBackground(hwnd
, lphc
, (HDC
)wParam
);
1969 /* wParam may contain a valid HDC! */
1970 return COMBO_Paint(lphc
, (HDC
)wParam
);
1972 return COMBO_EraseBackground(hwnd
, lphc
, (HDC
)wParam
);
1975 LRESULT result
= DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1976 if (lParam
&& (((LPMSG
)lParam
)->message
== WM_KEYDOWN
))
1978 int vk
= (int)((LPMSG
)lParam
)->wParam
;
1980 if ((vk
== VK_RETURN
|| vk
== VK_ESCAPE
) && (lphc
->wState
& CBF_DROPPED
))
1981 result
|= DLGC_WANTMESSAGE
;
1985 case WM_WINDOWPOSCHANGING
:
1986 return COMBO_WindowPosChanging(hwnd
, lphc
, (LPWINDOWPOS
)lParam
);
1987 case WM_WINDOWPOSCHANGED
:
1988 /* SetWindowPos can be called on a Combobox to resize its Listbox.
1989 * In that case, the Combobox itself will not be resized, so we won't
1990 * get a WM_SIZE. Since we still want to update the Listbox, we have to
1995 if( lphc
->hWndLBox
&&
1996 !(lphc
->wState
& CBF_NORESIZE
) ) COMBO_Size( lphc
);
1999 COMBO_Font( lphc
, (HFONT
)wParam
, (BOOL
)lParam
);
2002 return (LRESULT
)lphc
->hFont
;
2004 if( lphc
->wState
& CBF_EDIT
)
2005 SetFocus( lphc
->hWndEdit
);
2007 COMBO_SetFocus( lphc
);
2012 HWND hwndFocus
= WIN_GetFullHandle( (HWND
)wParam
);
2013 #else /* __REACTOS__ */
2014 HWND hwndFocus
= (HWND
)wParam
;
2015 #endif /* __REACTOS__ */
2017 (hwndFocus
!= lphc
->hWndEdit
&& hwndFocus
!= lphc
->hWndLBox
))
2018 COMBO_KillFocus( lphc
);
2023 return COMBO_Command( lphc
, wParam
, WIN_GetFullHandle( (HWND
)lParam
) );
2024 #else /* __REACTOS__ */
2025 return COMBO_Command( lphc
, wParam
, (HWND
)lParam
);
2026 #endif /* __REACTOS__ */
2028 return unicode
? COMBO_GetTextW( lphc
, wParam
, (LPWSTR
)lParam
)
2029 : COMBO_GetTextA( lphc
, wParam
, (LPSTR
)lParam
);
2031 case WM_GETTEXTLENGTH
:
2033 if ((message
== WM_GETTEXTLENGTH
) && !ISWIN31
&& !(lphc
->wState
& CBF_EDIT
))
2035 int j
= SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
2036 if (j
== -1) return 0;
2037 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, j
, 0) :
2038 SendMessageA(lphc
->hWndLBox
, LB_GETTEXTLEN
, j
, 0);
2040 else if( lphc
->wState
& CBF_EDIT
)
2043 lphc
->wState
|= CBF_NOEDITNOTIFY
;
2044 ret
= unicode
? SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
) :
2045 SendMessageA(lphc
->hWndEdit
, message
, wParam
, lParam
);
2046 lphc
->wState
&= ~CBF_NOEDITNOTIFY
;
2053 if( lphc
->wState
& CBF_EDIT
)
2055 return unicode
? SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
) :
2056 SendMessageA(lphc
->hWndEdit
, message
, wParam
, lParam
);
2062 case WM_COMPAREITEM
:
2063 case WM_MEASUREITEM
:
2064 return COMBO_ItemOp(lphc
, message
, lParam
);
2066 if( lphc
->wState
& CBF_EDIT
)
2067 EnableWindow( lphc
->hWndEdit
, (BOOL
)wParam
);
2068 EnableWindow( lphc
->hWndLBox
, (BOOL
)wParam
);
2070 /* Force the control to repaint when the enabled state changes. */
2071 InvalidateRect(lphc
->self
, NULL
, TRUE
);
2075 lphc
->wState
&= ~CBF_NOREDRAW
;
2077 lphc
->wState
|= CBF_NOREDRAW
;
2079 if( lphc
->wState
& CBF_EDIT
)
2080 SendMessageW(lphc
->hWndEdit
, message
, wParam
, lParam
);
2081 SendMessageW(lphc
->hWndLBox
, message
, wParam
, lParam
);
2084 if( KEYDATA_ALT
& HIWORD(lParam
) )
2085 if( wParam
== VK_UP
|| wParam
== VK_DOWN
)
2086 COMBO_FlipListbox( lphc
, FALSE
, FALSE
);
2095 if ((wParam
== VK_RETURN
|| wParam
== VK_ESCAPE
) &&
2096 (lphc
->wState
& CBF_DROPPED
))
2098 CBRollUp( lphc
, wParam
== VK_RETURN
, FALSE
);
2102 if( lphc
->wState
& CBF_EDIT
)
2103 hwndTarget
= lphc
->hWndEdit
;
2105 hwndTarget
= lphc
->hWndLBox
;
2107 return unicode
? SendMessageW(hwndTarget
, message
, wParam
, lParam
) :
2108 SendMessageA(hwndTarget
, message
, wParam
, lParam
);
2110 case WM_LBUTTONDOWN
:
2111 if( !(lphc
->wState
& CBF_FOCUSED
) ) SetFocus( lphc
->self
);
2112 if( lphc
->wState
& CBF_FOCUSED
) COMBO_LButtonDown( lphc
, lParam
);
2115 COMBO_LButtonUp( lphc
);
2118 if( lphc
->wState
& CBF_CAPTURE
)
2119 COMBO_MouseMove( lphc
, wParam
, lParam
);
2123 if (wParam
& (MK_SHIFT
| MK_CONTROL
))
2124 return unicode
? DefWindowProcW(hwnd
, message
, wParam
, lParam
) :
2125 DefWindowProcA(hwnd
, message
, wParam
, lParam
);
2127 if (GET_WHEEL_DELTA_WPARAM(wParam
) > 0) return SendMessageW(hwnd
, WM_KEYDOWN
, VK_UP
, 0);
2128 if (GET_WHEEL_DELTA_WPARAM(wParam
) < 0) return SendMessageW(hwnd
, WM_KEYDOWN
, VK_DOWN
, 0);
2131 /* Combo messages */
2133 case CB_ADDSTRING16
:
2134 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2136 #endif /* __REACTOS__ */
2140 if( lphc
->dwStyle
& CBS_LOWERCASE
)
2141 _wcslwr((LPWSTR
)lParam
);
2142 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
2143 _wcsupr((LPWSTR
)lParam
);
2144 return SendMessageW(lphc
->hWndLBox
, LB_ADDSTRING
, 0, lParam
);
2148 if( lphc
->dwStyle
& CBS_LOWERCASE
)
2149 _strlwr((LPSTR
)lParam
);
2150 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
2151 _strupr((LPSTR
)lParam
);
2152 return SendMessageA(lphc
->hWndLBox
, LB_ADDSTRING
, 0, lParam
);
2155 case CB_INSERTSTRING16
:
2156 wParam
= (INT
)(INT16
)wParam
;
2157 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2159 #endif /* __REACTOS__ */
2160 case CB_INSERTSTRING
:
2163 if( lphc
->dwStyle
& CBS_LOWERCASE
)
2164 _wcslwr((LPWSTR
)lParam
);
2165 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
2166 _wcsupr((LPWSTR
)lParam
);
2167 return SendMessageW(lphc
->hWndLBox
, LB_INSERTSTRING
, wParam
, lParam
);
2171 if( lphc
->dwStyle
& CBS_LOWERCASE
)
2172 _strlwr((LPSTR
)lParam
);
2173 else if( lphc
->dwStyle
& CBS_UPPERCASE
)
2174 _strupr((LPSTR
)lParam
);
2175 return SendMessageA(lphc
->hWndLBox
, LB_INSERTSTRING
, wParam
, lParam
);
2178 case CB_DELETESTRING16
:
2179 #endif /* __REACTOS__ */
2180 case CB_DELETESTRING
:
2181 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_DELETESTRING
, wParam
, 0) :
2182 SendMessageA(lphc
->hWndLBox
, LB_DELETESTRING
, wParam
, 0);
2184 case CB_SELECTSTRING16
:
2185 wParam
= (INT
)(INT16
)wParam
;
2186 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2188 #endif /* __REACTOS__ */
2189 case CB_SELECTSTRING
:
2190 return COMBO_SelectString(lphc
, (INT
)wParam
, lParam
, unicode
);
2192 case CB_FINDSTRING16
:
2193 wParam
= (INT
)(INT16
)wParam
;
2194 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2196 #endif /* __REACTOS__ */
2198 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_FINDSTRING
, wParam
, lParam
) :
2199 SendMessageA(lphc
->hWndLBox
, LB_FINDSTRING
, wParam
, lParam
);
2201 case CB_FINDSTRINGEXACT16
:
2202 wParam
= (INT
)(INT16
)wParam
;
2203 if( CB_HASSTRINGS(lphc
) ) lParam
= (LPARAM
)MapSL(lParam
);
2205 #endif /* __REACTOS__ */
2206 case CB_FINDSTRINGEXACT
:
2207 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_FINDSTRINGEXACT
, wParam
, lParam
) :
2208 SendMessageA(lphc
->hWndLBox
, LB_FINDSTRINGEXACT
, wParam
, lParam
);
2210 case CB_SETITEMHEIGHT16
:
2211 wParam
= (INT
)(INT16
)wParam
; /* signed integer */
2213 #endif /* __REACTOS__ */
2214 case CB_SETITEMHEIGHT
:
2215 return COMBO_SetItemHeight( lphc
, (INT
)wParam
, (INT
)lParam
);
2217 case CB_GETITEMHEIGHT16
:
2218 wParam
= (INT
)(INT16
)wParam
;
2220 #endif /* __REACTOS__ */
2221 case CB_GETITEMHEIGHT
:
2222 if( (INT
)wParam
>= 0 ) /* listbox item */
2223 return SendMessageW(lphc
->hWndLBox
, LB_GETITEMHEIGHT
, wParam
, 0);
2224 return CBGetTextAreaHeight(hwnd
, lphc
);
2226 case CB_RESETCONTENT16
:
2227 #endif /* __REACTOS__ */
2228 case CB_RESETCONTENT
:
2229 SendMessageW(lphc
->hWndLBox
, LB_RESETCONTENT
, 0, 0);
2230 if( (lphc
->wState
& CBF_EDIT
) && CB_HASSTRINGS(lphc
) )
2232 static const WCHAR empty_stringW
[] = { 0 };
2233 SendMessageW(lphc
->hWndEdit
, WM_SETTEXT
, 0, (LPARAM
)empty_stringW
);
2236 InvalidateRect(lphc
->self
, NULL
, TRUE
);
2238 case CB_INITSTORAGE
:
2239 return SendMessageW(lphc
->hWndLBox
, LB_INITSTORAGE
, wParam
, lParam
);
2240 case CB_GETHORIZONTALEXTENT
:
2241 return SendMessageW(lphc
->hWndLBox
, LB_GETHORIZONTALEXTENT
, 0, 0);
2242 case CB_SETHORIZONTALEXTENT
:
2243 return SendMessageW(lphc
->hWndLBox
, LB_SETHORIZONTALEXTENT
, wParam
, 0);
2244 case CB_GETTOPINDEX
:
2245 return SendMessageW(lphc
->hWndLBox
, LB_GETTOPINDEX
, 0, 0);
2247 return SendMessageW(lphc
->hWndLBox
, LB_GETLOCALE
, 0, 0);
2249 return SendMessageW(lphc
->hWndLBox
, LB_SETLOCALE
, wParam
, 0);
2250 case CB_GETDROPPEDWIDTH
:
2251 if( lphc
->droppedWidth
)
2252 return lphc
->droppedWidth
;
2253 return lphc
->droppedRect
.right
- lphc
->droppedRect
.left
;
2254 case CB_SETDROPPEDWIDTH
:
2255 if( (CB_GETTYPE(lphc
) != CBS_SIMPLE
) &&
2256 (INT
)wParam
< 32768 ) lphc
->droppedWidth
= (INT
)wParam
;
2259 case CB_GETDROPPEDCONTROLRECT16
:
2260 lParam
= (LPARAM
)MapSL(lParam
);
2264 CBGetDroppedControlRect( lphc
, &r
);
2265 CONV_RECT32TO16( &r
, (LPRECT16
)lParam
);
2268 #endif /* __REACTOS__ */
2269 case CB_GETDROPPEDCONTROLRECT
:
2270 if( lParam
) CBGetDroppedControlRect(lphc
, (LPRECT
)lParam
);
2273 case CB_GETDROPPEDSTATE16
:
2274 #endif /* __REACTOS__ */
2275 case CB_GETDROPPEDSTATE
:
2276 return (lphc
->wState
& CBF_DROPPED
) ? TRUE
: FALSE
;
2279 return SendMessageA(lphc
->hWndLBox
, LB_DIR16
, wParam
, lParam
);
2280 #endif /* __REACTOS__ */
2282 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_DIR
, wParam
, lParam
) :
2283 SendMessageA(lphc
->hWndLBox
, LB_DIR
, wParam
, lParam
);
2285 case CB_SHOWDROPDOWN16
:
2286 #endif /* __REACTOS__ */
2287 case CB_SHOWDROPDOWN
:
2288 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
2292 if( !(lphc
->wState
& CBF_DROPPED
) )
2296 if( lphc
->wState
& CBF_DROPPED
)
2297 CBRollUp( lphc
, FALSE
, TRUE
);
2302 #endif /* __REACTOS__ */
2304 return SendMessageW(lphc
->hWndLBox
, LB_GETCOUNT
, 0, 0);
2306 case CB_GETCURSEL16
:
2307 #endif /* __REACTOS__ */
2309 return SendMessageW(lphc
->hWndLBox
, LB_GETCURSEL
, 0, 0);
2311 case CB_SETCURSEL16
:
2312 wParam
= (INT
)(INT16
)wParam
;
2314 #endif /* __REACTOS__ */
2316 lParam
= SendMessageW(lphc
->hWndLBox
, LB_SETCURSEL
, wParam
, 0);
2318 SendMessageW(lphc
->hWndLBox
, LB_SETTOPINDEX
, wParam
, 0);
2320 /* no LBN_SELCHANGE in this case, update manually */
2321 if( lphc
->wState
& CBF_EDIT
)
2322 CBUpdateEdit( lphc
, (INT
)wParam
);
2324 InvalidateRect(lphc
->self
, &lphc
->textRect
, TRUE
);
2325 lphc
->wState
&= ~CBF_SELCHANGE
;
2328 case CB_GETLBTEXT16
:
2329 wParam
= (INT
)(INT16
)wParam
;
2330 lParam
= (LPARAM
)MapSL(lParam
);
2332 #endif /* __REACTOS__ */
2334 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_GETTEXT
, wParam
, lParam
) :
2335 SendMessageA(lphc
->hWndLBox
, LB_GETTEXT
, wParam
, lParam
);
2337 case CB_GETLBTEXTLEN16
:
2338 wParam
= (INT
)(INT16
)wParam
;
2340 #endif /* __REACTOS__ */
2341 case CB_GETLBTEXTLEN
:
2342 return unicode
? SendMessageW(lphc
->hWndLBox
, LB_GETTEXTLEN
, wParam
, 0) :
2343 SendMessageA(lphc
->hWndLBox
, LB_GETTEXTLEN
, wParam
, 0);
2345 case CB_GETITEMDATA16
:
2346 wParam
= (INT
)(INT16
)wParam
;
2348 #endif /* __REACTOS__ */
2349 case CB_GETITEMDATA
:
2350 return SendMessageW(lphc
->hWndLBox
, LB_GETITEMDATA
, wParam
, 0);
2352 case CB_SETITEMDATA16
:
2353 wParam
= (INT
)(INT16
)wParam
;
2355 #endif /* __REACTOS__ */
2356 case CB_SETITEMDATA
:
2357 return SendMessageW(lphc
->hWndLBox
, LB_SETITEMDATA
, wParam
, lParam
);
2359 case CB_GETEDITSEL16
:
2360 wParam
= lParam
= 0; /* just in case */
2362 #endif /* __REACTOS__ */
2364 /* Edit checks passed parameters itself */
2365 if( lphc
->wState
& CBF_EDIT
)
2366 return SendMessageW(lphc
->hWndEdit
, EM_GETSEL
, wParam
, lParam
);
2369 case CB_SETEDITSEL16
:
2370 #endif /* __REACTOS__ */
2372 if( lphc
->wState
& CBF_EDIT
)
2373 return SendMessageW(lphc
->hWndEdit
, EM_SETSEL
,
2374 (INT
)(USHORT
)LOWORD(lParam
), (INT
)(USHORT
)HIWORD(lParam
) );
2377 case CB_SETEXTENDEDUI16
:
2378 #endif /* __REACTOS__ */
2379 case CB_SETEXTENDEDUI
:
2380 if( CB_GETTYPE(lphc
) == CBS_SIMPLE
)
2383 lphc
->wState
|= CBF_EUI
;
2384 else lphc
->wState
&= ~CBF_EUI
;
2387 case CB_GETEXTENDEDUI16
:
2388 #endif /* __REACTOS__ */
2389 case CB_GETEXTENDEDUI
:
2390 return (lphc
->wState
& CBF_EUI
) ? TRUE
: FALSE
;
2393 if (message
>= WM_USER
)
2394 WARN("unknown msg WM_USER+%04x wp=%04x lp=%08lx\n",
2395 message
- WM_USER
, wParam
, lParam
);
2398 return unicode
? DefWindowProcW(hwnd
, message
, wParam
, lParam
) :
2399 DefWindowProcA(hwnd
, message
, wParam
, lParam
);
2402 /***********************************************************************
2405 * This is just a wrapper for the real ComboWndProc which locks/unlocks
2408 static LRESULT WINAPI
ComboWndProcA( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2410 if (!IsWindow(hwnd
)) return 0;
2411 return ComboWndProc_common( hwnd
, message
, wParam
, lParam
, FALSE
);
2414 /***********************************************************************
2417 static LRESULT WINAPI
ComboWndProcW( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2419 if (!IsWindow(hwnd
)) return 0;
2420 return ComboWndProc_common( hwnd
, message
, wParam
, lParam
, TRUE
);
2423 /*************************************************************************
2424 * GetComboBoxInfo (USER32.@)
2426 BOOL WINAPI
GetComboBoxInfo(HWND hwndCombo
, /* [in] handle to combo box */
2427 PCOMBOBOXINFO pcbi
/* [in/out] combo box information */)